Enabled toolbar buttons for read and star
This commit is contained in:
parent
92ac91d9d5
commit
7998b5450b
Multiplatform/Shared
@ -33,7 +33,7 @@ struct ArticleToolbarModifier: ViewModifier {
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .bottomBar) {
|
||||
Button(action: { }, label: {
|
||||
Button(action: { sceneModel.toggleReadStatusForSelectedArticles() }, label: {
|
||||
if sceneModel.readButtonState == .on {
|
||||
AppAssets.readClosedImage
|
||||
} else {
|
||||
@ -49,7 +49,7 @@ struct ArticleToolbarModifier: ViewModifier {
|
||||
}
|
||||
|
||||
ToolbarItem(placement: .bottomBar) {
|
||||
Button(action: { }, label: {
|
||||
Button(action: { sceneModel.toggleStarredStatusForSelectedArticles() }, label: {
|
||||
if sceneModel.starButtonState == .on {
|
||||
AppAssets.starClosedImage
|
||||
} else {
|
||||
|
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Account
|
||||
import Articles
|
||||
import RSCore
|
||||
@ -25,6 +26,8 @@ final class SceneModel: ObservableObject {
|
||||
private(set) var sidebarModel = SidebarModel()
|
||||
private(set) var timelineModel = TimelineModel()
|
||||
|
||||
private var selectedArticlesCancellable: AnyCancellable?
|
||||
|
||||
// MARK: Initialization API
|
||||
|
||||
/// Prepares the SceneModel to be used in the views
|
||||
@ -39,10 +42,22 @@ final class SceneModel: ObservableObject {
|
||||
self.webViewProvider = WebViewProvider(articleIconSchemeHandler: self.articleIconSchemeHandler!)
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
|
||||
|
||||
selectedArticlesCancellable = timelineModel.$selectedArticles.sink { [weak self] articles in
|
||||
self?.updateArticleState(articles: articles)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Article Management API
|
||||
|
||||
func toggleReadStatusForSelectedArticles() {
|
||||
timelineModel.toggleReadStatusForSelectedArticles()
|
||||
}
|
||||
|
||||
func toggleStarredStatusForSelectedArticles() {
|
||||
timelineModel.toggleStarredStatusForSelectedArticles()
|
||||
}
|
||||
|
||||
/// Retrieves the article before the given article in the Timeline
|
||||
func findPrevArticle(_ article: Article) -> Article? {
|
||||
return timelineModel.findPrevArticle(article)
|
||||
@ -92,15 +107,13 @@ private extension SceneModel {
|
||||
}
|
||||
let selectedArticleIDs = timelineModel.selectedArticles.map { $0.articleID }
|
||||
if !articleIDs.intersection(selectedArticleIDs).isEmpty {
|
||||
updateArticleState()
|
||||
updateArticleState(articles: timelineModel.selectedArticles)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Button State Updates
|
||||
|
||||
func updateArticleState() {
|
||||
let articles = timelineModel.selectedArticles
|
||||
|
||||
func updateArticleState(articles: [Article]) {
|
||||
guard !articles.isEmpty else {
|
||||
readButtonState = nil
|
||||
starButtonState = nil
|
||||
@ -116,9 +129,9 @@ private extension SceneModel {
|
||||
}
|
||||
|
||||
if articles.anyArticleIsUnstarred() {
|
||||
starButtonState = .on
|
||||
} else {
|
||||
starButtonState = .off
|
||||
} else {
|
||||
starButtonState = .on
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ struct SceneNavigationView: View {
|
||||
}).help("Go to Next Unread").padding(.trailing, 40)
|
||||
}
|
||||
ToolbarItem {
|
||||
Button(action: { }, label: {
|
||||
Button(action: { sceneModel.toggleReadStatusForSelectedArticles() }, label: {
|
||||
if sceneModel.readButtonState == .on {
|
||||
AppAssets.readClosedImage
|
||||
} else {
|
||||
@ -109,7 +109,7 @@ struct SceneNavigationView: View {
|
||||
.help(sceneModel.readButtonState == .on ? "Mark as Unread" : "Mark as Read")
|
||||
}
|
||||
ToolbarItem {
|
||||
Button(action: { }, label: {
|
||||
Button(action: { sceneModel.toggleStarredStatusForSelectedArticles() }, label: {
|
||||
if sceneModel.starButtonState == .on {
|
||||
AppAssets.starClosedImage
|
||||
} else {
|
||||
|
@ -31,6 +31,7 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||
|
||||
private var selectedArticleIDsCancellable: AnyCancellable?
|
||||
private var selectedArticleIDCancellable: AnyCancellable?
|
||||
private var selectedArticlesCancellable: AnyCancellable?
|
||||
|
||||
private var fetchSerialNumber = 0
|
||||
private let fetchRequestQueue = FetchRequestQueue()
|
||||
@ -84,6 +85,16 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||
self.selectedArticles = [article]
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This should be rewritten to use Combine correctly
|
||||
selectedArticlesCancellable = $selectedArticles.sink { articles in
|
||||
if articles.count == 1 {
|
||||
let article = articles.first!
|
||||
if !article.status.read {
|
||||
markArticles(Set([article]), statusKey: .read, flag: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: API
|
||||
@ -97,6 +108,56 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
|
||||
fetchAndReplaceArticlesAsync(feeds: feeds)
|
||||
}
|
||||
|
||||
func toggleReadStatusForSelectedArticles() {
|
||||
guard !selectedArticles.isEmpty else {
|
||||
return
|
||||
}
|
||||
if selectedArticles.anyArticleIsUnread() {
|
||||
markSelectedArticlesAsRead()
|
||||
} else {
|
||||
markSelectedArticlesAsUnread()
|
||||
}
|
||||
}
|
||||
|
||||
func markSelectedArticlesAsRead() {
|
||||
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: selectedArticles, markingRead: true, undoManager: undoManager) else {
|
||||
return
|
||||
}
|
||||
runCommand(markReadCommand)
|
||||
}
|
||||
|
||||
func markSelectedArticlesAsUnread() {
|
||||
guard let undoManager = undoManager, let markUnreadCommand = MarkStatusCommand(initialArticles: selectedArticles, markingRead: false, undoManager: undoManager) else {
|
||||
return
|
||||
}
|
||||
runCommand(markUnreadCommand)
|
||||
}
|
||||
|
||||
func toggleStarredStatusForSelectedArticles() {
|
||||
guard !selectedArticles.isEmpty else {
|
||||
return
|
||||
}
|
||||
if selectedArticles.anyArticleIsUnstarred() {
|
||||
markSelectedArticlesAsStarred()
|
||||
} else {
|
||||
markSelectedArticlesAsUnstarred()
|
||||
}
|
||||
}
|
||||
|
||||
func markSelectedArticlesAsStarred() {
|
||||
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: selectedArticles, markingStarred: true, undoManager: undoManager) else {
|
||||
return
|
||||
}
|
||||
runCommand(markReadCommand)
|
||||
}
|
||||
|
||||
func markSelectedArticlesAsUnstarred() {
|
||||
guard let undoManager = undoManager, let markUnreadCommand = MarkStatusCommand(initialArticles: selectedArticles, markingStarred: false, undoManager: undoManager) else {
|
||||
return
|
||||
}
|
||||
runCommand(markUnreadCommand)
|
||||
}
|
||||
|
||||
func articleFor(_ articleID: String) -> Article? {
|
||||
return idToArticleDictionary[articleID]
|
||||
}
|
||||
@ -138,7 +199,7 @@ private extension TimelineModel {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK:
|
||||
// MARK: Timeline Management
|
||||
|
||||
func sortParametersDidChange() {
|
||||
performBlockAndRestoreSelection {
|
||||
@ -202,6 +263,4 @@ private extension TimelineModel {
|
||||
// TODO: Update unread counts and other item done in didSet on AppKit
|
||||
}
|
||||
|
||||
// MARK: - Notifications
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user