Persist and restore per window per feed timeline filter state.

This commit is contained in:
Maurice Parker 2020-03-03 18:13:43 -08:00
parent ae8f36d300
commit ceef6116f9
2 changed files with 30 additions and 28 deletions

View File

@ -849,7 +849,7 @@ private extension MainWindowController {
menuItem.title = isReadFiltered ? showCommand : hideCommand menuItem.title = isReadFiltered ? showCommand : hideCommand
return true return true
} else { } else {
menuItem.title = hideCommand menuItem.title = showCommand
return false return false
} }
} }

View File

@ -22,10 +22,19 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
@IBOutlet var tableView: TimelineTableView! @IBOutlet var tableView: TimelineTableView!
private var articleReadFilterType: ReadFilterType? private var readFilterEnabledTable = [FeedIdentifier: Bool]()
var isReadFiltered: Bool? { var isReadFiltered: Bool? {
guard let articleReadFilterType = articleReadFilterType, articleReadFilterType != .alwaysRead else { return nil} guard representedObjects?.count == 1, let timelineFeed = representedObjects?.first as? Feed else {
return articleReadFilterType != .none return nil
}
guard timelineFeed.defaultReadFilterType != .alwaysRead else {
return nil
}
if let feedID = timelineFeed.feedID, let readFilterEnabled = readFilterEnabledTable[feedID] {
return readFilterEnabled
} else {
return timelineFeed.defaultReadFilterType == .read
}
} }
var representedObjects: [AnyObject]? { var representedObjects: [AnyObject]? {
@ -44,7 +53,6 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
showFeedNames = false showFeedNames = false
} }
determineReadFilterType()
selectionDidChange(nil) selectionDidChange(nil)
if showsSearchResults { if showsSearchResults {
fetchAndReplaceArticlesAsync() fetchAndReplaceArticlesAsync()
@ -224,16 +232,9 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
} }
func toggleReadFilter() { func toggleReadFilter() {
guard let filterType = articleReadFilterType else { return } guard let filter = isReadFiltered, let feedID = (representedObjects?.first as? Feed)?.feedID else { return }
readFilterEnabledTable[feedID] = !filter
switch filterType { delegate?.timelineInvalidatedRestorationState(self)
case .alwaysRead:
break
case .read:
articleReadFilterType = ReadFilterType.none
case .none:
articleReadFilterType = ReadFilterType.read
}
if let article = oneSelectedArticle, let account = article.account { if let article = oneSelectedArticle, let account = article.account {
exceptionArticleFetcher = SingleArticleFetcher(account: account, articleID: article.articleID) exceptionArticleFetcher = SingleArticleFetcher(account: account, articleID: article.articleID)
@ -247,11 +248,21 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
// MARK: State Restoration // MARK: State Restoration
func saveState(to coder: NSCoder) { func saveState(to coder: NSCoder) {
var readArticlesFilterState = [[AnyHashable: AnyHashable]: Bool]()
for key in readFilterEnabledTable.keys {
readArticlesFilterState[key.userInfo] = readFilterEnabledTable[key]
}
coder.encode(readArticlesFilterState, forKey: UserInfoKey.readArticlesFilterState)
} }
func restoreState(from coder: NSCoder) { func restoreState(from coder: NSCoder) {
if let readArticlesFilterState = try? coder.decodeTopLevelObject(forKey: UserInfoKey.readArticlesFilterState) as? [[AnyHashable: AnyHashable]: Bool] {
for key in readArticlesFilterState.keys {
if let feedIdentifier = FeedIdentifier(userInfo: key) {
readFilterEnabledTable[feedIdentifier] = readArticlesFilterState[key]
}
}
}
} }
// MARK: - Actions // MARK: - Actions
@ -1006,14 +1017,6 @@ private extension TimelineViewController {
// MARK: - Fetching Articles // MARK: - Fetching Articles
func determineReadFilterType() {
if representedObjects?.count ?? 0 == 1, let feed = representedObjects?.first as? Feed {
articleReadFilterType = feed.defaultReadFilterType
} else {
articleReadFilterType = .read
}
}
func fetchAndReplaceArticlesSync() { func fetchAndReplaceArticlesSync() {
// To be called when the user has made a change of selection in the sidebar. // To be called when the user has made a change of selection in the sidebar.
// It blocks the main thread, so that theres no async delay, // It blocks the main thread, so that theres no async delay,
@ -1071,7 +1074,7 @@ private extension TimelineViewController {
var fetchedArticles = Set<Article>() var fetchedArticles = Set<Article>()
for articleFetcher in articleFetchers { for articleFetcher in articleFetchers {
if articleReadFilterType != ReadFilterType.none { if isReadFiltered ?? true {
if let articles = try? articleFetcher.fetchUnreadArticles() { if let articles = try? articleFetcher.fetchUnreadArticles() {
fetchedArticles.formUnion(articles) fetchedArticles.formUnion(articles)
} }
@ -1089,8 +1092,7 @@ private extension TimelineViewController {
// if its been superseded by a newer fetch, or the timeline was emptied, etc., it wont get called. // if its been superseded by a newer fetch, or the timeline was emptied, etc., it wont get called.
precondition(Thread.isMainThread) precondition(Thread.isMainThread)
cancelPendingAsyncFetches() cancelPendingAsyncFetches()
let readFilter = articleReadFilterType != ReadFilterType.none let fetchOperation = FetchRequestOperation(id: fetchSerialNumber, readFilter: isReadFiltered ?? true, representedObjects: representedObjects) { [weak self] (articles, operation) in
let fetchOperation = FetchRequestOperation(id: fetchSerialNumber, readFilter: readFilter, representedObjects: representedObjects) { [weak self] (articles, operation) in
precondition(Thread.isMainThread) precondition(Thread.isMainThread)
guard !operation.isCanceled, let strongSelf = self, operation.id == strongSelf.fetchSerialNumber else { guard !operation.isCanceled, let strongSelf = self, operation.id == strongSelf.fetchSerialNumber else {
return return