diff --git a/Signal/src/ViewControllers/HomeView/HVTableDataSource.swift b/Signal/src/ViewControllers/HomeView/HVTableDataSource.swift index 5b60ff1d06..eb8a017267 100644 --- a/Signal/src/ViewControllers/HomeView/HVTableDataSource.swift +++ b/Signal/src/ViewControllers/HomeView/HVTableDataSource.swift @@ -22,6 +22,8 @@ public class HVTableDataSource: NSObject { fileprivate var lastReloadDate: Date? { tableView.lastReloadDate } + fileprivate var lastPreloadCellDate: Date? + public required override init() { super.init() } @@ -73,12 +75,6 @@ extension HVTableDataSource { extension HVTableDataSource: UIScrollViewDelegate { - public func scrollViewDidScroll(_ scrollView: UIScrollView) { - AssertIsOnMainThread() - - preloadCellsIfNecessary() - } - private func preloadCellsIfNecessary() { AssertIsOnMainThread() @@ -86,16 +82,29 @@ extension HVTableDataSource: UIScrollViewDelegate { owsFailDebug("Missing viewController.") return } - let newContentOffset = tableView.contentOffset - defer { - viewController.lastKnownTableViewContentOffset = newContentOffset + guard viewController.hasEverAppeared else { + return } - guard let oldContentOffset = viewController.lastKnownTableViewContentOffset else { + let newContentOffset = tableView.contentOffset + let oldContentOffset = viewController.lastKnownTableViewContentOffset + viewController.lastKnownTableViewContentOffset = newContentOffset + guard let oldContentOffset = oldContentOffset else { return } let deltaY = (newContentOffset - oldContentOffset).y + guard deltaY != 0 else { + return + } let isScrollingDownward = deltaY > 0 + // Debounce. + let maxPreloadFrequency: TimeInterval = kSecondInterval / 100 + if let lastPreloadCellDate = self.lastPreloadCellDate, + abs(lastPreloadCellDate.timeIntervalSinceNow) < maxPreloadFrequency { + return + } + lastPreloadCellDate = Date() + guard let visibleIndexPaths = tableView.indexPathsForVisibleRows else { owsFailDebug("Missing visibleIndexPaths.") return @@ -129,6 +138,7 @@ extension HVTableDataSource: UIScrollViewDelegate { indexPathsToPreload.append(indexPath) } + let preloadCount: Int = 3 if isScrollingDownward { guard let lastIndexPath = sortedIndexPaths.last else { owsFailDebug("Missing indexPath.") @@ -136,12 +146,11 @@ extension HVTableDataSource: UIScrollViewDelegate { } // Order matters; we want to preload in order of proximity // to viewport. - tryToEnqueue(IndexPath(row: lastIndexPath.row + 1, - section: lastIndexPath.section)) - tryToEnqueue(IndexPath(row: lastIndexPath.row + 2, - section: lastIndexPath.section)) - tryToEnqueue(IndexPath(row: lastIndexPath.row + 3, - section: lastIndexPath.section)) + for index in 0.. (ThreadViewModel, HVCellContentToken) in + guard nil == cellContentCache.get(key: cacheKey) else { + // If we already have an existing HVCellContentToken, abort. + throw HVPreloadError.alreadyLoaded + } // This is the expensive work we do off the main thread. let threadViewModel = Self.databaseStorage.read { transaction in ThreadViewModel(thread: thread, forHomeView: true, transaction: transaction) @@ -922,9 +936,16 @@ extension HVTableDataSource { Logger.info("contentToken already loaded.") } }.catch(on: .global()) { error in + if case HVPreloadError.alreadyLoaded = error { + return + } owsFailDebugUnlessNetworkFailure(error) } } + + private enum HVPreloadError: Error { + case alreadyLoaded + } } // MARK: - diff --git a/Signal/src/ViewControllers/HomeView/HomeViewCell.swift b/Signal/src/ViewControllers/HomeView/HomeViewCell.swift index e0757d1096..2c4c27b2d1 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewCell.swift +++ b/Signal/src/ViewControllers/HomeView/HomeViewCell.swift @@ -276,7 +276,7 @@ public class HomeViewCell: UITableViewCell { snippetLineHeight: snippetLineHeight) } - internal func configure(cellContentToken: HVCellContentToken) { + func configure(cellContentToken: HVCellContentToken) { AssertIsOnMainThread() OWSTableItem.configureCell(self)