// // NotificationTimelineViewModel+Diffable.swift // Mastodon // // Created by MainasuK on 2022-1-21. // import UIKit import CoreData import MastodonSDK extension NotificationTimelineViewModel { func setupDiffableDataSource( tableView: UITableView, notificationTableViewCellDelegate: NotificationTableViewCellDelegate ) { diffableDataSource = NotificationSection.diffableDataSource( tableView: tableView, context: context, configuration: NotificationSection.Configuration( authContext: authContext, notificationTableViewCellDelegate: notificationTableViewCellDelegate, filterContext: .notifications, activeFilters: context.statusFilterService.$activeFilters ) ) var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) diffableDataSource?.apply(snapshot) dataController.$records .receive(on: DispatchQueue.main) .sink { [weak self] records in guard let self = self else { return } guard let diffableDataSource = self.diffableDataSource else { return } Task { let oldSnapshot = diffableDataSource.snapshot() var newSnapshot: NSDiffableDataSourceSnapshot = { let newItems = records.map { record in NotificationItem.feed(record: record) } var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) snapshot.appendItems(newItems.removingDuplicates(), toSection: .main) return snapshot }() let anchors: [MastodonFeed] = records.filter { $0.hasMore == true } let itemIdentifiers = newSnapshot.itemIdentifiers for (index, item) in itemIdentifiers.enumerated() { guard case let .feed(record) = item else { continue } guard anchors.contains(where: { feed in feed.id == record.id }) else { continue } let isLast = index + 1 == itemIdentifiers.count if isLast { newSnapshot.insertItems([.bottomLoader], afterItem: item) } else { newSnapshot.insertItems([.feedLoader(record: record)], afterItem: item) } } let hasChanges = newSnapshot.itemIdentifiers != oldSnapshot.itemIdentifiers if !hasChanges { self.didLoadLatest.send() return } await self.updateSnapshotUsingReloadData(snapshot: newSnapshot) self.didLoadLatest.send() } // end Task } .store(in: &disposeBag) } // end func setupDiffableDataSource } extension NotificationTimelineViewModel { @MainActor func updateDataSource( snapshot: NSDiffableDataSourceSnapshot, animatingDifferences: Bool ) async { await diffableDataSource?.apply(snapshot, animatingDifferences: animatingDifferences) } @MainActor func updateSnapshotUsingReloadData( snapshot: NSDiffableDataSourceSnapshot ) async { await self.diffableDataSource?.applySnapshotUsingReloadData(snapshot) } }