// // HashtagTimelineViewModel.swift // Mastodon // // Created by BradGao on 2021/3/30. // import UIKit import Combine import CoreData import CoreDataStack import GameplayKit import MastodonSDK import MastodonCore final class HashtagTimelineViewModel { let hashtag: String var disposeBag = Set() var needLoadMiddleIndex: Int? = nil // input let context: AppContext let authContext: AuthContext let fetchedResultsController: StatusFetchedResultsController let isFetchingLatestTimeline = CurrentValueSubject(false) let timelinePredicate = CurrentValueSubject(nil) let hashtagEntity = CurrentValueSubject(nil) let listBatchFetchViewModel = ListBatchFetchViewModel() // output var diffableDataSource: UITableViewDiffableDataSource? let didLoadLatest = PassthroughSubject() let hashtagDetails = CurrentValueSubject(nil) // bottom loader private(set) lazy var stateMachine: GKStateMachine = { // exclude timeline middle fetcher state let stateMachine = GKStateMachine(states: [ State.Initial(viewModel: self), State.Reloading(viewModel: self), State.Fail(viewModel: self), State.Idle(viewModel: self), State.Loading(viewModel: self), State.NoMore(viewModel: self), ]) stateMachine.enter(State.Initial.self) return stateMachine }() init(context: AppContext, authContext: AuthContext, hashtag: String) { self.context = context self.authContext = authContext self.hashtag = hashtag self.fetchedResultsController = StatusFetchedResultsController( managedObjectContext: context.managedObjectContext, domain: authContext.mastodonAuthenticationBox.domain, additionalTweetPredicate: nil ) updateTagInformation() // end init } func viewWillAppear() { let predicate = Tag.predicate( domain: authContext.mastodonAuthenticationBox.domain, name: hashtag ) guard let object = Tag.findOrFetch(in: context.managedObjectContext, matching: predicate) else { return hashtagDetails.send(hashtagDetails.value?.copy(following: false)) } hashtagDetails.send(hashtagDetails.value?.copy(following: object.following)) } } extension HashtagTimelineViewModel { func followTag() { self.hashtagDetails.send(hashtagDetails.value?.copy(following: true)) Task { @MainActor in let tag = try? await context.apiService.followTag( for: hashtag, authenticationBox: authContext.mastodonAuthenticationBox ).value self.hashtagDetails.send(tag) } } func unfollowTag() { self.hashtagDetails.send(hashtagDetails.value?.copy(following: false)) Task { @MainActor in let tag = try? await context.apiService.unfollowTag( for: hashtag, authenticationBox: authContext.mastodonAuthenticationBox ).value self.hashtagDetails.send(tag) } } } private extension HashtagTimelineViewModel { func updateTagInformation() { Task { @MainActor in let tag = try? await context.apiService.getTagInformation( for: hashtag, authenticationBox: authContext.mastodonAuthenticationBox ).value self.hashtagDetails.send(tag) } } }