fix(mobile): load tab screens once, not on every tab switch - #183
Merged
Conversation
Shell raises OnAppearing on every tab selection, and all five tab pages called LoadCommand there unconditionally - so each tab tap cost a full API round trip, cleared the collections and repainted them. Against a slow or unreachable API that is a spinner every time the user comes back to a screen, which reads as an app permanently refreshing itself. Each page's OnAppearing now calls EnsureLoadedCommand: fetch on the first visit, then leave the screen alone. Freshness comes from invalidation rather than repetition: - SubscriptionsChangedMessage marks the list stale, so the reload happens when the user is looking at that screen instead of behind their back. The dashboard, a singleton whose totals move with any write, refetches straight away as before. - Category and payment-source renames and deletes now publish that message too. The dashboard names both in its breakdowns and no longer refetches on tab switch, so the change has to be announced. - SessionEndedMessage clears each screen and re-arms its fetch. Shell keeps the page it built for each ShellContent, so without this the next user to sign in would be handed the previous one's rows and no request would follow. - Pull-to-refresh is unchanged: RefreshView still binds LoadCommand, which always fetches. - A load that ended with nothing on screen is not "loaded", so an error screen still retries on the next visit. Cached rows do count, which is the case the refetch made painful. Also brings the Payment rows in line with Categories after #179: the "..." button is the same vertical-dots tonal icon button, and the SwipeView is gone. Two ways into one menu is one more than the screen needs, and only one of them was ever discoverable.
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.
The bug
Every tab tap refetched the whole screen. Shell raises
OnAppearingon each tab selection, and all five tab pages calledLoadCommandthere unconditionally — a full API round trip, collections cleared, list repainted. On a phone talking to a slow or unreachable API that is a spinner every single time you come back to a screen, which is what "the app keeps refreshing" turned out to mean.The fix
OnAppearingnow callsEnsureLoadedCommand— fetch on the first visit, then leave the screen alone. Freshness comes from invalidation, not repetition:SubscriptionsChangedMessagemarks the list stale, so the reload happens when the user is actually looking at it rather than behind their back. The dashboard — a singleton whose totals move with any write — still refetches immediately.IMessengeron those two view models.SessionEndedMessageclears each screen and re-arms its fetch. Shell keeps the page it built for eachShellContent, so without this the next user to sign in gets handed the previous one's rows and no request follows.RefreshViewstill bindsLoadCommand, which always fetches.Also brings the Payment rows in line with Categories after #179: the
•••button is now the same vertical-dots tonal icon button, and theSwipeViewis gone. Two routes into one menu is one more than the screen needs, and only one of them was ever discoverable.Verified on a physical device
Built and installed on a Pixel-class Android phone against a local API over
adb reverse, then:adb reverse --remove, devicecurl→000), and switched tabs again. Categories and Payment still rendered in full — neither has a local cache, so that data could only have come from the first load. Subs showed its rows with no offline banner, meaning no fetch was even attempted.isLoaded=Trueon every screen, with no view-model reconstruction.Tests
dotnet test tests/SubVora.Mobile.Tests→ 315 passed, 0 failed, including a newTabSwitchReloadTestscovering: repeat appearance costs no call, pull-to-refresh still fetches every time, a change message re-arms the fetch, sign-out clears and refetches, cache-served counts as loaded, an empty failure retries, and both renames announce themselves.Note
What is left after this is not a refresh: the tab bar highlights instantly while the page content swaps ~0.3–0.5s later. That is Shell's page-swap cost on Android in a Debug build, not a reload — no request is made and no view model is rebuilt. Worth judging on a Release build before chasing further.