Repository navigation
fix(chat): settle the chats list in one update after launch - #947
Merged
Merged
Conversation
…elaying it On cold launch the cached chats list painted, then changed: the feed loaded twice, its three parts applied separately, backfill rewrote previews one by one, and unread counts popped in per row. - The cached list paints and stays interactive immediately. - start() and the foreground hook share one in-flight loadFeed(), so each feed type is fetched once. - Once all three feeds return, one non-animated update applies them with unread counts resolved (width 4) inside it. The wait is capped at 2s for a slow feed type and 1.5s for the unread pass; past a cap, what has landed is applied. It does not wait on backfill. - Backfill runs after the reconcile through BackfillQueue, promotes the open chat, and is idempotent: a row's preview, lastActivity or order changes only for a genuinely newer message. The store keeps a stored lastMessage and lastActivity that are newer than a feed copy. - An empty store keeps the progressive behaviour. - The open chat shows its cached transcript at once, with a placeholder only when it is empty. - getConversations() takes the newer of a row's activity and its newest stored message, so messages persisted by the notification extension position the chat correctly at launch.
KnownAuthorDirectory persisted names but its snapshot stayed empty until a .task ran after the cached list painted, so previews drew without sender prefixes and refilled about a second later. Read the table at session start and land it when the Chats screen appears, beside the conversation cache.
…om onAppear The preload read finishes in about 3ms, but the Chats screen only applied it from onAppear, and applied the conversation cache first. The rows rendered once with an empty author table before it landed, so group previews drew without their sender prefix. The preload now applies itself on the main actor when it finishes, and onAppear takes the authors before the conversation cache.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On cold launch the chats list painted from cache and then kept changing: rows reordered, previews updated one at a time, and unread counts popped in. The list should be current the first time it settles, with only new events changing it after that, and launch must not get slower.
Why it churned
start()and the.activehook inAppDelegateeach ranloadFeed()..activefires on cold launch too, so every launch made two full feed loads and two backfill passes.resolveUnreadCountran aGetMessageper row from the row's.task.What changes
loadFeed()shares one in-flight task, so launch, foreground and reconnect make one fetch per feed type.FeedReconcileTiming.launch); past a cap, whatever has landed is applied. The reconcile does not wait on backfill. The feed carries the read pointer's message id but not itsunreadSeq, so counts can't be computed locally.BackfillQueue, and an opened chat jumps the queue. The open chat shows its cached transcript at once and shows the placeholder only when it is empty.lastMessageandlastActivitywhen a feed copy is older, andadvanceLastActivityignores a date that isn't later. A test caught a delayed feed response rolling back a row that a stream event had just advanced.getConversations()takes the newer of a row's activity and its newest stored message. The notification extension persists message rows but never updates the conversation row, so a chat that got a push while the app was closed used to launch at its old position.Tests:
ChatListLaunchSyncTests(one reconcile with counts populated, no wait on backfill, older data doesn't move a row, empty store isn't held, one fetch per feed type), plusBackfillQueueTests,BoundedWaitTests, and store and database round-trip cases.If the server deletes a chat's latest message, the row keeps its later activity and position, a side effect of the newer-wins rule.
Android counterpart: code-payments/code-android-app#1665.