diff --git a/Multiplatform/Shared/Timeline/TimelineContextMenu.swift b/Multiplatform/Shared/Timeline/TimelineContextMenu.swift index 98d5949ea..b32ae9309 100644 --- a/Multiplatform/Shared/Timeline/TimelineContextMenu.swift +++ b/Multiplatform/Shared/Timeline/TimelineContextMenu.swift @@ -81,6 +81,18 @@ struct TimelineContextMenu: View { } } + if let feed = timelineItem.article.webFeed, timelineModel.canMarkAllAsReadInFeed(feed) { + Divider() + Button { + timelineModel.markAllAsReadInFeed(feed) + } label: { + Text("Mark All as Read in “\(feed.nameForDisplay)”") + #if os(iOS) + AppAssets.markAllAsReadImage + #endif + } + } + if timelineModel.canOpenIndicatedArticleInBrowser(timelineItem.article) { Divider() Button { diff --git a/Multiplatform/Shared/Timeline/TimelineModel.swift b/Multiplatform/Shared/Timeline/TimelineModel.swift index 44f68d9de..855e14e9f 100644 --- a/Multiplatform/Shared/Timeline/TimelineModel.swift +++ b/Multiplatform/Shared/Timeline/TimelineModel.swift @@ -189,6 +189,19 @@ class TimelineModel: ObservableObject, UndoableCommandRunner { markArticlesWithUndo(articlesToMark, statusKey: .read, flag: true) } + func canMarkAllAsReadInFeed(_ feed: Feed) -> Bool { + guard let articlesSet = try? feed.fetchArticles() else { + return false + } + return Array(articlesSet).canMarkAllAsRead() + } + + func markAllAsReadInFeed(_ feed: Feed) { + guard let articlesSet = try? feed.fetchArticles() else { return } + let articlesToMark = Array(articlesSet) + markArticlesWithUndo(articlesToMark, statusKey: .read, flag: true) + } + func toggleStarredStatusForSelectedArticles() { guard !selectedArticles.isEmpty else { return