From ffaa55c50cdf4db5e50b54c4305cdcd8e223f60f Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Sun, 19 Nov 2017 16:28:26 -0800 Subject: [PATCH] Implement mark-everywhere-as-read. --- Evergreen/AppDelegate.swift | 29 +++++++++++++++++++ Evergreen/Base.lproj/Main.storyboard | 3 ++ .../MainWindow/MainWindowController.swift | 5 ++++ Evergreen/PseudoFeeds/SmartFeed.swift | 2 +- Frameworks/Account/Account.swift | 8 +++++ Frameworks/Database/ArticlesTable.swift | 5 ++++ Frameworks/Database/Database.swift | 5 ++++ Frameworks/Database/StatusesTable.swift | 21 +++++++++++++- 8 files changed, 76 insertions(+), 2 deletions(-) diff --git a/Evergreen/AppDelegate.swift b/Evergreen/AppDelegate.swift index 8267b949c..6d7744d77 100644 --- a/Evergreen/AppDelegate.swift +++ b/Evergreen/AppDelegate.swift @@ -86,6 +86,28 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, panicButtonWindowController!.runSheetOnWindow(window) } + func markEverywhereAsRead(with window: NSWindow) { + + let alert = NSAlert() + alert.messageText = NSLocalizedString("Mark All Articles as Read Everywhere?", comment: "Mark Everywhere alert messageText") + alert.informativeText = NSLocalizedString("This will mark every single article as read. All of them. The unread count will be zero.\n\nNote: this operation cannot be undone.", comment: "Mark Everywhere informativeText.") + + alert.addButton(withTitle: NSLocalizedString("Mark All Articles as Read", comment: "Mark Everywhere alert button.")) + alert.addButton(withTitle: NSLocalizedString("Don’t Mark as Read", comment: "Mark Everywhere alert button.")) + + alert.beginSheetModal(for: window) { (returnCode) in + + if returnCode == .alertFirstButtonReturn { + self.markEverywhereAsRead() + } + } + } + + func markEverywhereAsRead() { + + AccountManager.shared.accounts.forEach { $0.markEverywhereAsRead() } + } + // MARK: - NSApplicationDelegate func applicationDidFinishLaunching(_ note: Notification) { @@ -377,6 +399,13 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, createAndShowMainWindow() markOlderArticlesAsRead(with: mainWindowController!.window!) } + + @IBAction func markEverywhereAsRead(_ sender: Any?) { + + createAndShowMainWindow() + markEverywhereAsRead(with: mainWindowController!.window!) + } + } private extension AppDelegate { diff --git a/Evergreen/Base.lproj/Main.storyboard b/Evergreen/Base.lproj/Main.storyboard index 1a31ca9c3..c1237e996 100644 --- a/Evergreen/Base.lproj/Main.storyboard +++ b/Evergreen/Base.lproj/Main.storyboard @@ -438,6 +438,9 @@ + + + diff --git a/Evergreen/MainWindow/MainWindowController.swift b/Evergreen/MainWindow/MainWindowController.swift index 33a7487c6..26214a4b1 100644 --- a/Evergreen/MainWindow/MainWindowController.swift +++ b/Evergreen/MainWindow/MainWindowController.swift @@ -164,6 +164,11 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations { appDelegate.markOlderArticlesAsRead(with: window!) } + + @IBAction func markEverywhereAsRead(_ sender: Any?) { + + appDelegate.markEverywhereAsRead(with: window!) + } } // MARK: - Private diff --git a/Evergreen/PseudoFeeds/SmartFeed.swift b/Evergreen/PseudoFeeds/SmartFeed.swift index 8635b5a53..e623399b0 100644 --- a/Evergreen/PseudoFeeds/SmartFeed.swift +++ b/Evergreen/PseudoFeeds/SmartFeed.swift @@ -88,7 +88,7 @@ private extension SmartFeed { timer = nil } - private static let fetchCoalescingDelay: TimeInterval = 0.2 + private static let fetchCoalescingDelay: TimeInterval = 0.1 func startTimer() { diff --git a/Frameworks/Account/Account.swift b/Frameworks/Account/Account.swift index 034db558b..dcdee16ed 100644 --- a/Frameworks/Account/Account.swift +++ b/Frameworks/Account/Account.swift @@ -335,6 +335,14 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container, database.fetchStarredAndUnreadCount(for: flattenedFeeds(), callback: callback) } + public func markEverywhereAsRead() { + + // Does not support undo. + + database.markEverywhereAsRead() + flattenedFeeds().forEach { $0.unreadCount = 0 } + } + // MARK: - Notifications @objc func downloadProgressDidChange(_ note: Notification) { diff --git a/Frameworks/Database/ArticlesTable.swift b/Frameworks/Database/ArticlesTable.swift index 1f0d8eb0f..7d6bd1af1 100644 --- a/Frameworks/Database/ArticlesTable.swift +++ b/Frameworks/Database/ArticlesTable.swift @@ -187,6 +187,11 @@ final class ArticlesTable: DatabaseTable { return statusesTable.mark(articles.statuses(), statusKey, flag) } + + func markEverywhereAsRead() { + + return statusesTable.markEverywhereAsRead() + } } // MARK: - Private diff --git a/Frameworks/Database/Database.swift b/Frameworks/Database/Database.swift index 2365274bf..c312cce2e 100644 --- a/Frameworks/Database/Database.swift +++ b/Frameworks/Database/Database.swift @@ -84,5 +84,10 @@ public final class Database { return articlesTable.mark(articles, statusKey, flag) } + + public func markEverywhereAsRead() { + + articlesTable.markEverywhereAsRead() + } } diff --git a/Frameworks/Database/StatusesTable.swift b/Frameworks/Database/StatusesTable.swift index bda6a63d4..421911294 100644 --- a/Frameworks/Database/StatusesTable.swift +++ b/Frameworks/Database/StatusesTable.swift @@ -76,6 +76,20 @@ final class StatusesTable: DatabaseTable { return updatedStatuses } + func markEverywhereAsRead() { + + queue.update { (database) in + + let _ = database.executeUpdate("update statuses set read=1;", withArgumentsIn: nil) + + let cachedStatuses = self.cache.cachedStatuses + + DispatchQueue.main.async { + cachedStatuses.forEach { $0.read = true } + } + } + } + // MARK: Fetching func statusWithRow(_ row: FMResultSet) -> ArticleStatus? { @@ -164,6 +178,11 @@ private final class StatusCache { // Serial database queue only. var dictionary = [String: ArticleStatus]() + var cachedStatuses: Set { + get { + return Set(dictionary.values) + } + } func add(_ statuses: Set) { @@ -191,7 +210,7 @@ private final class StatusCache { self[articleID] = status } } - + subscript(_ articleID: String) -> ArticleStatus? { get { return dictionary[articleID]