remove link item creator and create view directly instead
This commit is contained in:
@ -8,9 +8,7 @@ import Views
|
||||
|
||||
extension HomeFeedViewModel {
|
||||
static func make(services: Services) -> HomeFeedViewModel {
|
||||
let viewModel = HomeFeedViewModel { feedItem in
|
||||
LinkItemDetailViewModel.make(feedItem: feedItem, services: services)
|
||||
}
|
||||
let viewModel = HomeFeedViewModel()
|
||||
|
||||
#if os(iOS)
|
||||
if UIDevice.isIPhone {
|
||||
@ -201,7 +199,6 @@ private func stopNetworkActivityIndicator() {
|
||||
|
||||
// TODO: remove this view model
|
||||
final class HomeFeedViewModel: ObservableObject {
|
||||
let detailViewModelCreator: (FeedItem) -> LinkItemDetailViewModel
|
||||
var currentDetailViewModel: LinkItemDetailViewModel?
|
||||
var profileContainerViewModel: ProfileContainerViewModel?
|
||||
|
||||
@ -227,9 +224,7 @@ final class HomeFeedViewModel: ObservableObject {
|
||||
var subscriptions = Set<AnyCancellable>()
|
||||
let performActionSubject = PassthroughSubject<Action, Never>()
|
||||
|
||||
init(detailViewModelCreator: @escaping (FeedItem) -> LinkItemDetailViewModel) {
|
||||
self.detailViewModelCreator = detailViewModelCreator
|
||||
}
|
||||
init() {}
|
||||
|
||||
func itemAppeared(item: FeedItem, searchQuery: String) {
|
||||
if isLoading { return }
|
||||
@ -248,6 +243,9 @@ final class HomeFeedViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
struct HomeFeedView: View {
|
||||
// @EnvironmentObject var authenticator: Authenticator
|
||||
// @EnvironmentObject var dataService: DataService
|
||||
|
||||
@ObservedObject private var viewModel: HomeFeedViewModel
|
||||
@State private var selectedLinkItem: FeedItem?
|
||||
@State private var searchQuery = ""
|
||||
@ -314,7 +312,7 @@ struct HomeFeedView: View {
|
||||
ForEach(viewModel.items) { item in
|
||||
let link = ZStack {
|
||||
NavigationLink(
|
||||
destination: LinkItemDetailView(viewModel: viewModel.detailViewModelCreator(item)),
|
||||
destination: LinkItemDetailView(viewModel: LinkItemDetailViewModel(item: item)),
|
||||
tag: item,
|
||||
selection: $selectedLinkItem
|
||||
) {
|
||||
|
||||
@ -5,88 +5,6 @@ import SwiftUI
|
||||
import Utils
|
||||
import Views
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
enum PDFProvider {
|
||||
static var pdfViewerProvider: ((URL, FeedItem) -> AnyView)?
|
||||
}
|
||||
@ -101,14 +19,84 @@ final class LinkItemDetailViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
var subscriptions = Set<AnyCancellable>()
|
||||
let performActionSubject = PassthroughSubject<Action, Never>()
|
||||
|
||||
init(item: FeedItem) {
|
||||
self.item = item
|
||||
}
|
||||
|
||||
func updateItemReadStatus(dataService: DataService) {
|
||||
dataService
|
||||
.updateArticleReadingProgressPublisher(
|
||||
itemID: item.id,
|
||||
readingProgress: item.isRead ? 0 : 100,
|
||||
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)
|
||||
}
|
||||
|
||||
func loadWebAppWrapper(dataService: DataService, rawAuthCookie: String?) {
|
||||
// Attempt to get `Viewer` from DataService
|
||||
if let currentViewer = dataService.currentViewer {
|
||||
createWebAppWrapperViewModel(
|
||||
username: currentViewer.username,
|
||||
dataService: dataService,
|
||||
rawAuthCookie: rawAuthCookie
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
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,
|
||||
dataService: dataService,
|
||||
rawAuthCookie: rawAuthCookie
|
||||
)
|
||||
}
|
||||
)
|
||||
.store(in: &subscriptions)
|
||||
}
|
||||
|
||||
private func createWebAppWrapperViewModel(username: String, dataService: DataService, rawAuthCookie: String?) {
|
||||
let baseURL = dataService.appEnvironment.webAppBaseURL
|
||||
|
||||
let urlRequest = URLRequest.webRequest(
|
||||
baseURL: dataService.appEnvironment.webAppBaseURL,
|
||||
urlPath: "/app/\(username)/\(item.slug)",
|
||||
queryParams: ["isAppEmbedView": "true", "highlightBarDisabled": isMacApp ? "false" : "true"]
|
||||
)
|
||||
|
||||
let newWebAppWrapperViewModel = WebAppWrapperViewModel(
|
||||
webViewURLRequest: urlRequest,
|
||||
baseURL: baseURL,
|
||||
rawAuthCookie: rawAuthCookie
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
struct LinkItemDetailView: View {
|
||||
@EnvironmentObject var authenticator: Authenticator
|
||||
@EnvironmentObject var dataService: DataService
|
||||
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
|
||||
|
||||
static let navBarHeight = 50.0
|
||||
@ -122,7 +110,9 @@ struct LinkItemDetailView: View {
|
||||
|
||||
var toggleReadStatusToolbarItem: some View {
|
||||
Button(
|
||||
action: { viewModel.performActionSubject.send(.updateReadStatus(markAsRead: !viewModel.item.isRead)) },
|
||||
action: {
|
||||
viewModel.updateItemReadStatus(dataService: dataService)
|
||||
},
|
||||
label: {
|
||||
Image(systemName: viewModel.item.isRead ? "line.horizontal.3.decrease.circle" : "checkmark.circle")
|
||||
}
|
||||
@ -232,7 +222,10 @@ struct LinkItemDetailView: View {
|
||||
Spacer()
|
||||
}
|
||||
.onAppear {
|
||||
viewModel.performActionSubject.send(.load)
|
||||
viewModel.loadWebAppWrapper(
|
||||
dataService: dataService,
|
||||
rawAuthCookie: authenticator.omnivoreAuthCookieString
|
||||
)
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
}
|
||||
@ -275,7 +268,10 @@ struct LinkItemDetailView: View {
|
||||
Spacer()
|
||||
}
|
||||
.onAppear {
|
||||
viewModel.performActionSubject.send(.load)
|
||||
viewModel.loadWebAppWrapper(
|
||||
dataService: dataService,
|
||||
rawAuthCookie: authenticator.omnivoreAuthCookieString
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,21 +57,21 @@ extension WebAppViewCoordinator: WKNavigationDelegate {
|
||||
let yOffset = scrollView.contentOffset.y
|
||||
|
||||
if yOffset == 0 {
|
||||
scrollView.contentInset.top = navBarHeight
|
||||
scrollView.contentInset.top = readerViewNavBarHeight
|
||||
navBarVisibilityRatio = 1
|
||||
return
|
||||
}
|
||||
|
||||
if yOffset < 0 {
|
||||
navBarVisibilityRatio = 1
|
||||
scrollView.contentInset.top = navBarHeight
|
||||
scrollView.contentInset.top = readerViewNavBarHeight
|
||||
return
|
||||
}
|
||||
|
||||
if yOffset < navBarHeight {
|
||||
if yOffset < readerViewNavBarHeight {
|
||||
let isScrollingUp = yOffsetAtStartOfDrag ?? 0 > yOffset
|
||||
navBarVisibilityRatio = isScrollingUp || yOffset < 0 ? 1 : min(1, 1 - (yOffset / navBarHeight))
|
||||
scrollView.contentInset.top = navBarVisibilityRatio * navBarHeight
|
||||
navBarVisibilityRatio = isScrollingUp || yOffset < 0 ? 1 : min(1, 1 - (yOffset / readerViewNavBarHeight))
|
||||
scrollView.contentInset.top = navBarVisibilityRatio * readerViewNavBarHeight
|
||||
return
|
||||
}
|
||||
|
||||
@ -79,21 +79,21 @@ extension WebAppViewCoordinator: WKNavigationDelegate {
|
||||
|
||||
if yOffset > yOffsetAtStartOfDrag, !isNavBarHidden {
|
||||
let translation = yOffset - yOffsetAtStartOfDrag
|
||||
let ratio = translation < navBarHeight ? 1 - (translation / navBarHeight) : 0
|
||||
let ratio = translation < readerViewNavBarHeight ? 1 - (translation / readerViewNavBarHeight) : 0
|
||||
navBarVisibilityRatio = min(ratio, 1)
|
||||
scrollView.contentInset.top = navBarVisibilityRatio * navBarHeight
|
||||
scrollView.contentInset.top = navBarVisibilityRatio * readerViewNavBarHeight
|
||||
}
|
||||
}
|
||||
|
||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||
if decelerate, scrollView.contentOffset.y + scrollView.contentInset.top < (yOffsetAtStartOfDrag ?? 0) {
|
||||
scrollView.contentInset.top = navBarHeight
|
||||
scrollView.contentInset.top = readerViewNavBarHeight
|
||||
navBarVisibilityRatio = 1
|
||||
}
|
||||
}
|
||||
|
||||
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
|
||||
scrollView.contentInset.top = navBarHeight
|
||||
scrollView.contentInset.top = readerViewNavBarHeight
|
||||
navBarVisibilityRatio = 1
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user