perf(wallet): stop the login spinner waiting on three network races - #1342
Merged
Conversation
The wallet tab blanks itself while `isAwaitingTokens || isAwaitingActivity`, and on a fresh login neither side resolves promptly. The balance fetch idled behind `tokenUpdater.poll(startIn = 2.seconds)`. Nothing else fetches balances after login — `TokenCoordinator.onUserLoggedIn` only hydrates Room, which is empty on a new account — so that head start was a second of spinner spent deliberately idle. It could also be worse than a second: `onAppInForeground` fires twice at login, once from the transition into `AuthState.Ready` and once from `ON_RESUME`, and `NetworkUpdater.poll` restarted unconditionally, cancelling the in-flight fetch and re-serving the delay. `poll` now keys on its previously unused `key` parameter and leaves an equivalent running loop alone; `stop` still resets on background and logout. `onboardingItems` stayed null until `hasEverTipped()` could answer, which waits on the sequential per-chat backfill behind `ChatHydrationState`. The milestone combine now always emits, carrying `isTipMilestoneResolved` to say whether the tip half can be believed. Only `isNewUserTutorialComplete` reads that flag, so "Scan a Tip Card" is still never drawn as outstanding to someone who already tipped, while the balance, the card deck and the action tiles draw off state the app already has, as iOS does. The feed gate waited on a 100-row page. The count only bites on a cold cache — with anything cached `fetchSinceLatest` pages forward from the newest row — so it is really how much history a login waits for before the wallet can draw, and the wallet previews three rows. 25 still covers the history screen's first page, which pages at 20, and leaves the rest to that screen's own paging. The catch-up is guarded against the repeated foreground edge as well, so the second one joins the fetch rather than duplicating it. The per-chat backfill is untouched. It remains the long pole for an account with many conversations; the wallet just no longer waits on it.
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 a fresh login or account create the wallet tab draws nothing while
isAwaitingTokens || isAwaitingActivity(WalletScreenContent.kt:86). That is anAND over three independent network races, none of which start before
AuthState.Ready, and each was slower than it needed to be. iOS seeds its walletfrom the session synchronously and gates only the tutorial card, which is most of
why it feels quicker.
Three changes, no behaviour dropped.
The balance fetch no longer idles for two seconds
tokenUpdater.poll(startIn = 2.seconds)is the only thing that fetches balancesafter login —
TokenCoordinator.onUserLoggedInjust hydrates Room, which is emptyon a new account — so the head start was two seconds of spinner spent deliberately
idle.
It could also be worse than two seconds.
onAppInForegroundfires twice at login,once from the transition into
AuthState.Readyand once fromON_RESUME, andNetworkUpdater.pollstopped and relaunched unconditionally: the second edgecancelled the in-flight fetch and re-served
startIn, pushing the first fetch of afresh session further out.
pollnow uses its previously unusedkeyparameter asan identity and leaves an equivalent running loop alone.
stopstill resets onbackground and logout, and
NetworkUpdaterTestcovers both.The tutorial waits on chat hydration; the rest of the tab does not
onboardingItemsstayed null untilhasEverTipped()could answer, and that answerwaits on the per-chat backfill behind
ChatHydrationState— a wait that scales withhow many conversations the account has. The milestone combine now always emits,
carrying
isTipMilestoneResolvedto say whether the tip half can be believed. OnlyisNewUserTutorialCompletereads that flag, so "Scan a Tip Card" is still neverdrawn as outstanding to someone who has already tipped, while the balance, the card
deck and the action tiles draw off state the app already holds.
The login feed seed is 25 rows, not 100
The count only bites on a cold cache; with anything cached
fetchSinceLatestpagesforward from the newest row and takes whatever has happened since. So it is really
how much history a fresh login waits for before the wallet can draw, and the wallet
previews three rows. 25 still covers the history screen's first page, which pages at
20, and leaves the rest to that screen's own paging. The catch-up is guarded against
the repeated foreground edge as well, so the second one joins the in-flight fetch
instead of duplicating it.
Out of scope
The sequential per-chat backfill behind
CatchUpCompleteis untouched, and it isstill the long pole for an account with many conversations. This takes the wallet off
it rather than fixing it.