Persist the Feeds Read filter across application launches. Issue #1349

This commit is contained in:
Maurice Parker 2019-11-26 20:23:12 -06:00
parent 8cb25e7c5e
commit ebd7f4904d
7 changed files with 53 additions and 20 deletions

View File

@ -1098,6 +1098,7 @@ private extension Account {
self.fetchingAllUnreadCounts = false self.fetchingAllUnreadCounts = false
self.updateUnreadCount() self.updateUnreadCount()
self.isUnreadCountsInitialized = true self.isUnreadCountsInitialized = true
self.postUnreadCountDidInitializeNotification()
return return
} }
@ -1111,9 +1112,11 @@ private extension Account {
feed.unreadCount = 0 feed.unreadCount = 0
} }
} }
self.fetchingAllUnreadCounts = false self.fetchingAllUnreadCounts = false
self.updateUnreadCount() self.updateUnreadCount()
self.isUnreadCountsInitialized = true self.isUnreadCountsInitialized = true
self.postUnreadCountDidInitializeNotification()
} }
} }
} }

View File

@ -102,6 +102,7 @@ public final class AccountManager: UnreadCountProvider {
readAccountsFromDisk() readAccountsFromDisk()
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidInitialize(_:)), name: .UnreadCountDidInitialize, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(accountStateDidChange(_:)), name: .AccountStateDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(accountStateDidChange(_:)), name: .AccountStateDidChange, object: nil)
@ -269,6 +270,15 @@ public final class AccountManager: UnreadCountProvider {
// MARK: - Notifications // MARK: - Notifications
@objc func unreadCountDidInitialize(_ notification: Notification) {
guard let _ = notification.object as? Account else {
return
}
if isUnreadCountsInitialized {
postUnreadCountDidInitializeNotification()
}
}
@objc dynamic func unreadCountDidChange(_ notification: Notification) { @objc dynamic func unreadCountDidChange(_ notification: Notification) {
guard let _ = notification.object as? Account else { guard let _ = notification.object as? Account else {
return return

View File

@ -9,7 +9,7 @@
import Foundation import Foundation
public extension Notification.Name { public extension Notification.Name {
static let UnreadCountDidInitialize = Notification.Name("UnreadCountDidInitialize")
static let UnreadCountDidChange = Notification.Name(rawValue: "UnreadCountDidChange") static let UnreadCountDidChange = Notification.Name(rawValue: "UnreadCountDidChange")
} }
@ -24,6 +24,10 @@ public protocol UnreadCountProvider {
public extension UnreadCountProvider { public extension UnreadCountProvider {
func postUnreadCountDidInitializeNotification() {
NotificationCenter.default.post(name: .UnreadCountDidInitialize, object: self, userInfo: nil)
}
func postUnreadCountDidChangeNotification() { func postUnreadCountDidChangeNotification() {
NotificationCenter.default.post(name: .UnreadCountDidChange, object: self, userInfo: nil) NotificationCenter.default.post(name: .UnreadCountDidChange, object: self, userInfo: nil)
} }

View File

@ -25,5 +25,6 @@ struct UserInfoKey {
static let windowState = "windowState" static let windowState = "windowState"
static let containerExpandedWindowState = "containerExpandedWindowState" static let containerExpandedWindowState = "containerExpandedWindowState"
static let readFeedsFilterState = "readFeedsFilterState"
} }

View File

@ -383,12 +383,12 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
} }
@IBAction func toggleFilter(_ sender: Any) { @IBAction func toggleFilter(_ sender: Any) {
if coordinator.isUnreadFeedsFiltered { if coordinator.isReadFeedsFiltered {
filterButton.image = AppAssets.filterInactiveImage filterButton.image = AppAssets.filterInactiveImage
coordinator.showAllFeeds() coordinator.showAllFeeds()
} else { } else {
filterButton.image = AppAssets.filterActiveImage filterButton.image = AppAssets.filterActiveImage
coordinator.hideUnreadFeeds() coordinator.hideReadFeeds()
} }
} }
@ -506,14 +506,16 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
} }
} }
func reloadFeeds() { func reloadFeeds(initialLoad: Bool) {
updateUI() updateUI()
// We have to reload all the visible cells because if we got here by doing a table cell move, // We have to reload all the visible cells because if we got here by doing a table cell move,
// then the table itself is in a weird state. This is because we do unusual things like allowing // then the table itself is in a weird state. This is because we do unusual things like allowing
// drops on a "folder" that should cause the dropped cell to disappear. // drops on a "folder" that should cause the dropped cell to disappear.
applyChanges(animated: true) { [weak self] in applyChanges(animated: !initialLoad) { [weak self] in
self?.reloadAllVisibleCells() if !initialLoad {
self?.reloadAllVisibleCells()
}
} }
} }
@ -633,6 +635,11 @@ private extension MasterFeedViewController {
} }
func updateUI() { func updateUI() {
if coordinator.isReadFeedsFiltered {
filterButton.image = AppAssets.filterActiveImage
} else {
filterButton.image = AppAssets.filterInactiveImage
}
refreshProgressView?.updateRefreshLabel() refreshProgressView?.updateRefreshLabel()
addNewItemButton?.isEnabled = !AccountManager.shared.activeAccounts.isEmpty addNewItemButton?.isEnabled = !AccountManager.shared.activeAccounts.isEmpty
} }

View File

@ -117,7 +117,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
return panelMode == .three return panelMode == .three
} }
var isUnreadFeedsFiltered: Bool { var isReadFeedsFiltered: Bool {
return treeControllerDelegate.isReadFiltered return treeControllerDelegate.isReadFiltered
} }
@ -279,8 +279,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
shadowTable.append([Node]()) shadowTable.append([Node]())
} }
rebuildShadowTable() NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidInitialize(_:)), name: .UnreadCountDidInitialize, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(containerChildrenDidChange(_:)), name: .ChildrenDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(containerChildrenDidChange(_:)), name: .ChildrenDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(batchUpdateDidPerform(_:)), name: .BatchUpdateDidPerform, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(batchUpdateDidPerform(_:)), name: .BatchUpdateDidPerform, object: nil)
@ -307,7 +306,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
masterFeedViewController = UIStoryboard.main.instantiateController(ofType: MasterFeedViewController.self) masterFeedViewController = UIStoryboard.main.instantiateController(ofType: MasterFeedViewController.self)
masterFeedViewController.coordinator = self masterFeedViewController.coordinator = self
masterNavigationController.pushViewController(masterFeedViewController, animated: false) masterNavigationController.pushViewController(masterFeedViewController, animated: false)
masterFeedViewController.reloadFeeds()
let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self) let articleViewController = UIStoryboard.main.instantiateController(ofType: ArticleViewController.self)
articleViewController.coordinator = self articleViewController.coordinator = self
@ -319,12 +317,11 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
return rootSplitViewController return rootSplitViewController
} }
func restoreWindowState(_ activity: NSUserActivity) { func restoreWindowState(_ activity: NSUserActivity?) {
if let windowState = activity.userInfo?[UserInfoKey.windowState] as? [AnyHashable: Any] { if let activity = activity, let windowState = activity.userInfo?[UserInfoKey.windowState] as? [AnyHashable: Any] {
restoreWindowState(windowState) restoreWindowState(windowState)
rebuildShadowTable()
masterFeedViewController.reloadFeeds()
} }
rebuildBackingStores(initialLoad: true)
} }
func handle(_ activity: NSUserActivity) { func handle(_ activity: NSUserActivity) {
@ -387,6 +384,15 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
// MARK: Notifications // MARK: Notifications
@objc func unreadCountDidInitialize(_ notification: Notification) {
guard notification.object is AccountManager else {
return
}
if isReadFeedsFiltered {
rebuildBackingStores()
}
}
@objc func statusesDidChange(_ note: Notification) { @objc func statusesDidChange(_ note: Notification) {
updateUnreadCount() updateUnreadCount()
} }
@ -525,7 +531,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
rebuildBackingStores() rebuildBackingStores()
} }
func hideUnreadFeeds() { func hideReadFeeds() {
treeControllerDelegate.isReadFiltered = true treeControllerDelegate.isReadFiltered = true
rebuildBackingStores() rebuildBackingStores()
} }
@ -1150,12 +1156,12 @@ private extension SceneCoordinator {
unreadCount = count unreadCount = count
} }
func rebuildBackingStores(_ updateExpandedNodes: (() -> Void)? = nil) { func rebuildBackingStores(initialLoad: Bool = false, updateExpandedNodes: (() -> Void)? = nil) {
if !animatingChanges && !BatchUpdate.shared.isPerforming { if !animatingChanges && !BatchUpdate.shared.isPerforming {
treeController.rebuild() treeController.rebuild()
updateExpandedNodes?() updateExpandedNodes?()
rebuildShadowTable() rebuildShadowTable()
masterFeedViewController.reloadFeeds() masterFeedViewController.reloadFeeds(initialLoad: initialLoad)
} }
} }
@ -1759,11 +1765,15 @@ private extension SceneCoordinator {
func windowState() -> [AnyHashable: Any] { func windowState() -> [AnyHashable: Any] {
let containerIdentifierUserInfos = expandedTable.map( { $0.userInfo }) let containerIdentifierUserInfos = expandedTable.map( { $0.userInfo })
return [ return [
UserInfoKey.readFeedsFilterState: isReadFeedsFiltered,
UserInfoKey.containerExpandedWindowState: containerIdentifierUserInfos UserInfoKey.containerExpandedWindowState: containerIdentifierUserInfos
] ]
} }
func restoreWindowState(_ windowState: [AnyHashable: Any]) { func restoreWindowState(_ windowState: [AnyHashable: Any]) {
if let readFeedsFilterState = windowState[UserInfoKey.readFeedsFilterState] as? Bool {
treeControllerDelegate.isReadFiltered = readFeedsFilterState
}
if let containerIdentifierUserInfos = windowState[UserInfoKey.containerExpandedWindowState] as? [[AnyHashable: Any]] { if let containerIdentifierUserInfos = windowState[UserInfoKey.containerExpandedWindowState] as? [[AnyHashable: Any]] {
let containerIdentifers = containerIdentifierUserInfos.compactMap( { ContainerIdentifier(userInfo: $0) }) let containerIdentifers = containerIdentifierUserInfos.compactMap( { ContainerIdentifier(userInfo: $0) })
expandedTable = Set(containerIdentifers) expandedTable = Set(containerIdentifers)

View File

@ -23,9 +23,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window!.tintColor = AppAssets.primaryAccentColor window!.tintColor = AppAssets.primaryAccentColor
window!.rootViewController = coordinator.start(for: window!.frame.size) window!.rootViewController = coordinator.start(for: window!.frame.size)
if let stateRestorationActivity = session.stateRestorationActivity { coordinator.restoreWindowState(session.stateRestorationActivity)
coordinator.restoreWindowState(stateRestorationActivity)
}
if let shortcutItem = connectionOptions.shortcutItem { if let shortcutItem = connectionOptions.shortcutItem {
window!.makeKeyAndVisible() window!.makeKeyAndVisible()