diff --git a/iOS/AppAssets.swift b/iOS/AppAssets.swift index 96cad2b37..5d7749b09 100644 --- a/iOS/AppAssets.swift +++ b/iOS/AppAssets.swift @@ -117,11 +117,11 @@ struct AppAssets { return UIImage(systemName: "asterisk.circle")! }() - static var markOlderAsReadDownImage: UIImage = { + static var markBelowAsReadImage: UIImage = { return UIImage(systemName: "arrowtriangle.down.circle")! }() - static var markOlderAsReadUpImage: UIImage = { + static var markAboveAsReadImage: UIImage = { return UIImage(systemName: "arrowtriangle.up.circle")! }() diff --git a/iOS/KeyboardManager.swift b/iOS/KeyboardManager.swift index 5dfa1a492..78753d38f 100644 --- a/iOS/KeyboardManager.swift +++ b/iOS/KeyboardManager.swift @@ -168,8 +168,8 @@ private extension KeyboardManager { let toggleReadTitle = NSLocalizedString("Toggle Read Status", comment: "Toggle Read Status") keys.append(KeyboardManager.createKeyCommand(title: toggleReadTitle, action: "toggleRead:", input: "u", modifiers: [.command, .shift])) - let markOlderAsReadTitle = NSLocalizedString("Mark Older as Read", comment: "Mark Older as Read") - keys.append(KeyboardManager.createKeyCommand(title: markOlderAsReadTitle, action: "markOlderArticlesAsRead:", input: "k", modifiers: [.command, .shift])) + let markOlderAsReadTitle = NSLocalizedString("Mark Below as Read", comment: "Mark Below as Read") + keys.append(KeyboardManager.createKeyCommand(title: markOlderAsReadTitle, action: "markBelowAsRead:", input: "k", modifiers: [.command, .shift])) let toggleStarredTitle = NSLocalizedString("Toggle Starred Status", comment: "Toggle Starred Status") keys.append(KeyboardManager.createKeyCommand(title: toggleStarredTitle, action: "toggleStarred:", input: "l", modifiers: [.command, .shift])) diff --git a/iOS/MasterTimeline/MasterTimelineViewController.swift b/iOS/MasterTimeline/MasterTimelineViewController.swift index f2cbc437a..e0a91330d 100644 --- a/iOS/MasterTimeline/MasterTimelineViewController.swift +++ b/iOS/MasterTimeline/MasterTimelineViewController.swift @@ -245,8 +245,14 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner popoverController.sourceView = view popoverController.sourceRect = CGRect(x: view.frame.size.width/2, y: view.frame.size.height/2, width: 1, height: 1) } - - alert.addAction(self.markOlderAsReadAlertAction(article, completion: completion)) + + if let action = self.markAboveAsReadAlertAction(article, completion: completion) { + alert.addAction(action) + } + + if let action = self.markBelowAsReadAlertAction(article, completion: completion) { + alert.addAction(action) + } if let action = self.discloseFeedAlertAction(article, completion: completion) { alert.addAction(action) @@ -293,7 +299,14 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner var actions = [UIAction]() actions.append(self.toggleArticleReadStatusAction(article)) actions.append(self.toggleArticleStarStatusAction(article)) - actions.append(self.markOlderAsReadAction(article)) + + if let action = self.markAboveAsReadAction(article) { + actions.append(action) + } + + if let action = self.markBelowAsReadAction(article) { + actions.append(action) + } if let action = self.discloseFeedAction(article) { actions.append(action) @@ -636,20 +649,54 @@ private extension MasterTimelineViewController { return action } - - func markOlderAsReadAction(_ article: Article) -> UIAction { - let title = NSLocalizedString("Mark Older as Read", comment: "Mark Older as Read") - let image = coordinator.sortDirection == .orderedDescending ? AppAssets.markOlderAsReadDownImage : AppAssets.markOlderAsReadUpImage + + func markAboveAsReadAction(_ article: Article) -> UIAction? { + guard coordinator.canMarkAboveAsRead(for: article) else { + return nil + } + + let title = NSLocalizedString("Mark Above as Read", comment: "Mark Above as Read") + let image = AppAssets.markAboveAsReadImage let action = UIAction(title: title, image: image) { [weak self] action in - self?.coordinator.markAsReadOlderArticlesInTimeline(article) + self?.coordinator.markAboveAsRead(article) } return action } - func markOlderAsReadAlertAction(_ article: Article, completion: @escaping (Bool) -> Void) -> UIAlertAction { - let title = NSLocalizedString("Mark Older as Read", comment: "Mark Older as Read") + func markBelowAsReadAction(_ article: Article) -> UIAction? { + guard coordinator.canMarkBelowAsRead(for: article) else { + return nil + } + + let title = NSLocalizedString("Mark Below as Read", comment: "Mark Below as Read") + let image = AppAssets.markBelowAsReadImage + let action = UIAction(title: title, image: image) { [weak self] action in + self?.coordinator.markBelowAsRead(article) + } + return action + } + + func markAboveAsReadAlertAction(_ article: Article, completion: @escaping (Bool) -> Void) -> UIAlertAction? { + guard coordinator.canMarkAboveAsRead(for: article) else { + return nil + } + + let title = NSLocalizedString("Mark Above as Read", comment: "Mark Above as Read") let action = UIAlertAction(title: title, style: .default) { [weak self] action in - self?.coordinator.markAsReadOlderArticlesInTimeline(article) + self?.coordinator.markAboveAsRead(article) + completion(true) + } + return action + } + + func markBelowAsReadAlertAction(_ article: Article, completion: @escaping (Bool) -> Void) -> UIAlertAction? { + guard coordinator.canMarkBelowAsRead(for: article) else { + return nil + } + + let title = NSLocalizedString("Mark Below as Read", comment: "Mark Below as Read") + let action = UIAlertAction(title: title, style: .default) { [weak self] action in + self?.coordinator.markBelowAsRead(article) completion(true) } return action diff --git a/iOS/RootSplitViewController.swift b/iOS/RootSplitViewController.swift index 2e2ca5e68..b4b88a527 100644 --- a/iOS/RootSplitViewController.swift +++ b/iOS/RootSplitViewController.swift @@ -54,8 +54,8 @@ class RootSplitViewController: UISplitViewController { coordinator.selectNextUnread() } - @objc func markOlderArticlesAsRead(_ sender: Any?) { - coordinator.markAsReadOlderArticlesInTimeline() + @objc func markBelowAsRead(_ sender: Any?) { + coordinator.markBelowAsRead() } @objc func markUnread(_ sender: Any?) { diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 6e7393c97..78bfe95d8 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -870,19 +870,45 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { markAllAsRead(articles) masterNavigationController.popViewController(animated: true) } - - func markAsReadOlderArticlesInTimeline() { - if let article = currentArticle { - markAsReadOlderArticlesInTimeline(article) - } + + func canMarkAboveAsRead(for article: Article) -> Bool { + return articles.first != article } - - func markAsReadOlderArticlesInTimeline(_ article: Article) { - let articlesToMark = articles.filter { $0.logicalDatePublished < article.logicalDatePublished } - if articlesToMark.isEmpty { + + func markAboveAsRead(_ article: Article) { + guard let position = articles.firstIndex(of: article) else { return } - markAllAsRead(articlesToMark) + + let articlesAbove = articles[.. Bool { + return articles.last != article + } + + func markBelowAsRead() { + guard let currentArticle = currentArticle else { + return + } + + markBelowAsRead(currentArticle) + } + + func markBelowAsRead(_ article: Article) { + guard let position = articles.firstIndex(of: article) else { + return + } + + var articlesBelow = Array(articles[position...]) + + guard !articlesBelow.isEmpty else { + return + } + + articlesBelow.removeFirst() + markAllAsRead(articlesBelow) } func markAsReadForCurrentArticle() {