Status actions pipeline

This commit is contained in:
Justin Mazzocchi 2020-09-14 16:32:34 -07:00
parent 56297a643c
commit a595133d70
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
4 changed files with 47 additions and 9 deletions

View file

@ -78,6 +78,15 @@ final class StatusListViewController: UITableViewController {
} }
.store(in: &cancellables) .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 viewModel.$loading
.receive(on: RunLoop.main) .receive(on: RunLoop.main)
.sink { [weak self] in .sink { [weak self] in
@ -146,6 +155,12 @@ extension StatusListViewController: UITableViewDataSourcePrefetching {
} }
private extension StatusListViewController { private extension StatusListViewController {
func share(url: URL) {
let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
present(activityViewController, animated: true, completion: nil)
}
func sizeTableHeaderFooterViews() { func sizeTableHeaderFooterViews() {
// https://useyourloaf.com/blog/variable-height-table-view-header/ // https://useyourloaf.com/blog/variable-height-table-view-header/
if let headerView = tableView.tableHeaderView { if let headerView = tableView.tableHeaderView {

View file

@ -9,15 +9,18 @@ public final class StatusListViewModel: ObservableObject {
@Published public private(set) var statusIDs = [[String]]() @Published public private(set) var statusIDs = [[String]]()
@Published public var alertItem: AlertItem? @Published public var alertItem: AlertItem?
@Published public private(set) var loading = false @Published public private(set) var loading = false
public let statusEvents: AnyPublisher<StatusViewModel.Event, Never>
public private(set) var maintainScrollPositionOfStatusID: String? public private(set) var maintainScrollPositionOfStatusID: String?
private var statuses = [String: Status]() private var statuses = [String: Status]()
private let statusListService: StatusListService private let statusListService: StatusListService
private var statusViewModelCache = [Status: (StatusViewModel, AnyCancellable)]() private var statusViewModelCache = [Status: (StatusViewModel, AnyCancellable)]()
private let statusEventsSubject = PassthroughSubject<StatusViewModel.Event, Never>()
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
init(statusListService: StatusListService) { init(statusListService: StatusListService) {
self.statusListService = statusListService self.statusListService = statusListService
statusEvents = statusEventsSubject.eraseToAnyPublisher()
statusListService.statusSections statusListService.statusSections
.combineLatest(statusListService.filters.map { $0.regularExpression() }) .combineLatest(statusListService.filters.map { $0.regularExpression() })
@ -54,15 +57,16 @@ public extension StatusListViewModel {
guard let status = statuses[id] else { return nil } guard let status = statuses[id] else { return nil }
var statusViewModel: StatusViewModel var statusViewModel: StatusViewModel
if let cachedViewModel = statusViewModelCache[status]?.0 { if let cachedViewModel = statusViewModelCache[status]?.0 {
statusViewModel = cachedViewModel statusViewModel = cachedViewModel
} else { } else {
statusViewModel = StatusViewModel(statusService: statusListService.statusService(status: status)) statusViewModel = StatusViewModel(statusService: statusListService.statusService(status: status))
statusViewModelCache[status] = (statusViewModel, statusViewModel.events statusViewModelCache[status] = (statusViewModel,
.flatMap { $0 } statusViewModel.events
.assignErrorsToAlertItem(to: \.alertItem, on: self) .flatMap { $0 }
.sink { _ in }) .assignErrorsToAlertItem(to: \.alertItem, on: self)
.sink { [weak self] in self?.statusEventsSubject.send($0) })
} }
statusViewModel.isContextParent = status.id == statusListService.contextParentID statusViewModel.isContextParent = status.id == statusListService.contextParentID

View file

@ -22,10 +22,10 @@ public struct StatusViewModel {
public var isReplyInContext = false public var isReplyInContext = false
public var hasReplyFollowing = false public var hasReplyFollowing = false
public var sensitiveContentToggled = 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 statusService: StatusService
private let eventsInput = PassthroughSubject<AnyPublisher<Never, Error>, Never>() private let eventsSubject = PassthroughSubject<AnyPublisher<Event, Error>, Never>()
init(statusService: StatusService) { init(statusService: StatusService) {
self.statusService = statusService self.statusService = statusService
@ -45,7 +45,16 @@ public struct StatusViewModel {
.map(AttachmentViewModel.init(attachment:)) .map(AttachmentViewModel.init(attachment:))
pollOptionTitles = statusService.status.displayStatus.poll?.options.map { $0.title } ?? [] pollOptionTitles = statusService.status.displayStatus.poll?.options.map { $0.title } ?? []
pollEmoji = statusService.status.displayStatus.poll?.emojis ?? [] 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() { 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())
} }
} }

View file

@ -148,6 +148,10 @@ private extension StatusView {
favoriteButton.addAction(favoriteAction, for: .touchUpInside) favoriteButton.addAction(favoriteAction, for: .touchUpInside)
contextParentFavoriteButton.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() applyStatusConfiguration()
} }