diff --git a/Mac/Base.lproj/Main.storyboard b/Mac/Base.lproj/Main.storyboard index 27675b309..19fbdd9f3 100644 --- a/Mac/Base.lproj/Main.storyboard +++ b/Mac/Base.lproj/Main.storyboard @@ -336,6 +336,12 @@ + + + + + + @@ -365,7 +371,7 @@ - + diff --git a/Mac/MainWindow/MainWindowController.swift b/Mac/MainWindow/MainWindowController.swift index 74b988dd5..39b56f8d3 100644 --- a/Mac/MainWindow/MainWindowController.swift +++ b/Mac/MainWindow/MainWindowController.swift @@ -237,10 +237,19 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { return currentSearchField != nil } - if item.action == #selector(toggleReadFilter(_:)) { + if item.action == #selector(toggleReadFeedsFilter(_:)) { (item as! NSMenuItem).state = sidebarViewController?.isReadFiltered ?? false ? .on : .off } + if item.action == #selector(toggleReadArticlesFilter(_:)) { + if let timelineContainer = timelineContainerViewController { + (item as! NSMenuItem).isEnabled = true + (item as! NSMenuItem).state = timelineContainer.isReadFiltered ? .on : .off + } else { + (item as! NSMenuItem).isEnabled = false + } + } + if item.action == #selector(toggleSidebar(_:)) { guard let splitViewItem = sidebarSplitViewItem else { return false @@ -443,9 +452,14 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { window?.makeFirstResponder(searchField) } - @IBAction func toggleReadFilter(_ sender: Any?) { + @IBAction func toggleReadFeedsFilter(_ sender: Any?) { sidebarViewController?.toggleReadFilter() } + + @IBAction func toggleReadArticlesFilter(_ sender: Any?) { + timelineContainerViewController?.toggleReadFilter() + } + } // MARK: - SidebarDelegate diff --git a/Mac/MainWindow/Timeline/TimelineContainerViewController.swift b/Mac/MainWindow/Timeline/TimelineContainerViewController.swift index b4f3b3a27..cdeaec45d 100644 --- a/Mac/MainWindow/Timeline/TimelineContainerViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineContainerViewController.swift @@ -30,6 +30,10 @@ final class TimelineContainerViewController: NSViewController { weak var delegate: TimelineContainerViewControllerDelegate? + var isReadFiltered: Bool { + return regularTimelineViewController.isReadFiltered + } + lazy var regularTimelineViewController = { return TimelineViewController(delegate: self) }() @@ -79,6 +83,11 @@ final class TimelineContainerViewController: NSViewController { } return true } + + func toggleReadFilter() { + regularTimelineViewController.toggleReadFilter() + } + } extension TimelineContainerViewController: TimelineDelegate { diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index 4eb1cae11..60f558dec 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -20,6 +20,11 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr @IBOutlet var tableView: TimelineTableView! + private var articleReadFilterType: ReadFilterType? + var isReadFiltered: Bool { + return articleReadFilterType ?? .read != .none + } + var representedObjects: [AnyObject]? { didSet { if !representedObjectArraysAreEqual(oldValue, representedObjects) { @@ -36,6 +41,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr showFeedNames = false } + determineReadFilterType() selectionDidChange(nil) if showsSearchResults { fetchAndReplaceArticlesAsync() @@ -213,6 +219,19 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr return representedObjects.first! === object } + func toggleReadFilter() { + guard let filterType = articleReadFilterType else { return } + switch filterType { + case .alwaysRead: + break + case .read: + articleReadFilterType = ReadFilterType.none + case .none: + articleReadFilterType = ReadFilterType.read + } + fetchAndReplaceArticlesAsync() + } + // MARK: - Actions @objc func openArticleInBrowser(_ sender: Any?) { @@ -944,6 +963,14 @@ private extension TimelineViewController { } // MARK: - Fetching Articles + + func determineReadFilterType() { + if representedObjects?.count ?? 0 == 1, let feed = representedObjects?.first as? Feed { + articleReadFilterType = feed.defaultReadFilterType + } else { + articleReadFilterType = .read + } + } func fetchAndReplaceArticlesSync() { // To be called when the user has made a change of selection in the sidebar. @@ -990,7 +1017,11 @@ private extension TimelineViewController { var fetchedArticles = Set
() for articleFetcher in articleFetchers { - fetchedArticles.formUnion(articleFetcher.fetchArticles()) + if articleReadFilterType != ReadFilterType.none { + fetchedArticles.formUnion(articleFetcher.fetchUnreadArticles()) + } else { + fetchedArticles.formUnion(articleFetcher.fetchArticles()) + } } return fetchedArticles } @@ -1000,7 +1031,8 @@ 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, readFilter: false, representedObjects: representedObjects) { [weak self] (articles, operation) in + let readFilter = articleReadFilterType != ReadFilterType.none + let fetchOperation = FetchRequestOperation(id: fetchSerialNumber, readFilter: readFilter, representedObjects: representedObjects) { [weak self] (articles, operation) in precondition(Thread.isMainThread) guard !operation.isCanceled, let strongSelf = self, operation.id == strongSelf.fetchSerialNumber else { return