move LinkItemDetailViewModel into binders package

This commit is contained in:
Satindar Dhillon 2022-02-23 16:24:21 -08:00
parent 2bbe0e22d1
commit 5e4502719e
7 changed files with 110 additions and 104 deletions

View file

@ -1,86 +0,0 @@
import Models
import Services
import SwiftUI
import Utils
import Views
extension LinkItemDetailViewModel {
static func make(feedItem: FeedItem, services: Services) -> LinkItemDetailViewModel {
let viewModel = LinkItemDetailViewModel(item: feedItem)
viewModel.bind(services: services)
return viewModel
}
func bind(services: Services) {
performActionSubject.sink { [weak self] action in
switch action {
case .load:
self?.loadWebAppWrapper(services: services)
case let .updateReadStatus(markAsRead: markAsRead):
self?.updateItemReadStatus(markAsRead: markAsRead, dataService: services.dataService)
}
}
.store(in: &subscriptions)
}
private func updateItemReadStatus(markAsRead: Bool, dataService: DataService) {
dataService
.updateArticleReadingProgressPublisher(
itemID: item.id,
readingProgress: markAsRead ? 100 : 0,
anchorIndex: 0
)
.sink { completion in
guard case let .failure(error) = completion else { return }
print(error)
} receiveValue: { [weak self] feedItem in
self?.item.readingProgress = feedItem.readingProgress
}
.store(in: &subscriptions)
}
private func loadWebAppWrapper(services: Services) {
// Attempt to get `Viewer` from DataService
if let currentViewer = services.dataService.currentViewer {
createWebAppWrapperViewModel(username: currentViewer.username, services: services)
return
}
services.dataService.viewerPublisher().sink(
receiveCompletion: { completion in
guard case let .failure(error) = completion else { return }
print(error)
},
receiveValue: { [weak self] viewer in
self?.createWebAppWrapperViewModel(username: viewer.username, services: services)
}
)
.store(in: &subscriptions)
}
private func createWebAppWrapperViewModel(username: String, services: Services) {
let baseURL = services.dataService.appEnvironment.webAppBaseURL
let urlRequest = URLRequest.webRequest(
baseURL: services.dataService.appEnvironment.webAppBaseURL,
urlPath: "/app/\(username)/\(item.slug)",
queryParams: ["isAppEmbedView": "true", "highlightBarDisabled": isMacApp ? "false" : "true"]
)
let newWebAppWrapperViewModel = WebAppWrapperViewModel(
webViewURLRequest: urlRequest,
baseURL: baseURL,
rawAuthCookie: services.authenticator.omnivoreAuthCookieString
)
newWebAppWrapperViewModel.performActionSubject.sink { action in
switch action {
case let .shareHighlight(highlightID):
print("show share modal for highlight with id: \(highlightID)")
}
}
.store(in: &newWebAppWrapperViewModel.subscriptions)
webAppWrapperViewModel = newWebAppWrapperViewModel
}
}

View file

@ -1,30 +1,114 @@
import Combine
import Models
import Services
import SwiftUI
import Utils
import Views
public enum PDFProvider {
public static var pdfViewerProvider: ((URL, FeedItem) -> AnyView)?
// TODO: remove this view model
extension LinkItemDetailViewModel {
static func make(feedItem: FeedItem, services: Services) -> LinkItemDetailViewModel {
let viewModel = LinkItemDetailViewModel(item: feedItem)
viewModel.bind(services: services)
return viewModel
}
func bind(services: Services) {
performActionSubject.sink { [weak self] action in
switch action {
case .load:
self?.loadWebAppWrapper(services: services)
case let .updateReadStatus(markAsRead: markAsRead):
self?.updateItemReadStatus(markAsRead: markAsRead, dataService: services.dataService)
}
}
.store(in: &subscriptions)
}
private func updateItemReadStatus(markAsRead: Bool, dataService: DataService) {
dataService
.updateArticleReadingProgressPublisher(
itemID: item.id,
readingProgress: markAsRead ? 100 : 0,
anchorIndex: 0
)
.sink { completion in
guard case let .failure(error) = completion else { return }
print(error)
} receiveValue: { [weak self] feedItem in
self?.item.readingProgress = feedItem.readingProgress
}
.store(in: &subscriptions)
}
private func loadWebAppWrapper(services: Services) {
// Attempt to get `Viewer` from DataService
if let currentViewer = services.dataService.currentViewer {
createWebAppWrapperViewModel(username: currentViewer.username, services: services)
return
}
services.dataService.viewerPublisher().sink(
receiveCompletion: { completion in
guard case let .failure(error) = completion else { return }
print(error)
},
receiveValue: { [weak self] viewer in
self?.createWebAppWrapperViewModel(username: viewer.username, services: services)
}
)
.store(in: &subscriptions)
}
private func createWebAppWrapperViewModel(username: String, services: Services) {
let baseURL = services.dataService.appEnvironment.webAppBaseURL
let urlRequest = URLRequest.webRequest(
baseURL: services.dataService.appEnvironment.webAppBaseURL,
urlPath: "/app/\(username)/\(item.slug)",
queryParams: ["isAppEmbedView": "true", "highlightBarDisabled": isMacApp ? "false" : "true"]
)
let newWebAppWrapperViewModel = WebAppWrapperViewModel(
webViewURLRequest: urlRequest,
baseURL: baseURL,
rawAuthCookie: services.authenticator.omnivoreAuthCookieString
)
newWebAppWrapperViewModel.performActionSubject.sink { action in
switch action {
case let .shareHighlight(highlightID):
print("show share modal for highlight with id: \(highlightID)")
}
}
.store(in: &newWebAppWrapperViewModel.subscriptions)
webAppWrapperViewModel = newWebAppWrapperViewModel
}
}
public final class LinkItemDetailViewModel: ObservableObject {
@Published public var item: FeedItem
@Published public var webAppWrapperViewModel: WebAppWrapperViewModel?
enum PDFProvider {
static var pdfViewerProvider: ((URL, FeedItem) -> AnyView)?
}
public enum Action {
final class LinkItemDetailViewModel: ObservableObject {
@Published var item: FeedItem
@Published var webAppWrapperViewModel: WebAppWrapperViewModel?
enum Action {
case load
case updateReadStatus(markAsRead: Bool)
}
public var subscriptions = Set<AnyCancellable>()
public let performActionSubject = PassthroughSubject<Action, Never>()
var subscriptions = Set<AnyCancellable>()
let performActionSubject = PassthroughSubject<Action, Never>()
public init(item: FeedItem) {
init(item: FeedItem) {
self.item = item
}
}
public struct LinkItemDetailView: View {
struct LinkItemDetailView: View {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
static let navBarHeight = 50.0
@ -32,7 +116,7 @@ public struct LinkItemDetailView: View {
@State private var showFontSizePopover = false
@State private var navBarVisibilityRatio = 1.0
public init(viewModel: LinkItemDetailViewModel) {
init(viewModel: LinkItemDetailViewModel) {
self.viewModel = viewModel
}
@ -61,7 +145,7 @@ public struct LinkItemDetailView: View {
)
}
public var body: some View {
var body: some View {
#if os(iOS)
if UIDevice.isIPhone, !viewModel.item.isPDF {
compactInnerBody

View file

@ -34,8 +34,8 @@ import WebKit
webView.backgroundColor = UIColor.clear
webView.configuration.userContentController = contentController
webView.scrollView.delegate = context.coordinator
webView.scrollView.contentInset.top = LinkItemDetailView.navBarHeight
webView.scrollView.verticalScrollIndicatorInsets.top = LinkItemDetailView.navBarHeight
webView.scrollView.contentInset.top = 50.0 // TODO: LinkItemDetailView.navBarHeight
webView.scrollView.verticalScrollIndicatorInsets.top = 50.0 // TODO: LinkItemDetailView.navBarHeight
for action in WebViewAction.allCases {
webView.configuration.userContentController.add(context.coordinator, name: action.rawValue)

View file

@ -2,7 +2,7 @@ import SwiftUI
import WebKit
final class WebAppViewCoordinator: NSObject {
let navBarHeight = LinkItemDetailView.navBarHeight
let navBarHeight = 50.0 // TODO: LinkItemDetailView.navBarHeight
var webViewActionHandler: (WKScriptMessage) -> Void = { _ in }
var linkHandler: (URL) -> Void = { _ in }
var needsReload = true

View file

@ -14,8 +14,8 @@ public final class WebAppWrapperViewModel: ObservableObject {
let baseURL: URL
let rawAuthCookie: String?
@Published var sendIncreaseFontSignal: Bool = false
@Published var sendDecreaseFontSignal: Bool = false
@Published public var sendIncreaseFontSignal: Bool = false
@Published public var sendDecreaseFontSignal: Bool = false
public init(webViewURLRequest: URLRequest, baseURL: URL, rawAuthCookie: String?) {
self.webViewURLRequest = webViewURLRequest

View file

@ -5,6 +5,14 @@ public struct FontSizeAdjustmentPopoverView: View {
let increaseFontAction: () -> Void
let decreaseFontAction: () -> Void
public init(
increaseFontAction: @escaping () -> Void,
decreaseFontAction: @escaping () -> Void
) {
self.increaseFontAction = increaseFontAction
self.decreaseFontAction = decreaseFontAction
}
static let preferredWebFontSizeKey = UserDefaultKey.preferredWebFontSize.rawValue
#if os(macOS)
@AppStorage(preferredWebFontSizeKey) var storedFontSize = Int(NSFont.userFont(ofSize: 16)?.pointSize ?? 16)

View file

@ -1,7 +1,7 @@
import SwiftUI
#if os(iOS)
extension View {
public extension View {
func fittedPopover<Content>(
isPresented: Binding<Bool>,
onDismiss: (() -> Void)? = nil,