diff --git a/Frameworks/Account/Feed.swift b/Frameworks/Account/Feed.swift index 32ba79313..5a05fdeb5 100644 --- a/Frameworks/Account/Feed.swift +++ b/Frameworks/Account/Feed.swift @@ -11,8 +11,8 @@ import RSCore public enum ReadFilter { case read - case all case none + case unavailable } public protocol Feed: FeedIdentifiable, ArticleFetcher, DisplayNameProvider, UnreadCountProvider { diff --git a/Frameworks/Account/WebFeed.swift b/Frameworks/Account/WebFeed.swift index 2bcc1dc5e..49857d9ca 100644 --- a/Frameworks/Account/WebFeed.swift +++ b/Frameworks/Account/WebFeed.swift @@ -14,7 +14,7 @@ import Articles public final class WebFeed: Feed, Renamable, Hashable { public var defaultReadFilter: ReadFilter { - return .all + return .none } public var feedID: FeedIdentifier? { diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index 54ff1e9e9..2d0000446 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -1000,7 +1000,7 @@ private extension TimelineViewController { // if it’s been superseded by a newer fetch, or the timeline was emptied, etc., it won’t get called. precondition(Thread.isMainThread) cancelPendingAsyncFetches() - let fetchOperation = FetchRequestOperation(id: fetchSerialNumber, representedObjects: representedObjects) { [weak self] (articles, operation) in + let fetchOperation = FetchRequestOperation(id: fetchSerialNumber, readFilter: .none, representedObjects: representedObjects) { [weak self] (articles, operation) in precondition(Thread.isMainThread) guard !operation.isCanceled, let strongSelf = self, operation.id == strongSelf.fetchSerialNumber else { return diff --git a/Shared/SmartFeeds/SmartFeed.swift b/Shared/SmartFeeds/SmartFeed.swift index b3e4a59fb..b231be418 100644 --- a/Shared/SmartFeeds/SmartFeed.swift +++ b/Shared/SmartFeeds/SmartFeed.swift @@ -14,7 +14,7 @@ import Account final class SmartFeed: PseudoFeed { public var defaultReadFilter: ReadFilter { - return .all + return .none } var feedID: FeedIdentifier? { diff --git a/Shared/SmartFeeds/UnreadFeed.swift b/Shared/SmartFeeds/UnreadFeed.swift index 8238425a2..4b5407a3f 100644 --- a/Shared/SmartFeeds/UnreadFeed.swift +++ b/Shared/SmartFeeds/UnreadFeed.swift @@ -20,7 +20,7 @@ import Articles final class UnreadFeed: PseudoFeed { public var defaultReadFilter: ReadFilter { - return .none + return .unavailable } var feedID: FeedIdentifier? { diff --git a/Shared/Timeline/FetchRequestOperation.swift b/Shared/Timeline/FetchRequestOperation.swift index ff9e0664b..411f7f020 100644 --- a/Shared/Timeline/FetchRequestOperation.swift +++ b/Shared/Timeline/FetchRequestOperation.swift @@ -19,14 +19,16 @@ typealias FetchRequestOperationResultBlock = (Set
, FetchRequestOperatio final class FetchRequestOperation { let id: Int + let readFilter: ReadFilter let resultBlock: FetchRequestOperationResultBlock var isCanceled = false var isFinished = false private let representedObjects: [Any] - init(id: Int, representedObjects: [Any], resultBlock: @escaping FetchRequestOperationResultBlock) { + init(id: Int, readFilter: ReadFilter, representedObjects: [Any], resultBlock: @escaping FetchRequestOperationResultBlock) { precondition(Thread.isMainThread) self.id = id + self.readFilter = readFilter self.representedObjects = representedObjects self.resultBlock = resultBlock } @@ -60,25 +62,38 @@ final class FetchRequestOperation { let numberOfFetchers = articleFetchers.count var fetchersReturned = 0 var fetchedArticles = Set
() - for articleFetcher in articleFetchers { - articleFetcher.fetchArticlesAsync { (articles) in - precondition(Thread.isMainThread) - guard !self.isCanceled else { - callCompletionIfNeeded() - return - } - - assert(!self.isFinished) + + func process(articles: Set
) { + precondition(Thread.isMainThread) + guard !self.isCanceled else { + callCompletionIfNeeded() + return + } + + assert(!self.isFinished) - fetchedArticles.formUnion(articles) - fetchersReturned += 1 - if fetchersReturned == numberOfFetchers { - self.isFinished = true - self.resultBlock(fetchedArticles, self) - callCompletionIfNeeded() + fetchedArticles.formUnion(articles) + fetchersReturned += 1 + if fetchersReturned == numberOfFetchers { + self.isFinished = true + self.resultBlock(fetchedArticles, self) + callCompletionIfNeeded() + } + } + + for articleFetcher in articleFetchers { + if readFilter == .read { + articleFetcher.fetchUnreadArticlesAsync { (articles) in + process(articles: articles) + } + } else { + articleFetcher.fetchArticlesAsync { (articles) in + process(articles: articles) } } } + } + } diff --git a/iOS/MasterTimeline/MasterTimelineViewController.swift b/iOS/MasterTimeline/MasterTimelineViewController.swift index 762b065ff..2bb1af496 100644 --- a/iOS/MasterTimeline/MasterTimelineViewController.swift +++ b/iOS/MasterTimeline/MasterTimelineViewController.swift @@ -90,7 +90,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner // MARK: Actions @IBAction func toggleFilter(_ sender: Any) { switch coordinator.articleReadFilter { - case .all: + case .none: filterButton.image = AppAssets.filterActiveImage coordinator.hideUnreadArticles() case .read: @@ -497,7 +497,7 @@ private extension MasterTimelineViewController { } switch coordinator.articleReadFilter { - case .all: + case .none: filterButton.isHidden = false filterButton.image = AppAssets.filterInactiveImage case .read: @@ -548,7 +548,7 @@ private extension MasterTimelineViewController { self?.configure(cell, article: article) return cell }) - dataSource.defaultRowAnimation = .left + dataSource.defaultRowAnimation = .middle return dataSource } diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 322c7ba50..29e2732a2 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -116,7 +116,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { return treeControllerDelegate.isUnreadFiltered } - var articleReadFilter: ReadFilter = .all + var articleReadFilter: ReadFilter = .none var rootNode: Node { return treeController.rootNode @@ -473,11 +473,17 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { } func showAllArticles() { - articleReadFilter = .all + articleReadFilter = .none + fetchAndReplaceArticlesAsync { + self.rebuildBackingStores() + } } func hideUnreadArticles() { articleReadFilter = .read + fetchAndReplaceArticlesAsync { + self.rebuildBackingStores() + } } func expand(_ node: Node) { @@ -1139,7 +1145,7 @@ private extension SceneCoordinator { func setTimelineFeed(_ feed: Feed?, completion: (() -> Void)? = nil) { timelineFeed = feed timelineMiddleIndexPath = nil - articleReadFilter = feed?.defaultReadFilter ?? .all + articleReadFilter = feed?.defaultReadFilter ?? .none fetchAndReplaceArticlesAsync { self.masterTimelineViewController?.reinitializeArticles() @@ -1480,7 +1486,7 @@ private extension SceneCoordinator { precondition(Thread.isMainThread) cancelPendingAsyncFetches() - let fetchOperation = FetchRequestOperation(id: fetchSerialNumber, representedObjects: representedObjects) { [weak self] (articles, operation) in + let fetchOperation = FetchRequestOperation(id: fetchSerialNumber, readFilter: articleReadFilter, representedObjects: representedObjects) { [weak self] (articles, operation) in precondition(Thread.isMainThread) guard !operation.isCanceled, let strongSelf = self, operation.id == strongSelf.fetchSerialNumber else { return