Status actions pipeline
This commit is contained in:
parent
56297a643c
commit
a595133d70
|
@ -78,6 +78,15 @@ final class StatusListViewController: UITableViewController {
|
|||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
viewModel.statusEvents.sink { [weak self] in
|
||||
switch $0 {
|
||||
case .ignorableOutput, .statusListNavigation, .urlNavigation: break
|
||||
case let .share(url):
|
||||
self?.share(url: url)
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
viewModel.$loading
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] in
|
||||
|
@ -146,6 +155,12 @@ extension StatusListViewController: UITableViewDataSourcePrefetching {
|
|||
}
|
||||
|
||||
private extension StatusListViewController {
|
||||
func share(url: URL) {
|
||||
let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
||||
|
||||
present(activityViewController, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func sizeTableHeaderFooterViews() {
|
||||
// https://useyourloaf.com/blog/variable-height-table-view-header/
|
||||
if let headerView = tableView.tableHeaderView {
|
||||
|
|
|
@ -9,15 +9,18 @@ public final class StatusListViewModel: ObservableObject {
|
|||
@Published public private(set) var statusIDs = [[String]]()
|
||||
@Published public var alertItem: AlertItem?
|
||||
@Published public private(set) var loading = false
|
||||
public let statusEvents: AnyPublisher<StatusViewModel.Event, Never>
|
||||
public private(set) var maintainScrollPositionOfStatusID: String?
|
||||
|
||||
private var statuses = [String: Status]()
|
||||
private let statusListService: StatusListService
|
||||
private var statusViewModelCache = [Status: (StatusViewModel, AnyCancellable)]()
|
||||
private let statusEventsSubject = PassthroughSubject<StatusViewModel.Event, Never>()
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
init(statusListService: StatusListService) {
|
||||
self.statusListService = statusListService
|
||||
statusEvents = statusEventsSubject.eraseToAnyPublisher()
|
||||
|
||||
statusListService.statusSections
|
||||
.combineLatest(statusListService.filters.map { $0.regularExpression() })
|
||||
|
@ -54,15 +57,16 @@ public extension StatusListViewModel {
|
|||
guard let status = statuses[id] else { return nil }
|
||||
|
||||
var statusViewModel: StatusViewModel
|
||||
|
||||
|
||||
if let cachedViewModel = statusViewModelCache[status]?.0 {
|
||||
statusViewModel = cachedViewModel
|
||||
} else {
|
||||
statusViewModel = StatusViewModel(statusService: statusListService.statusService(status: status))
|
||||
statusViewModelCache[status] = (statusViewModel, statusViewModel.events
|
||||
.flatMap { $0 }
|
||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||
.sink { _ in })
|
||||
statusViewModelCache[status] = (statusViewModel,
|
||||
statusViewModel.events
|
||||
.flatMap { $0 }
|
||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||
.sink { [weak self] in self?.statusEventsSubject.send($0) })
|
||||
}
|
||||
|
||||
statusViewModel.isContextParent = status.id == statusListService.contextParentID
|
||||
|
|
|
@ -22,10 +22,10 @@ public struct StatusViewModel {
|
|||
public var isReplyInContext = false
|
||||
public var hasReplyFollowing = false
|
||||
public var sensitiveContentToggled = false
|
||||
public let events: AnyPublisher<AnyPublisher<Never, Error>, Never>
|
||||
public let events: AnyPublisher<AnyPublisher<Event, Error>, Never>
|
||||
|
||||
private let statusService: StatusService
|
||||
private let eventsInput = PassthroughSubject<AnyPublisher<Never, Error>, Never>()
|
||||
private let eventsSubject = PassthroughSubject<AnyPublisher<Event, Error>, Never>()
|
||||
|
||||
init(statusService: StatusService) {
|
||||
self.statusService = statusService
|
||||
|
@ -45,7 +45,16 @@ public struct StatusViewModel {
|
|||
.map(AttachmentViewModel.init(attachment:))
|
||||
pollOptionTitles = statusService.status.displayStatus.poll?.options.map { $0.title } ?? []
|
||||
pollEmoji = statusService.status.displayStatus.poll?.emojis ?? []
|
||||
events = eventsInput.eraseToAnyPublisher()
|
||||
events = eventsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
public extension StatusViewModel {
|
||||
enum Event {
|
||||
case ignorableOutput
|
||||
case statusListNavigation(StatusListViewModel)
|
||||
case urlNavigation(URL)
|
||||
case share(URL)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +117,13 @@ public extension StatusViewModel {
|
|||
}
|
||||
|
||||
func toggleFavorited() {
|
||||
eventsInput.send(statusService.toggleFavorited())
|
||||
eventsSubject.send(statusService.toggleFavorited().map { _ in Event.ignorableOutput }.eraseToAnyPublisher())
|
||||
}
|
||||
|
||||
func shareStatus() {
|
||||
guard let url = statusService.status.displayStatus.url else { return }
|
||||
|
||||
eventsSubject.send(Just(Event.share(url)).setFailureType(to: Error.self).eraseToAnyPublisher())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,10 @@ private extension StatusView {
|
|||
favoriteButton.addAction(favoriteAction, for: .touchUpInside)
|
||||
contextParentFavoriteButton.addAction(favoriteAction, for: .touchUpInside)
|
||||
|
||||
let shareAction = UIAction { [weak self] _ in self?.statusConfiguration.viewModel.shareStatus() }
|
||||
|
||||
shareButton.addAction(shareAction, for: .touchUpInside)
|
||||
|
||||
applyStatusConfiguration()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue