fix(wallet): unify tab loading and stop the tutorial from showing for existing accounts - #1270
Merged
Merged
Conversation
… existing accounts
Two defects, one root cause: the wallet tab reads a local cache that starts
empty on every fresh login, and had no way to tell "this account has no
activity" from "we haven't looked yet".
- MessageDataSource.hasEverAddedMoney() and ChatMessageDataSource.hasEverTipped()
read the per-user DB (and, for the latter, the account id) once at subscription
time. The DB is created at login, after singletons build their flow graphs, so a
subscriber that started first latched onto a constant `false` for the whole
session -- pinning the onboarding checklist to "incomplete" and leaving the
new-user tutorial on screen for an established account. Both now resolve through
FlipcashDatabase.observeInstance(), matching what observeRecent() already did.
- ActivityFeedCoordinator publishes a FeedSyncState so callers can distinguish an
empty account from an unsynced cache. It resets to Unknown when API access is
lost, so the next account waits for its own fetch. Unavailable exists so an
offline device stops waiting instead of spinning forever; the 60s poller
upgrades it.
- WalletViewModel.State.onboardingItems is nullable ("unknown"), and
isAwaitingActivity covers the window before the feed has been reconciled. Local
rows short-circuit the wait.
- WalletScreenContent gates the whole tab behind one CodeCircularProgressIndicator
until tokens have hydrated and the activity side has settled. BalanceHeader's own
spinner is consequently unreachable here; v1's BalanceScreen still uses it.
v2-only: BalanceScreenContent never reads onboardingItems and BalanceHeader is
untouched, so the v1 path is unaffected.
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.
Two reported defects on the wallet tab, one root cause: the tab renders from a local cache that starts empty on every fresh login, and had no way to tell "this account has no activity" from "we haven't looked yet."
1. New-user tutorial shown to an existing account
MessageDataSource.hasEverAddedMoney()andChatMessageDataSource.hasEverTipped()were non-suspend flow factories that read the per-user DB — and, forhasEverTipped,userManager.accountId— once at subscription time. The per-user Room DB is created at login, after singletons have built their flow graphs, so a subscriber that started first (the wallet tab composing while a soft login is still in flight) latched onto a constantfalsefor the rest of the session. That pinned the onboarding checklist to "incomplete", so the tutorial stayed on screen and the 2×2 action grid (gated onhasAddedMoney) never rendered.Both now resolve through
FlipcashDatabase.observeInstance()— the patternMessageDataSource.observeRecent()two functions below already used, with a comment naming this exact hazard.Fixing the latch isn't sufficient on its own: the Room flows legitimately emit
falsefrom a genuinely-empty cache before the network sync lands, so the tutorial would still flash.ActivityFeedCoordinatornow publishes aFeedSyncState(Unknown/Synced/Unavailable) maintained byfetchSinceLatest, which every refresh path funnels through. It resets toUnknownwhen API access is lost, so the next account waits for its own fetch rather than inheriting the previous session's verdict.Unavailableexists so an offline device stops waiting instead of spinning forever — the 60s poller upgrades it when it succeeds.WalletViewModel.State.onboardingItemsis now nullable (null= unknown),isNewUserTutorialCompletetreats unknown as complete, andisAwaitingActivitycovers the window before the feed has been reconciled. Cached rows short-circuit the wait: if there's already activity to draw, there's nothing to mistake for a new account.2. Two loading states instead of one
BalanceHeaderstaged itself onbalance == nullwhile the body below it independently decided, from a still-empty cache, that this was a brand-new account and drew the tutorial — so the tab assembled in pieces.WalletScreenContentnow gates the entire tab behind a single centredCodeCircularProgressIndicatoruntil tokens have hydrated and the activity side has settled.BalanceHeader's own spinner is consequently unreachable on this screen; v1'sBalanceScreenstill uses it.Gating
v2-only in effect. All UI changes are in
WalletScreenContent/WalletViewModel, reached only viaAppScreenContent'sif (isNewUi)branch.BalanceScreenContent(v1) never readsonboardingItems, andBalanceHeaderis untouched. The two data-source fixes are shared, but they're pure correctness fixes to flows whose only consumer is the v2 checklist.Testing
WalletLoadingStateTest— 9 pure-state cases covering the wait window, both exits from it (SyncedandUnavailable), the cached-rows short-circuit, and the tutorial-visibility rules.:apps:flipcash:app:assembleDebugand:apps:flipcash:features:balance:testDebugUnitTestboth pass.