Add the concept of direct vs. indirect marking of articles. Fixes #3734

This commit is contained in:
Maurice Parker
2022-11-14 21:10:16 -06:00
parent 02e19366fb
commit 7c9ac3d712
7 changed files with 223 additions and 39 deletions

View File

@@ -637,6 +637,10 @@ extension MainWindowController: NSWindowDelegate {
extension MainWindowController: SidebarDelegate {
var directlyMarkedAsUnreadArticles: Set<Article>? {
return timelineContainerViewController?.currentTimelineViewController?.directlyMarkedAsUnreadArticles
}
func sidebarSelectionDidChange(_: SidebarViewController, selectedObjects: [AnyObject]?) {
// Dont update the timeline if it already has those objects.
let representedObjectsAreTheSame = timelineContainerViewController?.regularTimelineViewControllerHasRepresentedObjects(selectedObjects) ?? false

View File

@@ -69,8 +69,16 @@ extension SidebarViewController {
return
}
let articles = unreadArticles(for: objects)
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: Array(articles), markingRead: true, undoManager: undoManager) else {
var markableArticles = unreadArticles(for: objects)
if let directlyMarkedAsUnreadArticles = delegate?.directlyMarkedAsUnreadArticles {
markableArticles = markableArticles.subtracting(directlyMarkedAsUnreadArticles)
}
guard let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: markableArticles,
markingRead: true,
directlyMarked: false,
undoManager: undoManager) else {
return
}
runCommand(markReadCommand)

View File

@@ -17,6 +17,7 @@ extension Notification.Name {
}
protocol SidebarDelegate: AnyObject {
var directlyMarkedAsUnreadArticles: Set<Article>? { get }
func sidebarSelectionDidChange(_: SidebarViewController, selectedObjects: [AnyObject]?)
func unreadCount(for: AnyObject) -> Int
func sidebarInvalidatedRestorationState(_: SidebarViewController)
@@ -256,7 +257,11 @@ protocol SidebarDelegate: AnyObject {
return
}
if AppDefaults.shared.feedDoubleClickMarkAsRead, let articles = try? singleSelectedWebFeed?.fetchUnreadArticles() {
if let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: Array(articles), markingRead: true, undoManager: undoManager) {
if let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: Array(articles),
markingRead: true,
directlyMarked: false,
undoManager: undoManager) {
runCommand(markReadCommand)
}
}

View File

@@ -39,12 +39,12 @@ extension TimelineViewController {
@objc func markArticlesReadFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { return }
markArticles(articles, read: true)
markArticles(articles, read: true, directlyMarked: true)
}
@objc func markArticlesUnreadFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { return }
markArticles(articles, read: false)
markArticles(articles, read: false, directlyMarked: true)
}
@objc func markAboveArticlesReadFromContextualMenu(_ sender: Any?) {
@@ -59,14 +59,14 @@ extension TimelineViewController {
@objc func markArticlesStarredFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { return }
markArticles(articles, starred: true)
markArticles(articles, starred: true, directlyMarked: true)
}
@objc func markArticlesUnstarredFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else {
return
}
markArticles(articles, starred: false)
markArticles(articles, starred: false, directlyMarked: true)
}
@objc func selectFeedInSidebarFromContextualMenu(_ sender: Any?) {
@@ -81,7 +81,11 @@ extension TimelineViewController {
return
}
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: feedArticles, markingRead: true, undoManager: undoManager) else {
guard let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: feedArticles,
markingRead: true,
directlyMarked: false,
undoManager: undoManager) else {
return
}
@@ -115,16 +119,21 @@ extension TimelineViewController {
private extension TimelineViewController {
func markArticles(_ articles: [Article], read: Bool) {
markArticles(articles, statusKey: .read, flag: read)
func markArticles(_ articles: [Article], read: Bool, directlyMarked: Bool) {
markArticles(articles, statusKey: .read, flag: read, directlyMarked: directlyMarked)
}
func markArticles(_ articles: [Article], starred: Bool) {
markArticles(articles, statusKey: .starred, flag: starred)
func markArticles(_ articles: [Article], starred: Bool, directlyMarked: Bool) {
markArticles(articles, statusKey: .starred, flag: starred, directlyMarked: directlyMarked)
}
func markArticles(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool) {
guard let undoManager = undoManager, let markStatusCommand = MarkStatusCommand(initialArticles: articles, statusKey: statusKey, flag: flag, undoManager: undoManager) else {
func markArticles(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool, directlyMarked: Bool) {
guard let undoManager = undoManager,
let markStatusCommand = MarkStatusCommand(initialArticles: articles,
statusKey: statusKey,
flag: flag,
directlyMarked: directlyMarked,
undoManager: undoManager) else {
return
}

View File

@@ -123,10 +123,13 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
showFeedNames = .feed
}
directlyMarkedAsUnreadArticles = Set<Article>()
articleRowMap = [String: [Int]]()
tableView.reloadData()
}
}
var directlyMarkedAsUnreadArticles = Set<Article>()
var unreadCount: Int = 0 {
didSet {
@@ -219,6 +222,8 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange(_:)), name: .UserDidDeleteAccount, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(containerChildrenDidChange(_:)), name: .ChildrenDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(markStatusCommandDidDirectMarking(_:)), name: .MarkStatusCommandDidDirectMarking, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(markStatusCommandDidUndoDirectMarking(_:)), name: .MarkStatusCommandDidUndoDirectMarking, object: nil)
didRegisterForNotifications = true
}
}
@@ -230,7 +235,13 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
// MARK: - API
func markAllAsRead(completion: (() -> Void)? = nil) {
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: articles, markingRead: true, undoManager: undoManager, completion: completion) else {
let markableArticles = Set(articles).subtracting(directlyMarkedAsUnreadArticles)
guard let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: markableArticles,
markingRead: true,
directlyMarked: false,
undoManager: undoManager,
completion: completion) else {
return
}
runCommand(markReadCommand)
@@ -336,14 +347,22 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
}
@IBAction func markSelectedArticlesAsRead(_ sender: Any?) {
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: selectedArticles, markingRead: true, undoManager: undoManager) else {
guard let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: selectedArticles,
markingRead: true,
directlyMarked: true,
undoManager: undoManager) else {
return
}
runCommand(markReadCommand)
}
@IBAction func markSelectedArticlesAsUnread(_ sender: Any?) {
guard let undoManager = undoManager, let markUnreadCommand = MarkStatusCommand(initialArticles: selectedArticles, markingRead: false, undoManager: undoManager) else {
guard let undoManager = undoManager,
let markUnreadCommand = MarkStatusCommand(initialArticles: selectedArticles,
markingRead: false,
directlyMarked: true,
undoManager: undoManager) else {
return
}
runCommand(markUnreadCommand)
@@ -411,7 +430,11 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
return
}
guard let undoManager = undoManager, let markStarredCommand = MarkStatusCommand(initialArticles: selectedArticles, markingRead: markingRead, undoManager: undoManager) else {
guard let undoManager = undoManager,
let markStarredCommand = MarkStatusCommand(initialArticles: selectedArticles,
markingRead: markingRead,
directlyMarked: true,
undoManager: undoManager) else {
return
}
@@ -434,7 +457,11 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
return
}
guard let undoManager = undoManager, let markStarredCommand = MarkStatusCommand(initialArticles: selectedArticles, markingStarred: starring, undoManager: undoManager) else {
guard let undoManager = undoManager,
let markStarredCommand = MarkStatusCommand(initialArticles: selectedArticles,
markingStarred: starring,
directlyMarked: true,
undoManager: undoManager) else {
return
}
runCommand(markStarredCommand)
@@ -501,7 +528,12 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
return
}
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: articlesToMark, markingRead: true, undoManager: undoManager) else {
let markableArticles = Set(articlesToMark).subtracting(directlyMarkedAsUnreadArticles)
guard let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: markableArticles,
markingRead: true,
directlyMarked: false,
undoManager: undoManager) else {
return
}
runCommand(markReadCommand)
@@ -509,9 +541,16 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
func markAboveArticlesRead(_ selectedArticles: [Article]) {
guard let first = selectedArticles.first else { return }
let articlesToMark = articles.articlesAbove(article: first)
guard !articlesToMark.isEmpty else { return }
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: articlesToMark, markingRead: true, undoManager: undoManager) else {
let markableArticles = Set(articlesToMark).subtracting(directlyMarkedAsUnreadArticles)
guard let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: markableArticles,
markingRead: true,
directlyMarked: false,
undoManager: undoManager) else {
return
}
runCommand(markReadCommand)
@@ -519,9 +558,16 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
func markBelowArticlesRead(_ selectedArticles: [Article]) {
guard let last = selectedArticles.last else { return }
let articlesToMark = articles.articlesBelow(article: last)
guard !articlesToMark.isEmpty else { return }
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: articlesToMark, markingRead: true, undoManager: undoManager) else {
let markableArticles = Set(articlesToMark).subtracting(directlyMarkedAsUnreadArticles)
guard let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: markableArticles,
markingRead: true,
directlyMarked: false,
undoManager: undoManager) else {
return
}
runCommand(markReadCommand)
@@ -665,6 +711,28 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
self.groupByFeed = AppDefaults.shared.timelineGroupByFeed
}
@objc func markStatusCommandDidDirectMarking(_ note: Notification) {
guard let userInfo = note.userInfo,
let articles = userInfo[Account.UserInfoKey.articles] as? Set<Article>,
let statusKey = userInfo[Account.UserInfoKey.statusKey] as? ArticleStatus.Key,
let flag = userInfo[Account.UserInfoKey.statusFlag] as? Bool else { return }
if statusKey == .read && flag == false {
directlyMarkedAsUnreadArticles.formUnion(articles)
}
}
@objc func markStatusCommandDidUndoDirectMarking(_ note: Notification) {
guard let userInfo = note.userInfo,
let articles = userInfo[Account.UserInfoKey.articles] as? Set<Article>,
let statusKey = userInfo[Account.UserInfoKey.statusKey] as? ArticleStatus.Key,
let flag = userInfo[Account.UserInfoKey.statusFlag] as? Bool else { return }
if statusKey == .read && flag == false {
directlyMarkedAsUnreadArticles.subtract(articles)
}
}
// MARK: - Reloading Data
private func cellForRowView(_ rowView: NSView) -> NSView? {
@@ -899,14 +967,22 @@ extension TimelineViewController: NSTableViewDelegate {
}
private func toggleArticleRead(_ article: Article) {
guard let undoManager = undoManager, let markUnreadCommand = MarkStatusCommand(initialArticles: [article], markingRead: !article.status.read, undoManager: undoManager) else {
guard let undoManager = undoManager,
let markUnreadCommand = MarkStatusCommand(initialArticles: [article],
markingRead: !article.status.read,
directlyMarked: true,
undoManager: undoManager) else {
return
}
self.runCommand(markUnreadCommand)
}
private func toggleArticleStarred(_ article: Article) {
guard let undoManager = undoManager, let markUnreadCommand = MarkStatusCommand(initialArticles: [article], markingStarred: !article.status.starred, undoManager: undoManager) else {
guard let undoManager = undoManager,
let markUnreadCommand = MarkStatusCommand(initialArticles: [article],
markingStarred: !article.status.starred,
directlyMarked: true,
undoManager: undoManager) else {
return
}
self.runCommand(markUnreadCommand)

View File

@@ -8,9 +8,20 @@
import Foundation
import RSCore
import Account
import Articles
// Mark articles read/unread, starred/unstarred, deleted/undeleted.
//
// Directly marked articles are ones that were statused by selecting with a cursor or were selected by group.
// Indirectly marked articles didn't have any focus and were picked up using a Mark All command like Mark All as Read.
//
// See discussion for details: https://github.com/Ranchero-Software/NetNewsWire/issues/3734
public extension Notification.Name {
static let MarkStatusCommandDidDirectMarking = Notification.Name("MarkStatusCommandDid√DirectMarking")
static let MarkStatusCommandDidUndoDirectMarking = Notification.Name("MarkStatusCommandDidUndoDirectMarking")
}
final class MarkStatusCommand: UndoableCommand {
@@ -19,10 +30,11 @@ final class MarkStatusCommand: UndoableCommand {
let articles: Set<Article>
let undoManager: UndoManager
let flag: Bool
let directlyMarked: Bool
let statusKey: ArticleStatus.Key
var completion: (() -> Void)? = nil
init?(initialArticles: [Article], statusKey: ArticleStatus.Key, flag: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
init?(initialArticles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, directlyMarked: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
// Filter out articles that already have the desired status or can't be marked.
let articlesToMark = MarkStatusCommand.filteredArticles(initialArticles, statusKey, flag)
@@ -30,8 +42,9 @@ final class MarkStatusCommand: UndoableCommand {
completion?()
return nil
}
self.articles = Set(articlesToMark)
self.articles = articlesToMark
self.directlyMarked = directlyMarked
self.flag = flag
self.statusKey = statusKey
self.undoManager = undoManager
@@ -42,21 +55,39 @@ final class MarkStatusCommand: UndoableCommand {
self.redoActionName = actionName
}
convenience init?(initialArticles: [Article], markingRead: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
self.init(initialArticles: initialArticles, statusKey: .read, flag: markingRead, undoManager: undoManager, completion: completion)
convenience init?(initialArticles: [Article], statusKey: ArticleStatus.Key, flag: Bool, directlyMarked: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
self.init(initialArticles: Set(initialArticles), statusKey: .read, flag: flag, directlyMarked: directlyMarked, undoManager: undoManager, completion: completion)
}
convenience init?(initialArticles: [Article], markingStarred: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
self.init(initialArticles: initialArticles, statusKey: .starred, flag: markingStarred, undoManager: undoManager, completion: completion)
convenience init?(initialArticles: Set<Article>, markingRead: Bool, directlyMarked: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
self.init(initialArticles: initialArticles, statusKey: .read, flag: markingRead, directlyMarked: directlyMarked, undoManager: undoManager, completion: completion)
}
convenience init?(initialArticles: [Article], markingRead: Bool, directlyMarked: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
self.init(initialArticles: initialArticles, statusKey: .read, flag: markingRead, directlyMarked: directlyMarked, undoManager: undoManager, completion: completion)
}
convenience init?(initialArticles: Set<Article>, markingStarred: Bool, directlyMarked: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
self.init(initialArticles: initialArticles, statusKey: .starred, flag: markingStarred, directlyMarked: directlyMarked, undoManager: undoManager, completion: completion)
}
convenience init?(initialArticles: [Article], markingStarred: Bool, directlyMarked: Bool, undoManager: UndoManager, completion: (() -> Void)? = nil) {
self.init(initialArticles: initialArticles, statusKey: .starred, flag: markingStarred, directlyMarked: directlyMarked, undoManager: undoManager, completion: completion)
}
func perform() {
mark(statusKey, flag)
if directlyMarked {
markStatusCommandDidDirectMarking()
}
registerUndo()
}
func undo() {
mark(statusKey, !flag)
if directlyMarked {
markStatusCommandDidUndoDirectMarking()
}
registerRedo()
}
}
@@ -67,6 +98,18 @@ private extension MarkStatusCommand {
markArticles(articles, statusKey: statusKey, flag: flag, completion: completion)
completion = nil
}
func markStatusCommandDidDirectMarking() {
NotificationCenter.default.post(name: .MarkStatusCommandDidDirectMarking, object: self, userInfo: [Account.UserInfoKey.articles: articles,
Account.UserInfoKey.statusKey: statusKey,
Account.UserInfoKey.statusFlag: flag])
}
func markStatusCommandDidUndoDirectMarking() {
NotificationCenter.default.post(name: .MarkStatusCommandDidUndoDirectMarking, object: self, userInfo: [Account.UserInfoKey.articles: articles,
Account.UserInfoKey.statusKey: statusKey,
Account.UserInfoKey.statusFlag: flag])
}
static private let markReadActionName = NSLocalizedString("Mark Read", comment: "command")
static private let markUnreadActionName = NSLocalizedString("Mark Unread", comment: "command")
@@ -83,7 +126,7 @@ private extension MarkStatusCommand {
}
}
static func filteredArticles(_ articles: [Article], _ statusKey: ArticleStatus.Key, _ flag: Bool) -> [Article] {
static func filteredArticles(_ articles: Set<Article>, _ statusKey: ArticleStatus.Key, _ flag: Bool) -> Set<Article> {
return articles.filter{ article in
guard article.status.boolStatus(forKey: statusKey) != flag else { return false }
@@ -93,4 +136,5 @@ private extension MarkStatusCommand {
}
}
}

View File

@@ -110,6 +110,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
}
}
private var directlyMarkedAsUnreadArticles = Set<Article>()
var prefersStatusBarHidden = false
private let treeControllerDelegate = WebFeedTreeControllerDelegate()
@@ -330,6 +332,8 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
NotificationCenter.default.addObserver(self, selector: #selector(accountDidDownloadArticles(_:)), name: .AccountDidDownloadArticles, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(importDownloadedTheme(_:)), name: .didEndDownloadingTheme, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(markStatusCommandDidDirectMarking(_:)), name: .MarkStatusCommandDidDirectMarking, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(markStatusCommandDidUndoDirectMarking(_:)), name: .MarkStatusCommandDidUndoDirectMarking, object: nil)
}
func restoreWindowState(_ activity: NSUserActivity?) {
@@ -546,6 +550,28 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
}
}
@objc func markStatusCommandDidDirectMarking(_ note: Notification) {
guard let userInfo = note.userInfo,
let articles = userInfo[Account.UserInfoKey.articles] as? Set<Article>,
let statusKey = userInfo[Account.UserInfoKey.statusKey] as? ArticleStatus.Key,
let flag = userInfo[Account.UserInfoKey.statusFlag] as? Bool else { return }
if statusKey == .read && flag == false {
directlyMarkedAsUnreadArticles.formUnion(articles)
}
}
@objc func markStatusCommandDidUndoDirectMarking(_ note: Notification) {
guard let userInfo = note.userInfo,
let articles = userInfo[Account.UserInfoKey.articles] as? Set<Article>,
let statusKey = userInfo[Account.UserInfoKey.statusKey] as? ArticleStatus.Key,
let flag = userInfo[Account.UserInfoKey.statusFlag] as? Bool else { return }
if statusKey == .read && flag == false {
directlyMarkedAsUnreadArticles.subtract(articles)
}
}
// MARK: API
func suspend() {
@@ -996,7 +1022,9 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
}
func markAllAsRead(_ articles: [Article], completion: (() -> Void)? = nil) {
markArticlesWithUndo(articles, statusKey: .read, flag: true, completion: completion)
var markableArticles = Set(articles)
markableArticles.subtract(directlyMarkedAsUnreadArticles)
markArticlesWithUndo(markableArticles, statusKey: .read, flag: true, directlyMarked: false, completion: completion)
}
func markAllAsReadInTimeline(completion: (() -> Void)? = nil) {
@@ -1044,13 +1072,13 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
func markAsReadForCurrentArticle() {
if let article = currentArticle {
markArticlesWithUndo([article], statusKey: .read, flag: true)
markArticlesWithUndo([article], statusKey: .read, flag: true, directlyMarked: true)
}
}
func markAsUnreadForCurrentArticle() {
if let article = currentArticle {
markArticlesWithUndo([article], statusKey: .read, flag: false)
markArticlesWithUndo([article], statusKey: .read, flag: false, directlyMarked: true)
}
}
@@ -1062,7 +1090,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
func toggleRead(_ article: Article) {
guard !article.status.read || article.isAvailableToMarkUnread else { return }
markArticlesWithUndo([article], statusKey: .read, flag: !article.status.read)
markArticlesWithUndo([article], statusKey: .read, flag: !article.status.read, directlyMarked: true)
}
func toggleStarredForCurrentArticle() {
@@ -1072,7 +1100,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging {
}
func toggleStar(_ article: Article) {
markArticlesWithUndo([article], statusKey: .starred, flag: !article.status.starred)
markArticlesWithUndo([article], statusKey: .starred, flag: !article.status.starred, directlyMarked: true)
}
func timelineFeedIsEqualTo(_ feed: WebFeed) -> Bool {
@@ -1415,9 +1443,18 @@ private extension SceneCoordinator {
navController.toolbar.tintColor = AppAssets.primaryAccentColor
}
func markArticlesWithUndo(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool, completion: (() -> Void)? = nil) {
func markArticlesWithUndo(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool, directlyMarked: Bool, completion: (() -> Void)? = nil) {
markArticlesWithUndo(Set(articles), statusKey: statusKey, flag: flag, directlyMarked: directlyMarked, completion: completion)
}
func markArticlesWithUndo(_ articles: Set<Article>, statusKey: ArticleStatus.Key, flag: Bool, directlyMarked: Bool, completion: (() -> Void)? = nil) {
guard let undoManager = undoManager,
let markReadCommand = MarkStatusCommand(initialArticles: articles, statusKey: statusKey, flag: flag, undoManager: undoManager, completion: completion) else {
let markReadCommand = MarkStatusCommand(initialArticles: articles,
statusKey: statusKey,
flag: flag,
directlyMarked: directlyMarked,
undoManager: undoManager,
completion: completion) else {
completion?()
return
}
@@ -1935,6 +1972,7 @@ private extension SceneCoordinator {
func emptyTheTimeline() {
if !articles.isEmpty {
directlyMarkedAsUnreadArticles = Set<Article>()
replaceArticles(with: Set<Article>(), animated: false)
}
}