// // DiscoveryForYouViewModel.swift // Mastodon // // Created by MainasuK on 2022-4-14. // import UIKit import Combine import GameplayKit import MastodonSDK import MastodonCore final class DiscoveryForYouViewModel { var disposeBag = Set() // input let context: AppContext let authContext: AuthContext @MainActor @Published var familiarFollowers: [Mastodon.Entity.FamiliarFollowers] = [] @Published var isFetching = false @Published var accounts: [Mastodon.Entity.Account] var relationships: [Mastodon.Entity.Relationship] // output var diffableDataSource: UITableViewDiffableDataSource? let didLoadLatest = PassthroughSubject() init(context: AppContext, authContext: AuthContext) { self.context = context self.authContext = authContext self.accounts = [] self.relationships = [] } } extension DiscoveryForYouViewModel { @MainActor func fetch() async throws { guard isFetching == false else { return } isFetching = true defer { isFetching = false } do { let suggestedAccounts = try await fetchSuggestionAccounts() let familiarFollowersResponse = try? await context.apiService.familiarFollowers( query: .init(ids: suggestedAccounts.compactMap { $0.id }), authenticationBox: authContext.mastodonAuthenticationBox ).value let relationships = try? await context.apiService.relationship( forAccounts: suggestedAccounts, authenticationBox: authContext.mastodonAuthenticationBox ).value familiarFollowers = familiarFollowersResponse ?? [] accounts = suggestedAccounts self.relationships = relationships ?? [] } catch { // do nothing } await MainActor.run { guard let diffableDataSource = self.diffableDataSource else { return } var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.forYou]) let items = self.accounts.map { account in let relationship = relationships.first { $0.id == account.id } ?? nil return DiscoveryItem.account(account, relationship: relationship) } snapshot.appendItems(items, toSection: .forYou) diffableDataSource.apply(snapshot, animatingDifferences: false) } } private func fetchSuggestionAccounts() async throws -> [Mastodon.Entity.Account] { do { let response = try await context.apiService.suggestionAccountV2( query: nil, authenticationBox: authContext.mastodonAuthenticationBox ).value return response.compactMap { $0.account } } catch { // fallback V1 let response = try await context.apiService.suggestionAccount( query: nil, authenticationBox: authContext.mastodonAuthenticationBox ).value return response } } }