Account list edits
This commit is contained in:
parent
1fabcb41cc
commit
6b4e17e41e
|
@ -12,7 +12,7 @@ public struct AccountListService {
|
||||||
public let navigationService: NavigationService
|
public let navigationService: NavigationService
|
||||||
public let canRefresh = false
|
public let canRefresh = false
|
||||||
|
|
||||||
private let accountsSubject = PassthroughSubject<[Account], Error>()
|
private let accountsSubject = CurrentValueSubject<[Account], Error>([])
|
||||||
private let endpoint: AccountsEndpoint
|
private let endpoint: AccountsEndpoint
|
||||||
private let mastodonAPIClient: MastodonAPIClient
|
private let mastodonAPIClient: MastodonAPIClient
|
||||||
private let contentDatabase: ContentDatabase
|
private let contentDatabase: ContentDatabase
|
||||||
|
@ -27,23 +27,26 @@ public struct AccountListService {
|
||||||
self.mastodonAPIClient = mastodonAPIClient
|
self.mastodonAPIClient = mastodonAPIClient
|
||||||
self.contentDatabase = contentDatabase
|
self.contentDatabase = contentDatabase
|
||||||
self.titleComponents = titleComponents
|
self.titleComponents = titleComponents
|
||||||
sections = accountsSubject.scan([]) {
|
sections = accountsSubject
|
||||||
let presentIds = Set($0.map(\.id))
|
.map { [.init(items: $0.map { CollectionItem.account($0, endpoint.configuration) })] }
|
||||||
|
.eraseToAnyPublisher()
|
||||||
return $0 + $1.filter { !presentIds.contains($0.id) }
|
|
||||||
}
|
|
||||||
.map { [.init(items: $0.map { CollectionItem.account($0, endpoint.configuration) })] }
|
|
||||||
.eraseToAnyPublisher()
|
|
||||||
nextPageMaxId = nextPageMaxIdSubject.eraseToAnyPublisher()
|
nextPageMaxId = nextPageMaxIdSubject.eraseToAnyPublisher()
|
||||||
navigationService = NavigationService(mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
|
navigationService = NavigationService(mastodonAPIClient: mastodonAPIClient, contentDatabase: contentDatabase)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public extension AccountListService {
|
||||||
|
func remove(id: Account.Id) {
|
||||||
|
accountsSubject.value.removeAll { $0.id == id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension AccountListService: CollectionService {
|
extension AccountListService: CollectionService {
|
||||||
public func request(maxId: String?, minId: String?, search: Search?) -> AnyPublisher<Never, Error> {
|
public func request(maxId: String?, minId: String?, search: Search?) -> AnyPublisher<Never, Error> {
|
||||||
mastodonAPIClient.pagedRequest(endpoint, maxId: maxId, minId: minId)
|
mastodonAPIClient.pagedRequest(endpoint, maxId: maxId, minId: minId)
|
||||||
.handleEvents(receiveOutput: {
|
.handleEvents(receiveOutput: {
|
||||||
accountsSubject.send($0.result)
|
let presentIds = Set(accountsSubject.value.map(\.id))
|
||||||
|
accountsSubject.value.append(contentsOf: $0.result.filter { !presentIds.contains($0.id) })
|
||||||
|
|
||||||
guard let maxId = $0.info.maxId else { return }
|
guard let maxId = $0.info.maxId else { return }
|
||||||
|
|
||||||
|
|
|
@ -334,6 +334,8 @@ private extension TableViewController {
|
||||||
confirmDelete(statusViewModel: statusViewModel, redraft: redraft)
|
confirmDelete(statusViewModel: statusViewModel, redraft: redraft)
|
||||||
case let .report(reportViewModel):
|
case let .report(reportViewModel):
|
||||||
report(reportViewModel: reportViewModel)
|
report(reportViewModel: reportViewModel)
|
||||||
|
case let .accountListEdit(accountViewModel, edit):
|
||||||
|
accountListEdit(accountViewModel: accountViewModel, edit: edit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,6 +456,10 @@ private extension TableViewController {
|
||||||
present(alertController, animated: true)
|
present(alertController, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountListEdit(accountViewModel: AccountViewModel, edit: CollectionItemEvent.AccountListEdit) {
|
||||||
|
viewModel.applyAccountListEdit(viewModel: accountViewModel, edit: edit)
|
||||||
|
}
|
||||||
|
|
||||||
func set(expandAllState: ExpandAllState) {
|
func set(expandAllState: ExpandAllState) {
|
||||||
switch expandAllState {
|
switch expandAllState {
|
||||||
case .hidden:
|
case .hidden:
|
||||||
|
|
|
@ -12,4 +12,12 @@ public enum CollectionItemEvent {
|
||||||
case confirmDelete(StatusViewModel, redraft: Bool)
|
case confirmDelete(StatusViewModel, redraft: Bool)
|
||||||
case report(ReportViewModel)
|
case report(ReportViewModel)
|
||||||
case share(URL)
|
case share(URL)
|
||||||
|
case accountListEdit(AccountViewModel, AccountListEdit)
|
||||||
|
}
|
||||||
|
|
||||||
|
public extension CollectionItemEvent {
|
||||||
|
enum AccountListEdit {
|
||||||
|
case acceptFollowRequest
|
||||||
|
case rejectFollowRequest
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ public final class AccountViewModel: CollectionItemViewModel, ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension AccountViewModel {
|
public extension AccountViewModel {
|
||||||
|
var id: Account.Id { accountService.account.id }
|
||||||
|
|
||||||
var headerURL: URL {
|
var headerURL: URL {
|
||||||
if !identityContext.appPreferences.shouldReduceMotion, identityContext.appPreferences.animateHeaders {
|
if !identityContext.appPreferences.shouldReduceMotion, identityContext.appPreferences.animateHeaders {
|
||||||
return accountService.account.header
|
return accountService.account.header
|
||||||
|
@ -140,27 +142,11 @@ public extension AccountViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
func acceptFollowRequest() {
|
func acceptFollowRequest() {
|
||||||
ignorableOutputEvent(
|
accountListEdit(accountService.acceptFollowRequest(), event: .acceptFollowRequest)
|
||||||
accountService.acceptFollowRequest()
|
|
||||||
.collect()
|
|
||||||
.flatMap { [weak self] _ -> AnyPublisher<Never, Error> in
|
|
||||||
guard let self = self else { return Empty().eraseToAnyPublisher() }
|
|
||||||
|
|
||||||
return self.identityContext.service.verifyCredentials()
|
|
||||||
}
|
|
||||||
.eraseToAnyPublisher())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func rejectFollowRequest() {
|
func rejectFollowRequest() {
|
||||||
ignorableOutputEvent(
|
accountListEdit(accountService.rejectFollowRequest(), event: .rejectFollowRequest)
|
||||||
accountService.rejectFollowRequest()
|
|
||||||
.collect()
|
|
||||||
.flatMap { [weak self] _ -> AnyPublisher<Never, Error> in
|
|
||||||
guard let self = self else { return Empty().eraseToAnyPublisher() }
|
|
||||||
|
|
||||||
return self.identityContext.service.verifyCredentials()
|
|
||||||
}
|
|
||||||
.eraseToAnyPublisher())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func domainBlock() {
|
func domainBlock() {
|
||||||
|
@ -176,4 +162,15 @@ private extension AccountViewModel {
|
||||||
func ignorableOutputEvent(_ action: AnyPublisher<Never, Error>) {
|
func ignorableOutputEvent(_ action: AnyPublisher<Never, Error>) {
|
||||||
eventsSubject.send(action.map { _ in .ignorableOutput }.eraseToAnyPublisher())
|
eventsSubject.send(action.map { _ in .ignorableOutput }.eraseToAnyPublisher())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountListEdit(_ action: AnyPublisher<Never, Error>, event: CollectionItemEvent.AccountListEdit) {
|
||||||
|
eventsSubject.send(
|
||||||
|
action.collect()
|
||||||
|
.map { [weak self] _ -> CollectionItemEvent in
|
||||||
|
guard let self = self else { return .ignorableOutput }
|
||||||
|
|
||||||
|
return .accountListEdit(self, .acceptFollowRequest)
|
||||||
|
}
|
||||||
|
.eraseToAnyPublisher())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,6 +321,20 @@ extension CollectionItemsViewModel: CollectionViewModel {
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func applyAccountListEdit(viewModel: AccountViewModel, edit: CollectionItemEvent.AccountListEdit) {
|
||||||
|
(collectionService as? AccountListService)?.remove(id: viewModel.id)
|
||||||
|
|
||||||
|
switch edit {
|
||||||
|
case .acceptFollowRequest, .rejectFollowRequest:
|
||||||
|
identityContext.service.verifyCredentials()
|
||||||
|
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||||
|
.sink { _ in }
|
||||||
|
.store(in: &cancellables)
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension CollectionItemsViewModel {
|
private extension CollectionItemsViewModel {
|
||||||
|
|
|
@ -21,4 +21,5 @@ public protocol CollectionViewModel {
|
||||||
func canSelect(indexPath: IndexPath) -> Bool
|
func canSelect(indexPath: IndexPath) -> Bool
|
||||||
func viewModel(indexPath: IndexPath) -> CollectionItemViewModel
|
func viewModel(indexPath: IndexPath) -> CollectionItemViewModel
|
||||||
func toggleExpandAll()
|
func toggleExpandAll()
|
||||||
|
func applyAccountListEdit(viewModel: AccountViewModel, edit: CollectionItemEvent.AccountListEdit)
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,4 +139,8 @@ extension ProfileViewModel: CollectionViewModel {
|
||||||
public func toggleExpandAll() {
|
public func toggleExpandAll() {
|
||||||
collectionViewModel.value.toggleExpandAll()
|
collectionViewModel.value.toggleExpandAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func applyAccountListEdit(viewModel: AccountViewModel, edit: CollectionItemEvent.AccountListEdit) {
|
||||||
|
collectionViewModel.value.applyAccountListEdit(viewModel: viewModel, edit: edit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ extension AccountView: UITextViewDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension AccountView {
|
private extension AccountView {
|
||||||
|
// swiftlint:disable:next function_body_length
|
||||||
func initialSetup() {
|
func initialSetup() {
|
||||||
let stackView = UIStackView()
|
let stackView = UIStackView()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue