Refactoring

This commit is contained in:
Justin Mazzocchi 2021-02-04 14:24:27 -08:00
parent 19176f955c
commit 980c5f0099
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
12 changed files with 115 additions and 111 deletions

View file

@ -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
} }
} }

View file

@ -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 }
}

View file

@ -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,19 +341,12 @@ extension CollectionItemsViewModel: CollectionViewModel {
private extension CollectionItemsViewModel { private extension CollectionItemsViewModel {
private static let lastReadIdDebounceInterval: TimeInterval = 0.5 private static let lastReadIdDebounceInterval: TimeInterval = 0.5
var lastUpdateWasContextParentOnly: Bool { func send(event: CollectionItemEvent) {
collectionService is ContextService && lastUpdate.sections.map(\.items).map(\.count) == [0, 1, 0] eventsSubject.send(Just(event).setFailureType(to: Error.self).eraseToAnyPublisher())
} }
func cache(viewModel: CollectionItemViewModel, forItem item: CollectionItem) { var lastUpdateWasContextParentOnly: Bool {
viewModelCache[item] = (viewModel, viewModel.events collectionService is ContextService && lastUpdate.sections.map(\.items).map(\.count) == [0, 1, 0]
.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]) {
@ -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 }

View file

@ -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)
} }

View file

@ -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()
} }
} }

View file

@ -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
} }
} }

View file

@ -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()
} }
} }

View file

@ -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()
} }
} }

View file

@ -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)
} }

View file

@ -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

View file

@ -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

View file

@ -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()
} }
} }