mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-22 08:10:59 +00:00
Refactoring
This commit is contained in:
parent
19176f955c
commit
980c5f0099
12 changed files with 115 additions and 111 deletions
|
@ -5,18 +5,19 @@ import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public final class AccountViewModel: CollectionItemViewModel, ObservableObject {
|
public final class AccountViewModel: ObservableObject {
|
||||||
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
|
|
||||||
public let identityContext: IdentityContext
|
public let identityContext: IdentityContext
|
||||||
public internal(set) var configuration = CollectionItem.AccountConfiguration.withNote
|
public internal(set) var configuration = CollectionItem.AccountConfiguration.withNote
|
||||||
|
|
||||||
private let accountService: AccountService
|
private let accountService: AccountService
|
||||||
private let eventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
|
private let eventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>
|
||||||
|
|
||||||
init(accountService: AccountService, identityContext: IdentityContext) {
|
init(accountService: AccountService,
|
||||||
|
identityContext: IdentityContext,
|
||||||
|
eventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>) {
|
||||||
self.accountService = accountService
|
self.accountService = accountService
|
||||||
self.identityContext = identityContext
|
self.identityContext = identityContext
|
||||||
events = eventsSubject.eraseToAnyPublisher()
|
self.eventsSubject = eventsSubject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
// Copyright © 2020 Metabolist. All rights reserved.
|
|
||||||
|
|
||||||
import Combine
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
public protocol CollectionItemViewModel {
|
|
||||||
var events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never> { get }
|
|
||||||
}
|
|
|
@ -13,8 +13,8 @@ public class CollectionItemsViewModel: ObservableObject {
|
||||||
|
|
||||||
@Published private var lastUpdate = CollectionUpdate.empty
|
@Published private var lastUpdate = CollectionUpdate.empty
|
||||||
private let collectionService: CollectionService
|
private let collectionService: CollectionService
|
||||||
private var viewModelCache = [CollectionItem: (viewModel: CollectionItemViewModel, events: AnyCancellable)]()
|
private var viewModelCache = [CollectionItem: Any]()
|
||||||
private let eventsSubject = PassthroughSubject<CollectionItemEvent, Never>()
|
private let eventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
|
||||||
private let loadingSubject = PassthroughSubject<Bool, Never>()
|
private let loadingSubject = PassthroughSubject<Bool, Never>()
|
||||||
private let expandAllSubject: CurrentValueSubject<ExpandAllState, Never>
|
private let expandAllSubject: CurrentValueSubject<ExpandAllState, Never>
|
||||||
private var topVisibleIndexPath = IndexPath(item: 0, section: 0)
|
private var topVisibleIndexPath = IndexPath(item: 0, section: 0)
|
||||||
|
@ -83,7 +83,14 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
|
|
||||||
public var loading: AnyPublisher<Bool, Never> { loadingSubject.eraseToAnyPublisher() }
|
public var loading: AnyPublisher<Bool, Never> { loadingSubject.eraseToAnyPublisher() }
|
||||||
|
|
||||||
public var events: AnyPublisher<CollectionItemEvent, Never> { eventsSubject.eraseToAnyPublisher() }
|
public var events: AnyPublisher<CollectionItemEvent, Never> {
|
||||||
|
eventsSubject.flatMap { [weak self] eventPublisher -> AnyPublisher<CollectionItemEvent, Never> in
|
||||||
|
guard let self = self else { return Empty().eraseToAnyPublisher() }
|
||||||
|
|
||||||
|
return eventPublisher.assignErrorsToAlertItem(to: \.alertItem, on: self).eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
.eraseToAnyPublisher()
|
||||||
|
}
|
||||||
|
|
||||||
public var canRefresh: Bool { collectionService.canRefresh }
|
public var canRefresh: Bool { collectionService.canRefresh }
|
||||||
|
|
||||||
|
@ -128,44 +135,38 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
|
|
||||||
switch item {
|
switch item {
|
||||||
case let .status(status, _):
|
case let .status(status, _):
|
||||||
eventsSubject.send(
|
send(event: .navigation(.collection(collectionService
|
||||||
.navigation(.collection(collectionService
|
|
||||||
.navigationService
|
.navigationService
|
||||||
.contextService(id: status.displayStatus.id))))
|
.contextService(id: status.displayStatus.id))))
|
||||||
case let .loadMore(loadMore):
|
case let .loadMore(loadMore):
|
||||||
lastSelectedLoadMore = loadMore
|
lastSelectedLoadMore = loadMore
|
||||||
(viewModel(indexPath: indexPath) as? LoadMoreViewModel)?.loadMore()
|
(viewModel(indexPath: indexPath) as? LoadMoreViewModel)?.loadMore()
|
||||||
case let .account(account, _):
|
case let .account(account, _):
|
||||||
eventsSubject.send(
|
send(event: .navigation(.profile(collectionService
|
||||||
.navigation(.profile(collectionService
|
|
||||||
.navigationService
|
.navigationService
|
||||||
.profileService(account: account))))
|
.profileService(account: account))))
|
||||||
case let .notification(notification, _):
|
case let .notification(notification, _):
|
||||||
if let status = notification.status {
|
if let status = notification.status {
|
||||||
eventsSubject.send(
|
send(event: .navigation(.collection(collectionService
|
||||||
.navigation(.collection(collectionService
|
|
||||||
.navigationService
|
.navigationService
|
||||||
.contextService(id: status.displayStatus.id))))
|
.contextService(id: status.displayStatus.id))))
|
||||||
} else {
|
} else {
|
||||||
eventsSubject.send(
|
send(event: .navigation(.profile(collectionService
|
||||||
.navigation(.profile(collectionService
|
|
||||||
.navigationService
|
.navigationService
|
||||||
.profileService(account: notification.account))))
|
.profileService(account: notification.account))))
|
||||||
}
|
}
|
||||||
case let .conversation(conversation):
|
case let .conversation(conversation):
|
||||||
guard let status = conversation.lastStatus else { break }
|
guard let status = conversation.lastStatus else { break }
|
||||||
|
|
||||||
eventsSubject.send(
|
send(event: .navigation(.collection(collectionService
|
||||||
.navigation(.collection(collectionService
|
|
||||||
.navigationService
|
.navigationService
|
||||||
.contextService(id: status.displayStatus.id))))
|
.contextService(id: status.displayStatus.id))))
|
||||||
case let .tag(tag):
|
case let .tag(tag):
|
||||||
eventsSubject.send(
|
send(event: .navigation(.collection(collectionService
|
||||||
.navigation(.collection(collectionService
|
|
||||||
.navigationService
|
.navigationService
|
||||||
.timelineService(timeline: .tag(tag.name)))))
|
.timelineService(timeline: .tag(tag.name)))))
|
||||||
case let .moreResults(moreResults):
|
case let .moreResults(moreResults):
|
||||||
eventsSubject.send(.navigation(.searchScope(moreResults.scope)))
|
send(event: .navigation(.searchScope(moreResults.scope)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,9 +192,9 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// swiftlint:disable:next function_body_length cyclomatic_complexity
|
// swiftlint:disable:next function_body_length cyclomatic_complexity
|
||||||
public func viewModel(indexPath: IndexPath) -> CollectionItemViewModel {
|
public func viewModel(indexPath: IndexPath) -> Any {
|
||||||
let item = lastUpdate.sections[indexPath.section].items[indexPath.item]
|
let item = lastUpdate.sections[indexPath.section].items[indexPath.item]
|
||||||
let cachedViewModel = viewModelCache[item]?.viewModel
|
let cachedViewModel = viewModelCache[item]
|
||||||
|
|
||||||
switch item {
|
switch item {
|
||||||
case let .status(status, configuration):
|
case let .status(status, configuration):
|
||||||
|
@ -204,8 +205,9 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
} else {
|
} else {
|
||||||
viewModel = .init(
|
viewModel = .init(
|
||||||
statusService: collectionService.navigationService.statusService(status: status),
|
statusService: collectionService.navigationService.statusService(status: status),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
cache(viewModel: viewModel, forItem: item)
|
eventsSubject: eventsSubject)
|
||||||
|
viewModelCache[item] = viewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.configuration = configuration
|
viewModel.configuration = configuration
|
||||||
|
@ -217,9 +219,10 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
let viewModel = LoadMoreViewModel(
|
let viewModel = LoadMoreViewModel(
|
||||||
loadMoreService: collectionService.navigationService.loadMoreService(loadMore: loadMore))
|
loadMoreService: collectionService.navigationService.loadMoreService(loadMore: loadMore),
|
||||||
|
eventsSubject: eventsSubject)
|
||||||
|
|
||||||
cache(viewModel: viewModel, forItem: item)
|
viewModelCache[item] = viewModel
|
||||||
|
|
||||||
return viewModel
|
return viewModel
|
||||||
case let .account(account, configuration):
|
case let .account(account, configuration):
|
||||||
|
@ -230,31 +233,34 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
} else {
|
} else {
|
||||||
viewModel = AccountViewModel(
|
viewModel = AccountViewModel(
|
||||||
accountService: collectionService.navigationService.accountService(account: account),
|
accountService: collectionService.navigationService.accountService(account: account),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
cache(viewModel: viewModel, forItem: item)
|
eventsSubject: eventsSubject)
|
||||||
|
viewModelCache[item] = viewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.configuration = configuration
|
viewModel.configuration = configuration
|
||||||
|
|
||||||
return viewModel
|
return viewModel
|
||||||
case let .notification(notification, statusConfiguration):
|
case let .notification(notification, statusConfiguration):
|
||||||
let viewModel: CollectionItemViewModel
|
let viewModel: Any
|
||||||
|
|
||||||
if let cachedViewModel = cachedViewModel {
|
if let cachedViewModel = cachedViewModel {
|
||||||
viewModel = cachedViewModel
|
viewModel = cachedViewModel
|
||||||
} else if let status = notification.status, let statusConfiguration = statusConfiguration {
|
} else if let status = notification.status, let statusConfiguration = statusConfiguration {
|
||||||
let statusViewModel = StatusViewModel(
|
let statusViewModel = StatusViewModel(
|
||||||
statusService: collectionService.navigationService.statusService(status: status),
|
statusService: collectionService.navigationService.statusService(status: status),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
|
eventsSubject: eventsSubject)
|
||||||
statusViewModel.configuration = statusConfiguration
|
statusViewModel.configuration = statusConfiguration
|
||||||
viewModel = statusViewModel
|
viewModel = statusViewModel
|
||||||
cache(viewModel: viewModel, forItem: item)
|
viewModelCache[item] = viewModel
|
||||||
} else {
|
} else {
|
||||||
viewModel = NotificationViewModel(
|
viewModel = NotificationViewModel(
|
||||||
notificationService: collectionService.navigationService.notificationService(
|
notificationService: collectionService.navigationService.notificationService(
|
||||||
notification: notification),
|
notification: notification),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
cache(viewModel: viewModel, forItem: item)
|
eventsSubject: eventsSubject)
|
||||||
|
viewModelCache[item] = viewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
return viewModel
|
return viewModel
|
||||||
|
@ -268,7 +274,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
conversation: conversation),
|
conversation: conversation),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext)
|
||||||
|
|
||||||
cache(viewModel: viewModel, forItem: item)
|
viewModelCache[item] = viewModel
|
||||||
|
|
||||||
return viewModel
|
return viewModel
|
||||||
case let .tag(tag):
|
case let .tag(tag):
|
||||||
|
@ -278,7 +284,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
|
|
||||||
let viewModel = TagViewModel(tag: tag, identityContext: identityContext)
|
let viewModel = TagViewModel(tag: tag, identityContext: identityContext)
|
||||||
|
|
||||||
cache(viewModel: viewModel, forItem: item)
|
viewModelCache[item] = viewModel
|
||||||
|
|
||||||
return viewModel
|
return viewModel
|
||||||
case let .moreResults(moreResults):
|
case let .moreResults(moreResults):
|
||||||
|
@ -288,7 +294,7 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
|
|
||||||
let viewModel = MoreResultsViewModel(moreResults: moreResults)
|
let viewModel = MoreResultsViewModel(moreResults: moreResults)
|
||||||
|
|
||||||
cache(viewModel: viewModel, forItem: item)
|
viewModelCache[item] = viewModel
|
||||||
|
|
||||||
return viewModel
|
return viewModel
|
||||||
}
|
}
|
||||||
|
@ -335,21 +341,14 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
private extension CollectionItemsViewModel {
|
private extension CollectionItemsViewModel {
|
||||||
private static let lastReadIdDebounceInterval: TimeInterval = 0.5
|
private static let lastReadIdDebounceInterval: TimeInterval = 0.5
|
||||||
|
|
||||||
|
func send(event: CollectionItemEvent) {
|
||||||
|
eventsSubject.send(Just(event).setFailureType(to: Error.self).eraseToAnyPublisher())
|
||||||
|
}
|
||||||
|
|
||||||
var lastUpdateWasContextParentOnly: Bool {
|
var lastUpdateWasContextParentOnly: Bool {
|
||||||
collectionService is ContextService && lastUpdate.sections.map(\.items).map(\.count) == [0, 1, 0]
|
collectionService is ContextService && lastUpdate.sections.map(\.items).map(\.count) == [0, 1, 0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func cache(viewModel: CollectionItemViewModel, forItem item: CollectionItem) {
|
|
||||||
viewModelCache[item] = (viewModel, viewModel.events
|
|
||||||
.flatMap { [weak self] events -> AnyPublisher<CollectionItemEvent, Never> in
|
|
||||||
guard let self = self else { return Empty().eraseToAnyPublisher() }
|
|
||||||
|
|
||||||
return events.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
|
||||||
.eraseToAnyPublisher()
|
|
||||||
}
|
|
||||||
.sink { [weak self] in self?.eventsSubject.send($0) })
|
|
||||||
}
|
|
||||||
|
|
||||||
func process(sections: [CollectionSection]) {
|
func process(sections: [CollectionSection]) {
|
||||||
let items = sections.map(\.items).reduce([], +)
|
let items = sections.map(\.items).reduce([], +)
|
||||||
let itemsSet = Set(items)
|
let itemsSet = Set(items)
|
||||||
|
@ -402,7 +401,7 @@ private extension CollectionItemsViewModel {
|
||||||
if case let .remove(_, item, _) = removal,
|
if case let .remove(_, item, _) = removal,
|
||||||
case let .loadMore(loadMore) = item,
|
case let .loadMore(loadMore) = item,
|
||||||
loadMore == lastSelectedLoadMore,
|
loadMore == lastSelectedLoadMore,
|
||||||
let direction = (viewModelCache[item]?.viewModel as? LoadMoreViewModel)?.direction,
|
let direction = (viewModelCache[item] as? LoadMoreViewModel)?.direction,
|
||||||
direction == .up,
|
direction == .up,
|
||||||
let statusAfterLoadMore = items.first(where: {
|
let statusAfterLoadMore = items.first(where: {
|
||||||
guard case let .status(status, _) = $0 else { return false }
|
guard case let .status(status, _) = $0 else { return false }
|
||||||
|
|
|
@ -19,7 +19,7 @@ public protocol CollectionViewModel {
|
||||||
func viewedAtTop(indexPath: IndexPath)
|
func viewedAtTop(indexPath: IndexPath)
|
||||||
func select(indexPath: IndexPath)
|
func select(indexPath: IndexPath)
|
||||||
func canSelect(indexPath: IndexPath) -> Bool
|
func canSelect(indexPath: IndexPath) -> Bool
|
||||||
func viewModel(indexPath: IndexPath) -> CollectionItemViewModel
|
func viewModel(indexPath: IndexPath) -> Any
|
||||||
func toggleExpandAll()
|
func toggleExpandAll()
|
||||||
func applyAccountListEdit(viewModel: AccountViewModel, edit: CollectionItemEvent.AccountListEdit)
|
func applyAccountListEdit(viewModel: AccountViewModel, edit: CollectionItemEvent.AccountListEdit)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,32 +5,31 @@ import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public final class ConversationViewModel: CollectionItemViewModel, ObservableObject {
|
public final class ConversationViewModel: ObservableObject {
|
||||||
public let accountViewModels: [AccountViewModel]
|
public let accountViewModels: [AccountViewModel]
|
||||||
public let statusViewModel: StatusViewModel?
|
public let statusViewModel: StatusViewModel?
|
||||||
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
|
|
||||||
public let identityContext: IdentityContext
|
public let identityContext: IdentityContext
|
||||||
|
|
||||||
private let conversationService: ConversationService
|
private let conversationService: ConversationService
|
||||||
private let eventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
|
|
||||||
|
|
||||||
init(conversationService: ConversationService, identityContext: IdentityContext) {
|
init(conversationService: ConversationService, identityContext: IdentityContext) {
|
||||||
accountViewModels = conversationService.conversation.accounts.map {
|
accountViewModels = conversationService.conversation.accounts.map {
|
||||||
AccountViewModel(
|
AccountViewModel(
|
||||||
accountService: conversationService.navigationService.accountService(account: $0),
|
accountService: conversationService.navigationService.accountService(account: $0),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
|
eventsSubject: .init())
|
||||||
}
|
}
|
||||||
|
|
||||||
if let status = conversationService.conversation.lastStatus {
|
if let status = conversationService.conversation.lastStatus {
|
||||||
statusViewModel = StatusViewModel(
|
statusViewModel = StatusViewModel(
|
||||||
statusService: conversationService.navigationService.statusService(status: status),
|
statusService: conversationService.navigationService.statusService(status: status),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
|
eventsSubject: .init())
|
||||||
} else {
|
} else {
|
||||||
statusViewModel = nil
|
statusViewModel = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.conversationService = conversationService
|
self.conversationService = conversationService
|
||||||
self.identityContext = identityContext
|
self.identityContext = identityContext
|
||||||
self.events = eventsSubject.eraseToAnyPublisher()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,17 @@
|
||||||
import Combine
|
import Combine
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public final class LoadMoreViewModel: ObservableObject, CollectionItemViewModel {
|
public final class LoadMoreViewModel: ObservableObject {
|
||||||
public var direction = LoadMore.Direction.up
|
public var direction = LoadMore.Direction.up
|
||||||
@Published public private(set) var loading = false
|
@Published public private(set) var loading = false
|
||||||
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
|
|
||||||
|
|
||||||
private let loadMoreService: LoadMoreService
|
private let loadMoreService: LoadMoreService
|
||||||
private let eventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
|
private let eventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>
|
||||||
|
|
||||||
init(loadMoreService: LoadMoreService) {
|
init(loadMoreService: LoadMoreService,
|
||||||
|
eventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>) {
|
||||||
self.loadMoreService = loadMoreService
|
self.loadMoreService = loadMoreService
|
||||||
events = eventsSubject.eraseToAnyPublisher()
|
self.eventsSubject = eventsSubject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,11 @@
|
||||||
import Combine
|
import Combine
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public final class MoreResultsViewModel: ObservableObject, CollectionItemViewModel {
|
public final class MoreResultsViewModel: ObservableObject {
|
||||||
public var events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
|
|
||||||
|
|
||||||
private let moreResults: MoreResults
|
private let moreResults: MoreResults
|
||||||
private let eventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
|
|
||||||
|
|
||||||
init(moreResults: MoreResults) {
|
init(moreResults: MoreResults) {
|
||||||
self.moreResults = moreResults
|
self.moreResults = moreResults
|
||||||
events = eventsSubject.eraseToAnyPublisher()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,32 +5,34 @@ import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public final class NotificationViewModel: CollectionItemViewModel, ObservableObject {
|
public final class NotificationViewModel: ObservableObject {
|
||||||
public let accountViewModel: AccountViewModel
|
public let accountViewModel: AccountViewModel
|
||||||
public let statusViewModel: StatusViewModel?
|
public let statusViewModel: StatusViewModel?
|
||||||
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
|
|
||||||
public let identityContext: IdentityContext
|
public let identityContext: IdentityContext
|
||||||
|
|
||||||
private let notificationService: NotificationService
|
private let notificationService: NotificationService
|
||||||
private let eventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
|
private let eventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>
|
||||||
|
|
||||||
init(notificationService: NotificationService, identityContext: IdentityContext) {
|
init(notificationService: NotificationService,
|
||||||
|
identityContext: IdentityContext,
|
||||||
|
eventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>) {
|
||||||
self.notificationService = notificationService
|
self.notificationService = notificationService
|
||||||
self.identityContext = identityContext
|
self.identityContext = identityContext
|
||||||
|
self.eventsSubject = eventsSubject
|
||||||
self.accountViewModel = AccountViewModel(
|
self.accountViewModel = AccountViewModel(
|
||||||
accountService: notificationService.navigationService.accountService(
|
accountService: notificationService.navigationService.accountService(
|
||||||
account: notificationService.notification.account),
|
account: notificationService.notification.account),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
|
eventsSubject: eventsSubject)
|
||||||
|
|
||||||
if let status = notificationService.notification.status {
|
if let status = notificationService.notification.status {
|
||||||
statusViewModel = StatusViewModel(
|
statusViewModel = StatusViewModel(
|
||||||
statusService: notificationService.navigationService.statusService(status: status),
|
statusService: notificationService.navigationService.statusService(status: status),
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
|
eventsSubject: eventsSubject)
|
||||||
} else {
|
} else {
|
||||||
statusViewModel = nil
|
statusViewModel = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
self.events = eventsSubject.eraseToAnyPublisher()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ final public class ProfileViewModel {
|
||||||
|
|
||||||
private let profileService: ProfileService
|
private let profileService: ProfileService
|
||||||
private let collectionViewModel: CurrentValueSubject<CollectionItemsViewModel, Never>
|
private let collectionViewModel: CurrentValueSubject<CollectionItemsViewModel, Never>
|
||||||
|
private let accountEventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>
|
||||||
private let imagePresentationsSubject = PassthroughSubject<URL, Never>()
|
private let imagePresentationsSubject = PassthroughSubject<URL, Never>()
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
|
@ -25,8 +26,16 @@ final public class ProfileViewModel {
|
||||||
collectionService: profileService.timelineService(profileCollection: .statuses),
|
collectionService: profileService.timelineService(profileCollection: .statuses),
|
||||||
identityContext: identityContext))
|
identityContext: identityContext))
|
||||||
|
|
||||||
|
let accountEventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
|
||||||
|
|
||||||
|
self.accountEventsSubject = accountEventsSubject
|
||||||
|
|
||||||
profileService.accountServicePublisher
|
profileService.accountServicePublisher
|
||||||
.map { AccountViewModel(accountService: $0, identityContext: identityContext) }
|
.map {
|
||||||
|
AccountViewModel(accountService: $0,
|
||||||
|
identityContext: identityContext,
|
||||||
|
eventsSubject: accountEventsSubject)
|
||||||
|
}
|
||||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||||
.assign(to: &$accountViewModel)
|
.assign(to: &$accountViewModel)
|
||||||
|
|
||||||
|
@ -102,10 +111,12 @@ extension ProfileViewModel: CollectionViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
public var events: AnyPublisher<CollectionItemEvent, Never> {
|
public var events: AnyPublisher<CollectionItemEvent, Never> {
|
||||||
$accountViewModel.compactMap { $0 }
|
accountEventsSubject
|
||||||
.flatMap(\.events)
|
.flatMap { [weak self] eventPublisher -> AnyPublisher<CollectionItemEvent, Never> in
|
||||||
.flatMap { $0 }
|
guard let self = self else { return Empty().eraseToAnyPublisher() }
|
||||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
|
||||||
|
return eventPublisher.assignErrorsToAlertItem(to: \.alertItem, on: self).eraseToAnyPublisher()
|
||||||
|
}
|
||||||
.merge(with: collectionViewModel.flatMap(\.events))
|
.merge(with: collectionViewModel.flatMap(\.events))
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
@ -143,7 +154,7 @@ extension ProfileViewModel: CollectionViewModel {
|
||||||
collectionViewModel.value.canSelect(indexPath: indexPath)
|
collectionViewModel.value.canSelect(indexPath: indexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func viewModel(indexPath: IndexPath) -> CollectionItemViewModel {
|
public func viewModel(indexPath: IndexPath) -> Any {
|
||||||
collectionViewModel.value.viewModel(indexPath: indexPath)
|
collectionViewModel.value.viewModel(indexPath: indexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,9 @@ public final class ReportViewModel: ObservableObject {
|
||||||
events = eventsSubject.eraseToAnyPublisher()
|
events = eventsSubject.eraseToAnyPublisher()
|
||||||
|
|
||||||
if let statusService = statusService {
|
if let statusService = statusService {
|
||||||
statusViewModel = StatusViewModel(statusService: statusService, identityContext: identityContext)
|
statusViewModel = StatusViewModel(statusService: statusService,
|
||||||
|
identityContext: identityContext,
|
||||||
|
eventsSubject: .init())
|
||||||
elements.statusIds.insert(statusService.status.displayStatus.id)
|
elements.statusIds.insert(statusService.status.displayStatus.id)
|
||||||
} else {
|
} else {
|
||||||
statusViewModel = nil
|
statusViewModel = nil
|
||||||
|
|
|
@ -5,7 +5,7 @@ import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
import ServiceLayer
|
import ServiceLayer
|
||||||
|
|
||||||
public final class StatusViewModel: CollectionItemViewModel, AttachmentsRenderingViewModel, ObservableObject {
|
public final class StatusViewModel: AttachmentsRenderingViewModel, ObservableObject {
|
||||||
public let content: NSAttributedString
|
public let content: NSAttributedString
|
||||||
public let contentEmojis: [Emoji]
|
public let contentEmojis: [Emoji]
|
||||||
public let displayName: String
|
public let displayName: String
|
||||||
|
@ -18,15 +18,17 @@ public final class StatusViewModel: CollectionItemViewModel, AttachmentsRenderin
|
||||||
public let pollEmojis: [Emoji]
|
public let pollEmojis: [Emoji]
|
||||||
@Published public var pollOptionSelections = Set<Int>()
|
@Published public var pollOptionSelections = Set<Int>()
|
||||||
public var configuration = CollectionItem.StatusConfiguration.default
|
public var configuration = CollectionItem.StatusConfiguration.default
|
||||||
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
|
|
||||||
public let identityContext: IdentityContext
|
public let identityContext: IdentityContext
|
||||||
|
|
||||||
private let statusService: StatusService
|
private let statusService: StatusService
|
||||||
private let eventsSubject = PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>()
|
private let eventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>
|
||||||
|
|
||||||
init(statusService: StatusService, identityContext: IdentityContext) {
|
init(statusService: StatusService,
|
||||||
|
identityContext: IdentityContext,
|
||||||
|
eventsSubject: PassthroughSubject<AnyPublisher<CollectionItemEvent, Error>, Never>) {
|
||||||
self.statusService = statusService
|
self.statusService = statusService
|
||||||
self.identityContext = identityContext
|
self.identityContext = identityContext
|
||||||
|
self.eventsSubject = eventsSubject
|
||||||
content = statusService.status.displayStatus.content.attributed
|
content = statusService.status.displayStatus.content.attributed
|
||||||
contentEmojis = statusService.status.displayStatus.emojis
|
contentEmojis = statusService.status.displayStatus.emojis
|
||||||
displayName = statusService.status.displayStatus.account.displayName.isEmpty
|
displayName = statusService.status.displayStatus.account.displayName.isEmpty
|
||||||
|
@ -42,7 +44,6 @@ public final class StatusViewModel: CollectionItemViewModel, AttachmentsRenderin
|
||||||
attachmentViewModels = statusService.status.displayStatus.mediaAttachments
|
attachmentViewModels = statusService.status.displayStatus.mediaAttachments
|
||||||
.map { AttachmentViewModel(attachment: $0, identityContext: identityContext, status: statusService.status) }
|
.map { AttachmentViewModel(attachment: $0, identityContext: identityContext, status: statusService.status) }
|
||||||
pollEmojis = statusService.status.displayStatus.poll?.emojis ?? []
|
pollEmojis = statusService.status.displayStatus.poll?.emojis ?? []
|
||||||
events = eventsSubject.eraseToAnyPublisher()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +222,9 @@ public extension StatusViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
func reply() {
|
func reply() {
|
||||||
let replyViewModel = Self(statusService: statusService, identityContext: identityContext)
|
let replyViewModel = Self(statusService: statusService,
|
||||||
|
identityContext: identityContext,
|
||||||
|
eventsSubject: .init())
|
||||||
|
|
||||||
replyViewModel.configuration = configuration.reply()
|
replyViewModel.configuration = configuration.reply()
|
||||||
|
|
||||||
|
@ -292,7 +295,8 @@ public extension StatusViewModel {
|
||||||
if let inReplyToStatusService = inReplyToStatusService {
|
if let inReplyToStatusService = inReplyToStatusService {
|
||||||
inReplyToViewModel = Self(
|
inReplyToViewModel = Self(
|
||||||
statusService: inReplyToStatusService,
|
statusService: inReplyToStatusService,
|
||||||
identityContext: identityContext)
|
identityContext: identityContext,
|
||||||
|
eventsSubject: .init())
|
||||||
inReplyToViewModel?.configuration = CollectionItem.StatusConfiguration.default.reply()
|
inReplyToViewModel?.configuration = CollectionItem.StatusConfiguration.default.reply()
|
||||||
} else {
|
} else {
|
||||||
inReplyToViewModel = nil
|
inReplyToViewModel = nil
|
||||||
|
|
|
@ -4,16 +4,14 @@ import Combine
|
||||||
import Foundation
|
import Foundation
|
||||||
import Mastodon
|
import Mastodon
|
||||||
|
|
||||||
public struct TagViewModel: CollectionItemViewModel {
|
public struct TagViewModel {
|
||||||
public let identityContext: IdentityContext
|
public let identityContext: IdentityContext
|
||||||
public let events: AnyPublisher<AnyPublisher<CollectionItemEvent, Error>, Never>
|
|
||||||
|
|
||||||
private let tag: Tag
|
private let tag: Tag
|
||||||
|
|
||||||
init(tag: Tag, identityContext: IdentityContext) {
|
init(tag: Tag, identityContext: IdentityContext) {
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
self.identityContext = identityContext
|
self.identityContext = identityContext
|
||||||
events = Empty().eraseToAnyPublisher()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue