mastodon-ios/Mastodon/Scene/Report/ReportViewModel+Data.swift

139 lines
5.7 KiB
Swift

//
// ReportViewModel+Data.swift
// Mastodon
//
// Created by ihugo on 2021/4/20.
//
import Combine
import CoreData
import CoreDataStack
import Foundation
import MastodonSDK
import UIKit
import os.log
extension ReportViewModel {
func requestRecentStatus(
domain: String,
accountId: String,
authorizationBox: MastodonAuthenticationBox
) {
context.apiService.userTimeline(
domain: domain,
accountID: accountId,
excludeReblogs: true,
authorizationBox: authorizationBox
)
.receive(on: DispatchQueue.main)
.sink { [weak self] completion in
switch completion {
case .failure(let error):
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch user timeline fail: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
guard let self = self else { return }
guard let reportStatusId = self.status?.id else { return }
var statusIDs = self.statusFetchedResultsController.statusIDs.value
guard statusIDs.contains(reportStatusId) else { return }
statusIDs.append(reportStatusId)
self.statusFetchedResultsController.statusIDs.value = statusIDs
case .finished:
break
}
} receiveValue: { [weak self] response in
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
guard let self = self else { return }
var statusIDs = response.value.map { $0.id }
if let reportStatusId = self.status?.id, !statusIDs.contains(reportStatusId) {
statusIDs.append(reportStatusId)
}
self.statusFetchedResultsController.statusIDs.value = statusIDs
}
.store(in: &disposeBag)
}
func fetchStatus() {
let managedObjectContext = self.statusFetchedResultsController.fetchedResultsController.managedObjectContext
statusFetchedResultsController.objectIDs.eraseToAnyPublisher()
.receive(on: DispatchQueue.main)
.debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
.sink { [weak self] objectIDs in
guard let self = self else { return }
guard let diffableDataSource = self.diffableDataSource else { return }
var items: [Item] = []
var snapshot = NSDiffableDataSourceSnapshot<ReportSection, Item>()
snapshot.appendSections([.main])
defer {
// not animate when empty items fix loader first appear layout issue
diffableDataSource.apply(snapshot, animatingDifferences: !items.isEmpty)
}
var oldSnapshotAttributeDict: [NSManagedObjectID : Item.ReportStatusAttribute] = [:]
let oldSnapshot = diffableDataSource.snapshot()
for item in oldSnapshot.itemIdentifiers {
guard case let .reportStatus(objectID, attribute) = item else { continue }
oldSnapshotAttributeDict[objectID] = attribute
}
for objectID in objectIDs {
let attribute = oldSnapshotAttributeDict[objectID] ?? Item.ReportStatusAttribute()
let item = Item.reportStatus(objectID: objectID, attribute: attribute)
items.append(item)
guard let status = managedObjectContext.object(with: objectID) as? Status else {
continue
}
if status.id == self.status?.id {
attribute.isSelected = true
self.append(statusID: status.id)
self.continueEnableSubject.send(true)
}
}
snapshot.appendItems(items, toSection: .main)
}
.store(in: &disposeBag)
}
func prefetchData(prefetchRowsAt indexPaths: [IndexPath]) {
guard let diffableDataSource = diffableDataSource else { return }
// prefetch reply status
guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
let domain = activeMastodonAuthenticationBox.domain
var statusObjectIDs: [NSManagedObjectID] = []
for indexPath in indexPaths {
let item = diffableDataSource.itemIdentifier(for: indexPath)
switch item {
case .reportStatus(let objectID, _):
statusObjectIDs.append(objectID)
default:
continue
}
}
let backgroundManagedObjectContext = context.backgroundManagedObjectContext
backgroundManagedObjectContext.perform { [weak self] in
guard let self = self else { return }
for objectID in statusObjectIDs {
let status = backgroundManagedObjectContext.object(with: objectID) as! Status
guard let replyToID = status.inReplyToID, status.replyTo == nil else {
// skip
continue
}
self.context.statusPrefetchingService.prefetchReplyTo(
domain: domain,
statusObjectID: status.objectID,
statusID: status.id,
replyToStatusID: replyToID,
authorizationBox: activeMastodonAuthenticationBox
)
}
}
}
}