diff --git a/Mac/MainWindow/MainWindowController.swift b/Mac/MainWindow/MainWindowController.swift index de5bdfa30..18a965024 100644 --- a/Mac/MainWindow/MainWindowController.swift +++ b/Mac/MainWindow/MainWindowController.swift @@ -387,6 +387,16 @@ extension MainWindowController: SidebarDelegate { updateWindowTitle() NotificationCenter.default.post(name: .InspectableObjectsDidChange, object: nil) } + + func unreadCount(for representedObject: AnyObject) -> Int { + guard let timelineViewController = regularTimelineViewController else { + return 0 + } + guard timelineViewController.representsThisObjectOnly(representedObject) else { + return 0 + } + return timelineViewController.unreadCount + } } // MARK: - TimelineContainerViewControllerDelegate @@ -545,6 +555,10 @@ private extension MainWindowController { return timelineContainerViewController?.currentTimelineViewController } + var regularTimelineViewController: TimelineViewController? { + return timelineContainerViewController?.regularTimelineViewController + } + var sidebarSplitViewItem: NSSplitViewItem? { return splitViewController?.splitViewItems[0] } diff --git a/Mac/MainWindow/Sidebar/SidebarViewController.swift b/Mac/MainWindow/Sidebar/SidebarViewController.swift index 2e50721f0..8426e1dc1 100644 --- a/Mac/MainWindow/Sidebar/SidebarViewController.swift +++ b/Mac/MainWindow/Sidebar/SidebarViewController.swift @@ -14,6 +14,7 @@ import RSCore protocol SidebarDelegate: class { func sidebarSelectionDidChange(_: SidebarViewController, selectedObjects: [AnyObject]?) + func unreadCount(for: AnyObject) -> Int } @objc class SidebarViewController: NSViewController, NSOutlineViewDelegate, NSOutlineViewDataSource, NSMenuDelegate, UndoableCommandRunner { @@ -59,7 +60,6 @@ protocol SidebarDelegate: class { NotificationCenter.default.addObserver(self, selector: #selector(feedSettingDidChange(_:)), name: .FeedSettingDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange(_:)), name: .DisplayNameDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(userDidRequestSidebarSelection(_:)), name: .UserDidRequestSidebarSelection, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(calendarDayChanged(_:)), name: .NSCalendarDayChanged, object: nil) outlineView.reloadData() @@ -139,12 +139,6 @@ protocol SidebarDelegate: class { revealAndSelectRepresentedObject(feed as AnyObject) } - @objc func calendarDayChanged(_ note: Notification) { - DispatchQueue.main.async { - SmartFeedsController.shared.todayFeed.fetchUnreadCounts() - } - } - // MARK: - Actions @IBAction func delete(_ sender: AnyObject?) { @@ -503,6 +497,14 @@ private extension SidebarViewController { } func unreadCountFor(_ node: Node) -> Int { + // If this node is the one and only selection, + // then the unread count comes from the timeline. + // This ensures that any transients in the timeline + // are accounted for in the unread count. + if selectedNodes.count == 1 && node === selectedNodes.first! { + return delegate?.unreadCount(for: node.representedObject) ?? 0 + } + if let unreadCountProvider = node.representedObject as? UnreadCountProvider { return unreadCountProvider.unreadCount } diff --git a/Mac/MainWindow/Timeline/TimelineContainerViewController.swift b/Mac/MainWindow/Timeline/TimelineContainerViewController.swift index 12f6d62d2..a8fa3bb84 100644 --- a/Mac/MainWindow/Timeline/TimelineContainerViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineContainerViewController.swift @@ -30,7 +30,7 @@ final class TimelineContainerViewController: NSViewController { weak var delegate: TimelineContainerViewControllerDelegate? - private lazy var regularTimelineViewController = { + lazy var regularTimelineViewController = { return TimelineViewController(delegate: self) }() private lazy var searchTimelineViewController: TimelineViewController = { diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index 7249da5bb..26750287d 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -19,14 +19,14 @@ protocol TimelineDelegate: class { func timelineSelectionDidChange(_: TimelineViewController, selectedArticles: [Article]?) } -final class TimelineViewController: NSViewController, UndoableCommandRunner { +final class TimelineViewController: NSViewController, UndoableCommandRunner, UnreadCountProvider { @IBOutlet var tableView: TimelineTableView! var representedObjects: [AnyObject]? { didSet { if !representedObjectArraysAreEqual(oldValue, representedObjects) { - + unreadCount = 0 if let representedObjects = representedObjects { if representedObjects.count == 1 && representedObjects.first is Feed { showFeedNames = false @@ -76,11 +76,21 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner { // Just reload visible cells in this case: don’t call reloadData. articleRowMap = [String: Int]() reloadVisibleCells() + updateUnreadCount() return } updateShowAvatars() articleRowMap = [String: Int]() tableView.reloadData() + updateUnreadCount() + } + } + + var unreadCount: Int = 0 { + didSet { + if unreadCount != oldValue { + postUnreadCountDidChangeNotification() + } } } @@ -221,6 +231,16 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner { return selectedArticles.canMarkAllAsRead() } + func representsThisObjectOnly(_ object: AnyObject) -> Bool { + guard let representedObjects = representedObjects else { + return false + } + if representedObjects.count != 1 { + return false + } + return representedObjects.first! === object + } + // MARK: - Actions @objc func openArticleInBrowser(_ sender: Any?) { @@ -448,6 +468,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner { return } reloadVisibleCells(for: articles) + updateUnreadCount() } @objc func feedIconDidBecomeAvailable(_ note: Notification) { @@ -810,6 +831,16 @@ private extension TimelineViewController { } } + func updateUnreadCount() { + var count = 0 + for article in articles { + if !article.status.read { + count += 1 + } + } + unreadCount = count + } + func queueReloadAvailableCells() { CoalescingQueue.standard.add(self, #selector(reloadAvailableCells))