Implement the Mark All as Read button
This commit is contained in:
parent
40e0a1b676
commit
e391b29353
@ -35,6 +35,7 @@ final class SceneModel: ObservableObject {
|
|||||||
private(set) var sidebarModel = SidebarModel()
|
private(set) var sidebarModel = SidebarModel()
|
||||||
private(set) var timelineModel = TimelineModel()
|
private(set) var timelineModel = TimelineModel()
|
||||||
|
|
||||||
|
private var articlesCancellable: AnyCancellable?
|
||||||
private var selectedArticlesCancellable: AnyCancellable?
|
private var selectedArticlesCancellable: AnyCancellable?
|
||||||
|
|
||||||
// MARK: Initialization API
|
// MARK: Initialization API
|
||||||
@ -50,13 +51,22 @@ final class SceneModel: ObservableObject {
|
|||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
|
||||||
|
|
||||||
|
articlesCancellable = timelineModel.$articles.sink { [weak self] articles in
|
||||||
|
self?.updateMarkAllAsReadButtonsState(articles: articles)
|
||||||
|
}
|
||||||
|
|
||||||
selectedArticlesCancellable = timelineModel.$selectedArticles.sink { [weak self] articles in
|
selectedArticlesCancellable = timelineModel.$selectedArticles.sink { [weak self] articles in
|
||||||
self?.updateArticleButtonsState(articles: articles)
|
self?.updateArticleButtonsState(selectedArticles: articles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Article Management API
|
// MARK: Article Management API
|
||||||
|
|
||||||
|
/// Marks all the articles in the Timeline as read
|
||||||
|
func markAllAsRead() {
|
||||||
|
timelineModel.markAllAsRead()
|
||||||
|
}
|
||||||
|
|
||||||
/// Toggles the read status for the selected articles
|
/// Toggles the read status for the selected articles
|
||||||
func toggleReadStatusForSelectedArticles() {
|
func toggleReadStatusForSelectedArticles() {
|
||||||
timelineModel.toggleReadStatusForSelectedArticles()
|
timelineModel.toggleReadStatusForSelectedArticles()
|
||||||
@ -123,16 +133,25 @@ private extension SceneModel {
|
|||||||
guard let articleIDs = note.userInfo?[Account.UserInfoKey.articleIDs] as? Set<String> else {
|
guard let articleIDs = note.userInfo?[Account.UserInfoKey.articleIDs] as? Set<String> else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
updateMarkAllAsReadButtonsState(articles: timelineModel.articles)
|
||||||
let selectedArticleIDs = timelineModel.selectedArticles.map { $0.articleID }
|
let selectedArticleIDs = timelineModel.selectedArticles.map { $0.articleID }
|
||||||
if !articleIDs.intersection(selectedArticleIDs).isEmpty {
|
if !articleIDs.intersection(selectedArticleIDs).isEmpty {
|
||||||
updateArticleButtonsState(articles: timelineModel.selectedArticles)
|
updateArticleButtonsState(selectedArticles: timelineModel.selectedArticles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Button State Updates
|
// MARK: Button State Updates
|
||||||
|
|
||||||
func updateArticleButtonsState(articles: [Article]) {
|
func updateMarkAllAsReadButtonsState(articles: [Article]) {
|
||||||
guard !articles.isEmpty else {
|
if articles.canMarkAllAsRead() {
|
||||||
|
markAllAsReadButtonState = false
|
||||||
|
} else {
|
||||||
|
markAllAsReadButtonState = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateArticleButtonsState(selectedArticles: [Article]) {
|
||||||
|
guard !selectedArticles.isEmpty else {
|
||||||
readButtonState = nil
|
readButtonState = nil
|
||||||
starButtonState = nil
|
starButtonState = nil
|
||||||
openInBrowserButtonState = nil
|
openInBrowserButtonState = nil
|
||||||
@ -140,21 +159,21 @@ private extension SceneModel {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if articles.anyArticleIsUnread() {
|
if selectedArticles.anyArticleIsUnread() {
|
||||||
readButtonState = true
|
readButtonState = true
|
||||||
} else if articles.anyArticleIsReadAndCanMarkUnread() {
|
} else if selectedArticles.anyArticleIsReadAndCanMarkUnread() {
|
||||||
readButtonState = false
|
readButtonState = false
|
||||||
} else {
|
} else {
|
||||||
readButtonState = nil
|
readButtonState = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if articles.anyArticleIsUnstarred() {
|
if selectedArticles.anyArticleIsUnstarred() {
|
||||||
starButtonState = false
|
starButtonState = false
|
||||||
} else {
|
} else {
|
||||||
starButtonState = true
|
starButtonState = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if articles.count == 1, articles.first?.preferredLink != nil {
|
if selectedArticles.count == 1, selectedArticles.first?.preferredLink != nil {
|
||||||
openInBrowserButtonState = true
|
openInBrowserButtonState = true
|
||||||
shareButtonState = true
|
shareButtonState = true
|
||||||
} else {
|
} else {
|
||||||
|
@ -92,6 +92,7 @@ struct SceneNavigationView: View {
|
|||||||
}
|
}
|
||||||
ToolbarItem {
|
ToolbarItem {
|
||||||
Button {
|
Button {
|
||||||
|
sceneModel.markAllAsRead()
|
||||||
} label: {
|
} label: {
|
||||||
AppAssets.markAllAsReadImagePDF
|
AppAssets.markAllAsReadImagePDF
|
||||||
.resizable()
|
.resizable()
|
||||||
|
@ -33,6 +33,12 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
|||||||
@Published var readFilterEnabledTable = [FeedIdentifier: Bool]()
|
@Published var readFilterEnabledTable = [FeedIdentifier: Bool]()
|
||||||
@Published var isReadFiltered: Bool? = nil
|
@Published var isReadFiltered: Bool? = nil
|
||||||
|
|
||||||
|
@Published var articles = [Article]() {
|
||||||
|
didSet {
|
||||||
|
articleDictionaryNeedsUpdate = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var undoManager: UndoManager?
|
var undoManager: UndoManager?
|
||||||
var undoableCommands = [UndoableCommand]()
|
var undoableCommands = [UndoableCommand]()
|
||||||
|
|
||||||
@ -45,13 +51,7 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
|||||||
private var fetchSerialNumber = 0
|
private var fetchSerialNumber = 0
|
||||||
private let fetchRequestQueue = FetchRequestQueue()
|
private let fetchRequestQueue = FetchRequestQueue()
|
||||||
private var exceptionArticleFetcher: ArticleFetcher?
|
private var exceptionArticleFetcher: ArticleFetcher?
|
||||||
|
|
||||||
private var articles = [Article]() {
|
|
||||||
didSet {
|
|
||||||
articleDictionaryNeedsUpdate = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var articleDictionaryNeedsUpdate = true
|
private var articleDictionaryNeedsUpdate = true
|
||||||
private var _idToArticleDictionary = [String: Article]()
|
private var _idToArticleDictionary = [String: Article]()
|
||||||
private var idToArticleDictionary: [String: Article] {
|
private var idToArticleDictionary: [String: Article] {
|
||||||
@ -198,6 +198,14 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
|||||||
markArticlesWithUndo(articlesToMark, statusKey: .read, flag: true)
|
markArticlesWithUndo(articlesToMark, statusKey: .read, flag: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func canMarkAllAsRead() -> Bool {
|
||||||
|
return articles.canMarkAllAsRead()
|
||||||
|
}
|
||||||
|
|
||||||
|
func markAllAsRead() {
|
||||||
|
markArticlesWithUndo(articles, statusKey: .read, flag: true)
|
||||||
|
}
|
||||||
|
|
||||||
func toggleStarredStatusForSelectedArticles() {
|
func toggleStarredStatusForSelectedArticles() {
|
||||||
guard !selectedArticles.isEmpty else {
|
guard !selectedArticles.isEmpty else {
|
||||||
return
|
return
|
||||||
|
@ -10,6 +10,7 @@ import SwiftUI
|
|||||||
|
|
||||||
struct TimelineToolbarModifier: ViewModifier {
|
struct TimelineToolbarModifier: ViewModifier {
|
||||||
|
|
||||||
|
@EnvironmentObject private var sceneModel: SceneModel
|
||||||
@EnvironmentObject private var timelineModel: TimelineModel
|
@EnvironmentObject private var timelineModel: TimelineModel
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
@ -34,9 +35,11 @@ struct TimelineToolbarModifier: ViewModifier {
|
|||||||
|
|
||||||
ToolbarItem {
|
ToolbarItem {
|
||||||
Button {
|
Button {
|
||||||
|
sceneModel.markAllAsRead()
|
||||||
} label: {
|
} label: {
|
||||||
AppAssets.markAllAsReadImage
|
AppAssets.markAllAsReadImage
|
||||||
}
|
}
|
||||||
|
.disabled(sceneModel.markAllAsReadButtonState == nil)
|
||||||
.help("Mark All As Read")
|
.help("Mark All As Read")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user