Kurdtvs-Live-Kurdish-TV-Kur.../Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift

113 lines
4.0 KiB
Swift
Raw Normal View History

2021-01-28 09:10:30 +01:00
//
// PublicTimelineViewModel.swift
// Mastodon
//
// Created by sxiaojian on 2021/1/27.
//
2021-02-02 12:04:24 +01:00
import AlamofireImage
2021-01-28 09:10:30 +01:00
import Combine
import CoreData
import CoreDataStack
2021-02-02 12:04:24 +01:00
import GameplayKit
2021-01-28 09:10:30 +01:00
import MastodonSDK
2021-02-02 12:04:24 +01:00
import os.log
import UIKit
2021-01-28 09:10:30 +01:00
class PublicTimelineViewModel: NSObject {
var disposeBag = Set<AnyCancellable>()
// input
let context: AppContext
let fetchedResultsController: NSFetchedResultsController<Toot>
2021-02-04 08:09:58 +01:00
2021-02-02 12:04:24 +01:00
let isFetchingLatestTimeline = CurrentValueSubject<Bool, Never>(false)
2021-01-28 09:10:30 +01:00
2021-02-04 08:09:58 +01:00
// middle loader
let loadMiddleSateMachineList = CurrentValueSubject<[String: GKStateMachine], Never>([:])
weak var tableView: UITableView?
//
var tootIDsWhichHasGap = [String]()
2021-01-28 09:10:30 +01:00
// output
var diffableDataSource: UITableViewDiffableDataSource<TimelineSection, Item>?
2021-02-02 12:04:24 +01:00
lazy var stateMachine: GKStateMachine = {
let stateMachine = GKStateMachine(states: [
State.Initial(viewModel: self),
State.Loading(viewModel: self),
State.Fail(viewModel: self),
State.Idle(viewModel: self),
State.LoadingMore(viewModel: self),
])
stateMachine.enter(State.Initial.self)
return stateMachine
}()
let tootIDs = CurrentValueSubject<[String], Never>([])
2021-01-28 09:10:30 +01:00
let items = CurrentValueSubject<[Item], Never>([])
var cellFrameCache = NSCache<NSNumber, NSValue>()
init(context: AppContext) {
self.context = context
self.fetchedResultsController = {
let fetchRequest = Toot.sortedFetchRequest
fetchRequest.predicate = Toot.predicate(domain: "", ids: [])
2021-01-28 09:10:30 +01:00
fetchRequest.returnsObjectsAsFaults = false
fetchRequest.fetchBatchSize = 20
let controller = NSFetchedResultsController(
fetchRequest: fetchRequest,
managedObjectContext: context.managedObjectContext,
sectionNameKeyPath: nil,
cacheName: nil
)
return controller
}()
super.init()
2021-02-02 12:04:24 +01:00
fetchedResultsController.delegate = self
2021-01-28 09:10:30 +01:00
items
.receive(on: DispatchQueue.main)
.debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
.sink { [weak self] items in
guard let self = self else { return }
guard let diffableDataSource = self.diffableDataSource else { return }
2021-02-02 12:04:24 +01:00
os_log("%{public}s[%{public}ld], %{public}s: items did change", (#file as NSString).lastPathComponent, #line, #function)
2021-01-28 09:10:30 +01:00
var snapshot = NSDiffableDataSourceSnapshot<TimelineSection, Item>()
snapshot.appendSections([.main])
snapshot.appendItems(items)
2021-02-03 06:01:50 +01:00
if let currentState = self.stateMachine.currentState {
switch currentState {
case is State.Idle, is State.LoadingMore, is State.Fail:
snapshot.appendItems([.bottomLoader], toSection: .main)
default:
break
}
}
2021-01-28 09:10:30 +01:00
diffableDataSource.apply(snapshot, animatingDifferences: !items.isEmpty)
}
.store(in: &disposeBag)
tootIDs
2021-01-28 09:10:30 +01:00
.receive(on: DispatchQueue.main)
.sink { [weak self] ids in
guard let self = self else { return }
let domain = self.context.authenticationService.activeMastodonAuthenticationBox.value?.domain ?? ""
self.fetchedResultsController.fetchRequest.predicate = Toot.predicate(domain: domain, ids: ids)
2021-01-28 09:10:30 +01:00
do {
try self.fetchedResultsController.performFetch()
} catch {
assertionFailure(error.localizedDescription)
}
}
.store(in: &disposeBag)
}
deinit {
2021-02-02 12:04:24 +01:00
os_log("%{public}s[%{public}ld], %{public}s", (#file as NSString).lastPathComponent, #line, #function)
2021-01-28 09:10:30 +01:00
}
}