mastodon-ios/Mastodon/Scene/Discovery/ForYou/DiscoveryForYouViewModel.swift

104 lines
3.2 KiB
Swift

//
// 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<AnyCancellable>()
// 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<DiscoverySection, DiscoveryItem>?
let didLoadLatest = PassthroughSubject<Void, Never>()
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<DiscoverySection, DiscoveryItem>()
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
}
}
}