// // SuggestionAccountViewModel.swift // Mastodon // // Created by sxiaojian on 2021/4/21. // import Combine import MastodonSDK import MastodonCore import UIKit protocol SuggestionAccountViewModelDelegate: AnyObject { var homeTimelineNeedRefresh: PassthroughSubject { get } } final class SuggestionAccountViewModel: NSObject { var disposeBag = Set() weak var delegate: SuggestionAccountViewModelDelegate? // input let context: AppContext let authContext: AuthContext @Published var accounts: [Mastodon.Entity.V2.SuggestionAccount] = [] var relationships: [Mastodon.Entity.Relationship] = [] var viewWillAppear = PassthroughSubject() // output var tableViewDiffableDataSource: UITableViewDiffableDataSource? @Published var records = [Mastodon.Entity.Account]() init( context: AppContext, authContext: AuthContext ) { self.context = context self.authContext = authContext // ) super.init() updateSuggestions() } func updateSuggestions() { Task { var users: [Mastodon.Entity.Account] = [] var suggestedAccounts = [Mastodon.Entity.V2.SuggestionAccount]() do { let response = try await context.apiService.suggestionAccountV2( query: .init(limit: 5), authenticationBox: authContext.mastodonAuthenticationBox ) suggestedAccounts = response.value guard suggestedAccounts.isNotEmpty else { return } let accounts = suggestedAccounts.compactMap { $0.account } let relationships = try await context.apiService.relationship( forAccounts: accounts, authenticationBox: authContext.mastodonAuthenticationBox ).value // users = response.value.map { $0 } self.relationships = relationships self.accounts = suggestedAccounts } catch { self.relationships = [] self.accounts = [] } guard users.isNotEmpty else { return } records = users } // fetch relationship $records .removeDuplicates() .sink { [weak self] records in guard let self else { return } Task { _ = try await self.context.apiService.relationship( records: records, authenticationBox: self.authContext.mastodonAuthenticationBox ) } } .store(in: &disposeBag) } func setupDiffableDataSource( tableView: UITableView, suggestionAccountTableViewCellDelegate: SuggestionAccountTableViewCellDelegate ) { tableViewDiffableDataSource = RecommendAccountSection.tableViewDiffableDataSource( tableView: tableView, context: context, configuration: RecommendAccountSection.Configuration( authContext: authContext, suggestionAccountTableViewCellDelegate: suggestionAccountTableViewCellDelegate ) ) $accounts .receive(on: DispatchQueue.main) .sink { [weak self] suggestedAccounts in guard let self, let tableViewDiffableDataSource = self.tableViewDiffableDataSource else { return } let accounts = suggestedAccounts.compactMap { $0.account } let accountsWithRelationship: [(account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?)] = accounts.compactMap { account in guard let relationship = self.relationships.first(where: {$0.id == account.id }) else { return (account: account, relationship: nil)} return (account: account, relationship: relationship) } var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) let items: [RecommendAccountItem] = accountsWithRelationship.map { RecommendAccountItem.account($0.account, relationship: $0.relationship) } snapshot.appendItems(items, toSection: .main) tableViewDiffableDataSource.applySnapshotUsingReloadData(snapshot) } .store(in: &disposeBag) } func followAllSuggestedAccounts(_ dependency: NeedsDependency & AuthContextProvider, presentedOn: UIViewController?, completion: (() -> Void)? = nil) { let tmpAccounts = accounts.compactMap { $0.account } Task { await dependency.coordinator.showLoading(on: presentedOn) await withTaskGroup(of: Void.self, body: { taskGroup in // for user in records { for account in tmpAccounts { taskGroup.addTask { try? await DataSourceFacade.responseToUserViewButtonAction( dependency: dependency, user: account, buttonState: .follow ) } } // } }) delegate?.homeTimelineNeedRefresh.send() completion?() } } }