Skip to content

Commit 199cee8

Browse files
committed
Fix chat folder duplication when switching Personal to All Chats
Root cause: background All Chats node kept paginating and applying stale transitions while Personal was selected. mapToQueue work from superseded location generations could merge against a desynced previousView. - Drop stale transitions when chatListLocationGeneration advances - Pause pagination on non-active folder tabs - Reset paginated location when a tab becomes active again - Force full list refresh when filter context changes - Stop scroll-syncing off-screen tabs during folder pan - Track selectTab async with MetaDisposable + generation guard Co-authored-by: D3C0Y <decoder-dev@users.noreply.github.com>
1 parent 39ef7ac commit 199cee8

3 files changed

Lines changed: 38 additions & 17 deletions

File tree

‎submodules/ChatListUI/Sources/ChatListController.swift‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
152152

153153
private let stateDisposable = MetaDisposable()
154154
private let filterDisposable = MetaDisposable()
155+
private let selectTabDisposable = MetaDisposable()
156+
private var selectTabGeneration: Int = 0
155157
private let extrasFoldersDisposable = MetaDisposable()
156158
private var skipExtrasFoldersReload = false
157159
private let featuredFiltersDisposable = MetaDisposable()
@@ -4228,9 +4230,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
42284230
}
42294231
}
42304232

4231-
let _ = (self.context.engine.peers.currentChatListFilters()
4232-
|> deliverOnMainQueue).startStandalone(next: { [weak self] filters in
4233-
guard let strongSelf = self else {
4233+
self.selectTabGeneration &+= 1
4234+
let generation = self.selectTabGeneration
4235+
self.selectTabDisposable.set((self.context.engine.peers.currentChatListFilters()
4236+
|> deliverOnMainQueue).startStrict(next: { [weak self] filters in
4237+
guard let strongSelf = self, generation == strongSelf.selectTabGeneration else {
42344238
return
42354239
}
42364240
let updatedFilter: ChatListFilter?
@@ -4261,7 +4265,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
42614265
}
42624266
strongSelf.chatListDisplayNode.mainContainerNode.switchToAvailableFilter(preferring: updatedFilter.flatMap { .filter($0.id) } ?? .all, animated: false)
42634267
}
4264-
})
4268+
}))
42654269
}
42664270

42674271
private func readAllInFilter(id: Int32) {

‎submodules/ChatListUI/Sources/ChatListControllerNode.swift‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,13 @@ public final class ChatListContainerNode: ASDisplayNode, ASGestureRecognizerDele
177177
previousItemNode.listNode.addedVisibleChatsWithPeerIds = nil
178178
previousItemNode.listNode.didBeginSelectingChats = nil
179179
previousItemNode.listNode.canExpandHiddenItems = nil
180+
previousItemNode.listNode.isActiveForFolderPagination = false
180181

181182
previousItemNode.accessibilityElementsHidden = true
182183
}
183184
self.currentItemNodeValue = itemNode
184185
itemNode.accessibilityElementsHidden = false
186+
itemNode.listNode.reconcileLocationOnTabActivation()
185187

186188
itemNode.listNode.activateSearch = { [weak self] in
187189
self?.activateSearch?()
@@ -607,12 +609,6 @@ public final class ChatListContainerNode: ASDisplayNode, ASGestureRecognizerDele
607609
for (id, itemNode) in self.itemNodes {
608610
if id != selectedId {
609611
itemNode.emptyNode?.restartAnimation()
610-
611-
if let controller = self.controller, let chatListDisplayNode = controller.displayNode as? ChatListControllerNode, let navigationBarComponentView = chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View, let clippedScrollOffset = navigationBarComponentView.clippedScrollOffset {
612-
let scrollOffset = clippedScrollOffset
613-
614-
let _ = itemNode.listNode.scrollToOffsetFromTop(scrollOffset, animated: false)
615-
}
616612
}
617613
}
618614

‎submodules/ChatListUI/Sources/Node/ChatListNode.swift‎

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,8 @@ public final class ChatListNode: ListViewImpl {
12991299
}
13001300

13011301
private var currentLocation: ChatListNodeLocation?
1302+
private var chatListLocationGeneration: Int = 0
1303+
var isActiveForFolderPagination: Bool = false
13021304
public private(set) var chatListFilter: ChatListFilter? {
13031305
didSet {
13041306
self.chatListFilterValue.set(.single(self.chatListFilter))
@@ -1930,10 +1932,14 @@ public final class ChatListNode: ListViewImpl {
19301932

19311933
let chatListViewUpdate = self.chatListLocation.get()
19321934
|> distinctUntilChanged
1933-
|> mapToSignal { listLocation -> Signal<(ChatListNodeViewUpdate, ChatListFilter?), NoError> in
1935+
|> mapToSignal { [weak self] listLocation -> Signal<(ChatListNodeViewUpdate, ChatListFilter?, Int), NoError> in
1936+
guard let strongSelf = self else {
1937+
return .complete()
1938+
}
1939+
let locationGeneration = strongSelf.chatListLocationGeneration
19341940
return chatListViewForLocation(chatListLocation: location, location: listLocation, account: context.account, shouldLoadCanMessagePeer: shouldLoadCanMessagePeer)
19351941
|> map { update in
1936-
return (update, listLocation.filter)
1942+
return (update, listLocation.filter, locationGeneration)
19371943
}
19381944
}
19391945

@@ -1963,7 +1969,7 @@ public final class ChatListNode: ListViewImpl {
19631969
|> distinctUntilChanged
19641970

19651971
let chatListViewUpdateForFilters = combineLatest(chatListViewUpdate, messageFilterSettings)
1966-
|> map { update, _ -> (ChatListNodeViewUpdate, ChatListFilter?) in
1972+
|> map { update, _ -> (ChatListNodeViewUpdate, ChatListFilter?, Int) in
19671973
return update
19681974
}
19691975

@@ -2229,8 +2235,14 @@ public final class ChatListNode: ListViewImpl {
22292235
chatListFilters,
22302236
accountIsPremium
22312237
)
2232-
|> mapToQueue { (hideArchivedFolderByDefault, archiveFolderPresentation, displayArchiveIntro, storageInfo, savedMessagesPeer, updateAndFilter, state, contacts, chatListFilters, accountIsPremium) -> Signal<ChatListNodeListViewTransition, NoError> in
2233-
let (update, filter) = updateAndFilter
2238+
|> mapToQueue { [weak self] (hideArchivedFolderByDefault, archiveFolderPresentation, displayArchiveIntro, storageInfo, savedMessagesPeer, updateAndFilter, state, contacts, chatListFilters, accountIsPremium) -> Signal<ChatListNodeListViewTransition, NoError> in
2239+
guard let strongSelf = self else {
2240+
return .complete()
2241+
}
2242+
let (update, filter, locationGeneration) = updateAndFilter
2243+
if locationGeneration != strongSelf.chatListLocationGeneration {
2244+
return .complete()
2245+
}
22342246

22352247
let previousHideArchivedFolderByDefaultValue = previousHideArchivedFolderByDefault.swap(hideArchivedFolderByDefault)
22362248
let previousArchiveFolderPresentationValue = previousArchiveFolderPresentation.swap(archiveFolderPresentation)
@@ -2689,9 +2701,11 @@ public final class ChatListNode: ListViewImpl {
26892701
searchMode = true
26902702
}
26912703

2704+
var forceAllUpdated = false
26922705
if filter != previousView?.filter {
26932706
disableAnimations = true
26942707
updatedScrollPosition = nil
2708+
forceAllUpdated = true
26952709
}
26962710

26972711
let filterData = filter.flatMap { filter -> ChatListItemFilterData? in
@@ -2702,7 +2716,6 @@ public final class ChatListNode: ListViewImpl {
27022716
}
27032717
}
27042718

2705-
var forceAllUpdated = false
27062719
let previousChatListFiltersValue = previousChatListFilters.swap(chatListFilters)
27072720
if chatListFilters != previousChatListFiltersValue {
27082721
forceAllUpdated = true
@@ -2725,7 +2738,7 @@ public final class ChatListNode: ListViewImpl {
27252738
}
27262739

27272740
self.displayedItemRangeChanged = { [weak self] range, transactionOpaqueState in
2728-
if let strongSelf = self, let chatListView = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView {
2741+
if let strongSelf = self, strongSelf.isActiveForFolderPagination, let chatListView = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView {
27292742
let originalList = chatListView.originalList
27302743
if let range = range.loadedRange {
27312744
var location: ChatListNodeLocation?
@@ -3803,8 +3816,16 @@ public final class ChatListNode: ListViewImpl {
38033816
}
38043817
}
38053818

3819+
func reconcileLocationOnTabActivation() {
3820+
self.isActiveForFolderPagination = true
3821+
if case .navigation = self.currentLocation {
3822+
self.setChatListLocation(.initial(count: 50, filter: self.chatListFilter))
3823+
}
3824+
}
3825+
38063826
private func setChatListLocation(_ location: ChatListNodeLocation) {
38073827
self.currentLocation = location
3828+
self.chatListLocationGeneration &+= 1
38083829
self.chatListLocation.set(location)
38093830
}
38103831

0 commit comments

Comments
 (0)