diff --git a/Signal/src/ViewControllers/HomeView/Chat List/CLVLoader.swift b/Signal/src/ViewControllers/HomeView/Chat List/CLVLoader.swift index efe2494cb3..446ad02d12 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/CLVLoader.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/CLVLoader.swift @@ -169,10 +169,12 @@ public class CLVLoader: Dependencies { lastRenderState: CLVRenderState, transaction: SDSAnyReadTransaction) -> CLVLoadResult { do { - return try loadRenderStateAndDiffInternal(viewInfo: viewInfo, - updatedItemIds: updatedItemIds, - lastRenderState: lastRenderState, - transaction: transaction) + return try loadRenderStateAndDiffInternal( + viewInfo: viewInfo, + updatedItemIds: updatedItemIds, + lastRenderState: lastRenderState, + transaction: transaction + ) } catch { owsFailDebug("Error: \(error)") // Fail over to reloading the table view with a new render state. @@ -180,6 +182,11 @@ public class CLVLoader: Dependencies { } } + static func newRenderStateWithViewInfo(_ viewInfo: CLVViewInfo, lastRenderState: CLVRenderState) -> CLVLoadResult { + let renderState = CLVRenderState(viewInfo: viewInfo, pinnedThreads: lastRenderState.pinnedThreads, unpinnedThreads: lastRenderState.unpinnedThreads) + return .renderStateWithRowChanges(renderState: renderState, rowChanges: []) + } + private static func loadRenderStateAndDiffInternal(viewInfo: CLVViewInfo, updatedItemIds allUpdatedItemIds: Set, lastRenderState: CLVRenderState, diff --git a/Signal/src/ViewControllers/HomeView/Chat List/CLVRenderState.swift b/Signal/src/ViewControllers/HomeView/Chat List/CLVRenderState.swift index 76005c15e7..44642f4b46 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/CLVRenderState.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/CLVRenderState.swift @@ -151,12 +151,13 @@ struct CLVViewInfo: Equatable { let archiveCount: UInt let inboxCount: UInt let inboxFilter: InboxFilter? + let isMultiselectActive: Bool let hasVisibleReminders: Bool let lastSelectedThreadId: String? let requiredVisibleThreadIds: Set var hasArchivedThreadsRow: Bool { - chatListMode == .inbox && inboxFilter == nil && archiveCount > 0 + chatListMode == .inbox && !isMultiselectActive && inboxFilter == nil && archiveCount > 0 } static var empty: CLVViewInfo { @@ -165,6 +166,7 @@ struct CLVViewInfo: Equatable { archiveCount: 0, inboxCount: 0, inboxFilter: nil, + isMultiselectActive: false, hasVisibleReminders: false, lastSelectedThreadId: nil, requiredVisibleThreadIds: [] @@ -174,6 +176,7 @@ struct CLVViewInfo: Equatable { static func build( chatListMode: ChatListMode, inboxFilter: InboxFilter?, + isMultiselectActive: Bool, lastSelectedThreadId: String?, hasVisibleReminders: Bool, transaction: SDSAnyReadTransaction @@ -192,6 +195,7 @@ struct CLVViewInfo: Equatable { archiveCount: archiveCount, inboxCount: inboxCount, inboxFilter: inboxFilter, + isMultiselectActive: isMultiselectActive, hasVisibleReminders: hasVisibleReminders, lastSelectedThreadId: lastSelectedThreadId, requiredVisibleThreadIds: requiredThreadIds diff --git a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Loading.swift b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Loading.swift index 78da0cc36f..b85d6faa93 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Loading.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Loading.swift @@ -54,6 +54,11 @@ extension ChatListViewController { return CLVLoader.loadRenderStateForReset(viewInfo: viewInfo, transaction: transaction) } + fileprivate func copyRenderStateAndDiff(viewInfo: CLVViewInfo) -> CLVLoadResult { + AssertIsOnMainThread() + return CLVLoader.newRenderStateWithViewInfo(viewInfo, lastRenderState: renderState) + } + fileprivate func loadNewRenderStateWithDiff(viewInfo: CLVViewInfo, updatedThreadIds: Set, transaction: SDSAnyReadTransaction) -> CLVLoadResult { @@ -100,11 +105,6 @@ extension ChatListViewController { fileprivate func applyRowChanges(_ rowChanges: [CLVRowChange], renderState: CLVRenderState, animated: Bool) { AssertIsOnMainThread() - guard !rowChanges.isEmpty else { - owsFailDebug("Empty rowChanges.") - return - } - let sectionDifference = renderState.sections.difference(from: tableDataSource.renderState.sections, by: { $0.type == $1.type }) let isChangingFilter = tableDataSource.renderState.viewInfo.inboxFilter != renderState.viewInfo.inboxFilter tableDataSource.renderState = renderState @@ -212,7 +212,7 @@ extension ChatListViewController { private enum CLVLoadType { case resetAll case incrementalDiff(updatedThreadIds: Set) - case reloadTableOnly + case incrementalWithoutThreadUpdates case none } @@ -234,26 +234,27 @@ public class CLVLoadCoordinator: Dependencies { func build( chatListMode: ChatListMode, inboxFilter: InboxFilter?, + isMultiselectActive: Bool, lastSelectedThreadId: String?, hasVisibleReminders: Bool, - canApplyRowChanges: Bool, lastViewInfo: CLVViewInfo, transaction: SDSAnyReadTransaction ) -> CLVLoadInfo { let viewInfo = CLVViewInfo.build( chatListMode: chatListMode, inboxFilter: inboxFilter, + isMultiselectActive: isMultiselectActive, lastSelectedThreadId: lastSelectedThreadId, hasVisibleReminders: hasVisibleReminders, transaction: transaction ) - if shouldResetAll || !canApplyRowChanges { + if shouldResetAll { return CLVLoadInfo(viewInfo: viewInfo, loadType: .resetAll) } else if !updatedThreadIds.isEmpty || viewInfo.inboxFilter != lastViewInfo.inboxFilter { return CLVLoadInfo(viewInfo: viewInfo, loadType: .incrementalDiff(updatedThreadIds: updatedThreadIds)) } else if viewInfo != lastViewInfo { - return CLVLoadInfo(viewInfo: viewInfo, loadType: .reloadTableOnly) + return CLVLoadInfo(viewInfo: viewInfo, loadType: .incrementalWithoutThreadUpdates) } else { return CLVLoadInfo(viewInfo: viewInfo, loadType: .none) } @@ -336,14 +337,12 @@ public class CLVLoadCoordinator: Dependencies { let loadResult: CLVLoadResult = databaseStorage.read { transaction in // Decide what kind of load we prefer. - let canApplyRowChanges = viewController.tableDataSource.renderState.visibleThreadCount > 0 - let loadInfo = loadInfoBuilder.build( chatListMode: viewController.viewState.chatListMode, inboxFilter: viewController.viewState.inboxFilter, + isMultiselectActive: viewController.viewState.multiSelectState.isActive, lastSelectedThreadId: viewController.viewState.lastSelectedThreadId, hasVisibleReminders: hasVisibleReminders, - canApplyRowChanges: canApplyRowChanges, lastViewInfo: viewController.renderState.viewInfo, transaction: transaction ) @@ -368,8 +367,8 @@ public class CLVLoadCoordinator: Dependencies { transaction: transaction ) - case .reloadTableOnly: - return .reloadTable + case .incrementalWithoutThreadUpdates: + return viewController.copyRenderStateAndDiff(viewInfo: loadInfo.viewInfo) case .none: return .noChanges diff --git a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Multiselect.swift b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Multiselect.swift index e8a12ba6f0..c15cb4b504 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Multiselect.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Multiselect.swift @@ -39,6 +39,7 @@ extension ChatListViewController { searchBar.alpha = 0.5 viewState.multiSelectState.setIsActive(true, tableView: tableView, cancelCurrentEditAction: cancelCurrentEditAction) showToolbar() + loadCoordinator.loadIfNecessary(shouldForceLoad: true) } func leaveMultiselectMode() { @@ -58,6 +59,7 @@ extension ChatListViewController { viewState.multiSelectState.setIsActive(false, tableView: tableView) title = viewState.multiSelectState.title hideToolbar() + loadCoordinator.loadIfNecessary(shouldForceLoad: true) if let lastViewedThread, isConversationActive(forThread: lastViewedThread) { ensureSelectedThread(lastViewedThread, animated: false)