Persist the Feeds Read filter across application launches. Issue #1349
This commit is contained in:
parent
8cb25e7c5e
commit
ebd7f4904d
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue