diff --git a/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift b/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift index 8df022f7..bc41622a 100644 --- a/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsCollectionViewController.swift @@ -25,6 +25,8 @@ class NotificationsCollectionViewController: UIViewController, TimelineLikeColle private(set) var collectionView: UICollectionView! private(set) var dataSource: UICollectionViewDiffableDataSource! + var reconfigureVisibleItemsOnEndDecelerating: Bool = false + private var newer: RequestRange? private var older: RequestRange? @@ -662,6 +664,13 @@ extension NotificationsCollectionViewController: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) { MenuPreviewHelper.willPerformPreviewAction(animator: animator, presenter: self) } + + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + if reconfigureVisibleItemsOnEndDecelerating { + reconfigureVisibleItemsOnEndDecelerating = false + reconfigureVisibleCells() + } + } } extension NotificationsCollectionViewController: UICollectionViewDragDelegate { diff --git a/Tusker/Screens/Profile/ProfileStatusesViewController.swift b/Tusker/Screens/Profile/ProfileStatusesViewController.swift index 4ea79fef..0afde88d 100644 --- a/Tusker/Screens/Profile/ProfileStatusesViewController.swift +++ b/Tusker/Screens/Profile/ProfileStatusesViewController.swift @@ -32,6 +32,8 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie private(set) var dataSource: UICollectionViewDiffableDataSource! private(set) var headerCell: ProfileHeaderCollectionViewCell? + var reconfigureVisibleItemsOnEndDecelerating: Bool = false + private(set) var state: State = .unloaded init(accountID: String?, kind: Kind, owner: ProfileViewController) { @@ -627,6 +629,13 @@ extension ProfileStatusesViewController: UICollectionViewDelegate { return true } } + + func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { + if reconfigureVisibleItemsOnEndDecelerating { + reconfigureVisibleItemsOnEndDecelerating = false + reconfigureVisibleCells() + } + } } extension ProfileStatusesViewController: UICollectionViewDragDelegate { diff --git a/Tusker/Screens/Timeline/TimelineViewController.swift b/Tusker/Screens/Timeline/TimelineViewController.swift index 9c7bcf11..14c42986 100644 --- a/Tusker/Screens/Timeline/TimelineViewController.swift +++ b/Tusker/Screens/Timeline/TimelineViewController.swift @@ -42,6 +42,8 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro private(set) var collectionView: UICollectionView! private(set) var dataSource: UICollectionViewDiffableDataSource! + var reconfigureVisibleItemsOnEndDecelerating: Bool = false + private var cancellables = Set() private var userActivityNeedsUpdate = PassthroughSubject() // the last time this VC disappeared or the scene was backgrounded while it was active, used to decide if we want to check for present when reappearing @@ -1317,6 +1319,11 @@ extension TimelineViewController: UICollectionViewDelegate { func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { userActivityNeedsUpdate.send() + + if reconfigureVisibleItemsOnEndDecelerating { + reconfigureVisibleItemsOnEndDecelerating = false + reconfigureVisibleCells() + } } func scrollViewDidScroll(_ scrollView: UIScrollView) { diff --git a/Tusker/Screens/Utilities/TimelineLikeCollectionViewController.swift b/Tusker/Screens/Utilities/TimelineLikeCollectionViewController.swift index a75892a6..6cf2ae5b 100644 --- a/Tusker/Screens/Utilities/TimelineLikeCollectionViewController.swift +++ b/Tusker/Screens/Utilities/TimelineLikeCollectionViewController.swift @@ -21,6 +21,8 @@ protocol TimelineLikeCollectionViewController: UIViewController, TimelineLikeCon var collectionView: UICollectionView! { get } var dataSource: UICollectionViewDiffableDataSource! { get } + + var reconfigureVisibleItemsOnEndDecelerating: Bool { get set } } protocol TimelineLikeCollectionViewSection: Hashable, Sendable { @@ -125,6 +127,18 @@ extension TimelineLikeCollectionViewController { var config: ToastConfiguration if let error = error as? Self.Error, error == .allCaughtUp { + // Reconfigure visible items to update timestamps. + #if targetEnvironment(macCatalyst) + let isRefreshing = false + #else + let isRefreshing = collectionView.refreshControl?.isRefreshing ?? false + #endif + if isRefreshing { + reconfigureVisibleItemsOnEndDecelerating = true + } else { + reconfigureVisibleCells() + } + config = ToastConfiguration(title: "You're all caught up") config.edge = .top config.dismissAutomaticallyAfter = 2 @@ -204,6 +218,16 @@ extension TimelineLikeCollectionViewController { await task.value } + @MainActor + func reconfigureVisibleCells() { + let items = collectionView.indexPathsForVisibleItems.compactMap { dataSource.itemIdentifier(for: $0) } + if !items.isEmpty { + var snapshot = dataSource.snapshot() + snapshot.reconfigureItems(items) + dataSource.apply(snapshot, animatingDifferences: false) + } + } + func registerTimelineLikeCells() { collectionView.register(LoadingCollectionViewCell.self, forCellWithReuseIdentifier: "loadingIndicator") collectionView.register(ConfirmLoadMoreCollectionViewCell.self, forCellWithReuseIdentifier: "confirmLoadMore")