diff --git a/Mac/MainWindow/Timeline/TimelineViewController.swift b/Mac/MainWindow/Timeline/TimelineViewController.swift index 38cec256e..d29c91a8d 100644 --- a/Mac/MainWindow/Timeline/TimelineViewController.swift +++ b/Mac/MainWindow/Timeline/TimelineViewController.swift @@ -191,6 +191,8 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr private let keyboardDelegate = TimelineKeyboardDelegate() private var timelineShowsSeparatorsObserver: NSKeyValueObservation? + let scrollPositionQueue = CoalescingQueue(name: "Timeline Scroll Position", interval: 0.3, maxInterval: 1.0) + convenience init(delegate: TimelineDelegate) { self.init(nibName: "TimelineTableView", bundle: nil) self.delegate = delegate @@ -223,6 +225,12 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr NotificationCenter.default.addObserver(self, selector: #selector(containerChildrenDidChange(_:)), name: .ChildrenDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil) + if let scrollView = self.tableView.enclosingScrollView { + scrollView.contentView.postsBoundsChangedNotifications = true + + NotificationCenter.default.addObserver(self, selector: #selector(scrollViewDidScroll(notification:)), name: NSView.boundsDidChangeNotification, object: scrollView.contentView) + } + didRegisterForNotifications = true } } @@ -324,6 +332,20 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr } } + @objc func scrollViewDidScroll(notification: Notification){ + scrollPositionQueue.add(self, #selector(scrollPositionDidChange)) + } + + @objc func scrollPositionDidChange(){ + let firstVisibleRowIndex = tableView.rows(in: tableView.visibleRect).location + guard let unreadArticlesScrolledAway = articles.articlesAbove(position: firstVisibleRowIndex).unreadArticles() else { return } + + guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: unreadArticlesScrolledAway, markingRead: true, undoManager: undoManager) else { + return + } + runCommand(markReadCommand) + } + @IBAction func toggleStatusOfSelectedArticles(_ sender: Any?) { guard !selectedArticles.isEmpty else { return diff --git a/iOS/MasterTimeline/MasterTimelineViewController.swift b/iOS/MasterTimeline/MasterTimelineViewController.swift index 72a019828..73b39ee99 100644 --- a/iOS/MasterTimeline/MasterTimelineViewController.swift +++ b/iOS/MasterTimeline/MasterTimelineViewController.swift @@ -516,6 +516,24 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner @objc func scrollPositionDidChange() { coordinator.timelineMiddleIndexPath = tableView.middleVisibleRow() + + guard let firstVisibleRowIndexPath = tableView.indexPathsForVisibleRows?[0] else { return } + + guard let firstVisibleArticle = dataSource.itemIdentifier(for: firstVisibleRowIndexPath) else { + return + } + + guard let unreadArticlesScrolledAway = coordinator.articles.articlesAbove(article: firstVisibleArticle).unreadArticles() else { return } + + coordinator.markAllAsRead(unreadArticlesScrolledAway) + + for article in unreadArticlesScrolledAway { + if let indexPath = dataSource.indexPath(for: article) { + if let cell = tableView.cellForRow(at: indexPath) as? MasterTimelineTableViewCell { + configure(cell, article: article) + } + } + } } // MARK: Reloading