NetNewsWire/Multiplatform/Shared/SceneModel.swift

126 lines
3.1 KiB
Swift
Raw Normal View History

2020-06-28 21:21:43 +02:00
//
// SceneModel.swift
// NetNewsWire
//
// Created by Maurice Parker on 6/28/20.
// Copyright © 2020 Ranchero Software. All rights reserved.
//
import Foundation
import Account
import Articles
import RSCore
2020-06-28 21:21:43 +02:00
final class SceneModel: ObservableObject {
@Published var refreshProgressState = RefreshProgressModel.State.none
@Published var readButtonState: ArticleReadButtonState?
@Published var starButtonState: ArticleStarButtonState?
private var refreshProgressModel: RefreshProgressModel? = nil
private var articleIconSchemeHandler: ArticleIconSchemeHandler? = nil
2020-07-12 01:22:47 +02:00
private(set) var webViewProvider: WebViewProvider? = nil
private(set) var sidebarModel = SidebarModel()
private(set) var timelineModel = TimelineModel()
// MARK: Initialization API
/// Prepares the SceneModel to be used in the views
func startup() {
2020-07-12 01:22:47 +02:00
sidebarModel.delegate = self
timelineModel.delegate = self
self.refreshProgressModel = RefreshProgressModel()
self.refreshProgressModel!.$state.assign(to: self.$refreshProgressState)
2020-07-08 17:20:04 +02:00
self.articleIconSchemeHandler = ArticleIconSchemeHandler(sceneModel: self)
self.webViewProvider = WebViewProvider(articleIconSchemeHandler: self.articleIconSchemeHandler!)
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
}
// MARK: Article Management API
/// Retrieves the article before the given article in the Timeline
func findPrevArticle(_ article: Article) -> Article? {
2020-07-12 01:22:47 +02:00
return timelineModel.findPrevArticle(article)
}
/// Retrieves the article after the given article in the Timeline
func findNextArticle(_ article: Article) -> Article? {
2020-07-12 01:22:47 +02:00
return timelineModel.findNextArticle(article)
}
/// Returns the article with the given articleID
func articleFor(_ articleID: String) -> Article? {
2020-07-12 01:22:47 +02:00
return timelineModel.articleFor(articleID)
}
2020-06-28 21:21:43 +02:00
}
// MARK: SidebarModelDelegate
extension SceneModel: SidebarModelDelegate {
2020-06-29 13:16:48 +02:00
func unreadCount(for feed: Feed) -> Int {
// TODO: Get the count from the timeline if Feed is the current timeline
return feed.unreadCount
}
}
2020-06-30 18:03:33 +02:00
// MARK: TimelineModelDelegate
extension SceneModel: TimelineModelDelegate {
func timelineRequestedWebFeedSelection(_: TimelineModel, webFeed: WebFeed) {
}
}
2020-07-02 22:30:50 +02:00
// MARK: Private
2020-07-02 22:30:50 +02:00
private extension SceneModel {
2020-07-02 22:30:50 +02:00
// MARK: Notifications
@objc func statusesDidChange(_ note: Notification) {
2020-07-12 01:22:47 +02:00
guard let articleIDs = note.userInfo?[Account.UserInfoKey.articleIDs] as? Set<String> else {
return
}
2020-07-12 01:22:47 +02:00
let selectedArticleIDs = timelineModel.selectedArticles.map { $0.articleID }
if !articleIDs.intersection(selectedArticleIDs).isEmpty {
updateArticleState()
}
}
2020-07-12 01:22:47 +02:00
// MARK: Button State Updates
func updateArticleState() {
2020-07-12 01:22:47 +02:00
let articles = timelineModel.selectedArticles
guard !articles.isEmpty else {
readButtonState = nil
starButtonState = nil
return
}
2020-07-12 01:22:47 +02:00
if articles.anyArticleIsUnread() {
readButtonState = .on
} else if articles.anyArticleIsReadAndCanMarkUnread() {
readButtonState = .off
} else {
readButtonState = nil
}
2020-07-12 01:22:47 +02:00
if articles.anyArticleIsUnstarred() {
starButtonState = .on
} else {
starButtonState = .off
}
}
2020-07-02 22:30:50 +02:00
}