2021-04-12 10:31:53 +02:00
|
|
|
//
|
2021-06-22 12:28:27 +02:00
|
|
|
// NotificationViewModel+Diffable.swift
|
2021-04-12 10:31:53 +02:00
|
|
|
// Mastodon
|
|
|
|
//
|
|
|
|
// Created by sxiaojian on 2021/4/13.
|
|
|
|
//
|
|
|
|
|
|
|
|
import CoreData
|
|
|
|
import CoreDataStack
|
2021-04-15 04:16:30 +02:00
|
|
|
import os.log
|
|
|
|
import UIKit
|
2021-06-15 10:36:42 +02:00
|
|
|
import MastodonSDK
|
2021-04-12 10:31:53 +02:00
|
|
|
|
|
|
|
extension NotificationViewModel {
|
|
|
|
func setupDiffableDataSource(
|
2021-04-14 09:00:48 +02:00
|
|
|
for tableView: UITableView,
|
|
|
|
delegate: NotificationTableViewCellDelegate,
|
|
|
|
dependency: NeedsDependency
|
2021-04-12 10:31:53 +02:00
|
|
|
) {
|
2021-06-15 10:36:42 +02:00
|
|
|
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
|
2021-04-12 10:31:53 +02:00
|
|
|
.autoconnect()
|
|
|
|
.share()
|
|
|
|
.eraseToAnyPublisher()
|
2021-04-20 07:18:27 +02:00
|
|
|
|
2021-04-12 10:31:53 +02:00
|
|
|
diffableDataSource = NotificationSection.tableViewDiffableDataSource(
|
|
|
|
for: tableView,
|
|
|
|
timestampUpdatePublisher: timestampUpdatePublisher,
|
2021-04-14 09:00:48 +02:00
|
|
|
managedObjectContext: context.managedObjectContext,
|
|
|
|
delegate: delegate,
|
2021-04-20 07:18:27 +02:00
|
|
|
dependency: dependency
|
2021-04-12 10:31:53 +02:00
|
|
|
)
|
2021-06-22 11:58:11 +02:00
|
|
|
|
|
|
|
var snapshot = NSDiffableDataSourceSnapshot<NotificationSection, NotificationItem>()
|
|
|
|
snapshot.appendSections([.main])
|
|
|
|
diffableDataSource.apply(snapshot)
|
|
|
|
|
|
|
|
// workaround to append loader wrong animation issue
|
|
|
|
snapshot.appendItems([.bottomLoader], toSection: .main)
|
|
|
|
diffableDataSource.apply(snapshot)
|
2021-04-12 10:31:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extension NotificationViewModel: NSFetchedResultsControllerDelegate {
|
|
|
|
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
2021-04-15 04:16:30 +02:00
|
|
|
os_log("%{public}s[%{public}ld], %{public}s", (#file as NSString).lastPathComponent, #line, #function)
|
2021-04-12 10:31:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
|
2021-04-15 04:16:30 +02:00
|
|
|
os_log("%{public}s[%{public}ld], %{public}s", (#file as NSString).lastPathComponent, #line, #function)
|
2021-04-12 10:31:53 +02:00
|
|
|
|
|
|
|
guard let tableView = self.tableView else { return }
|
2021-04-15 04:16:30 +02:00
|
|
|
guard let navigationBar = contentOffsetAdjustableTimelineViewControllerDelegate?.navigationBar() else { return }
|
2021-04-12 10:31:53 +02:00
|
|
|
|
|
|
|
guard let diffableDataSource = self.diffableDataSource else { return }
|
|
|
|
|
2021-06-15 10:36:42 +02:00
|
|
|
let predicate: NSPredicate = {
|
|
|
|
let notificationTypePredicate = MastodonNotification.predicate(
|
|
|
|
validTypesRaws: Mastodon.Entity.Notification.NotificationType.knownCases.map { $0.rawValue }
|
|
|
|
)
|
|
|
|
return fetchedResultsController.fetchRequest.predicate.flatMap {
|
|
|
|
NSCompoundPredicate(andPredicateWithSubpredicates: [$0, notificationTypePredicate])
|
|
|
|
} ?? notificationTypePredicate
|
|
|
|
}()
|
2021-04-12 10:31:53 +02:00
|
|
|
let parentManagedObjectContext = fetchedResultsController.managedObjectContext
|
|
|
|
let managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
|
|
|
managedObjectContext.parent = parentManagedObjectContext
|
|
|
|
|
|
|
|
managedObjectContext.perform {
|
|
|
|
let notifications: [MastodonNotification] = {
|
|
|
|
let request = MastodonNotification.sortedFetchRequest
|
|
|
|
request.returnsObjectsAsFaults = false
|
|
|
|
request.predicate = predicate
|
|
|
|
do {
|
|
|
|
return try managedObjectContext.fetch(request)
|
|
|
|
} catch {
|
|
|
|
assertionFailure(error.localizedDescription)
|
|
|
|
return []
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
DispatchQueue.main.async {
|
2021-04-15 06:35:40 +02:00
|
|
|
let oldSnapshot = diffableDataSource.snapshot()
|
2021-04-20 07:18:27 +02:00
|
|
|
var oldSnapshotAttributeDict: [NSManagedObjectID : Item.StatusAttribute] = [:]
|
|
|
|
for item in oldSnapshot.itemIdentifiers {
|
|
|
|
guard case let .notification(objectID, attribute) = item else { continue }
|
|
|
|
oldSnapshotAttributeDict[objectID] = attribute
|
|
|
|
}
|
2021-04-15 06:35:40 +02:00
|
|
|
var newSnapshot = NSDiffableDataSourceSnapshot<NotificationSection, NotificationItem>()
|
|
|
|
newSnapshot.appendSections([.main])
|
2021-04-20 07:18:27 +02:00
|
|
|
let items: [NotificationItem] = notifications.map { notification in
|
|
|
|
let attribute: Item.StatusAttribute = oldSnapshotAttributeDict[notification.objectID] ?? Item.StatusAttribute()
|
|
|
|
return NotificationItem.notification(objectID: notification.objectID, attribute: attribute)
|
|
|
|
}
|
|
|
|
newSnapshot.appendItems(items, toSection: .main)
|
2021-04-15 06:35:40 +02:00
|
|
|
if !notifications.isEmpty, self.noMoreNotification.value == false {
|
|
|
|
newSnapshot.appendItems([.bottomLoader], toSection: .main)
|
|
|
|
}
|
2021-06-22 12:28:27 +02:00
|
|
|
|
|
|
|
self.isFetchingLatestNotification.value = false
|
|
|
|
|
|
|
|
diffableDataSource.apply(newSnapshot, animatingDifferences: false) { [weak self] in
|
|
|
|
guard let self = self else { return }
|
|
|
|
self.dataSourceDidUpdated.send()
|
2021-04-12 10:31:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-06-22 12:28:27 +02:00
|
|
|
|
2021-04-12 10:31:53 +02:00
|
|
|
}
|