[Mobile] Faster cold-start splash + smaller cache blob + no image flash#14277
Open
raymondjacobson wants to merge 3 commits intomainfrom
Open
[Mobile] Faster cold-start splash + smaller cache blob + no image flash#14277raymondjacobson wants to merge 3 commits intomainfrom
raymondjacobson wants to merge 3 commits intomainfrom
Conversation
## Splash gate removed The native splash was held until isRestoring=false (~1.2s on device). Account data comes from the synchronous localStorage cache, so showHomeStack is true even during React Query restoration — there is no sign-in screen flash. Dropping the gate means the splash dismisses as soon as React is ready, and the lineup skeleton (which is more informative than a blank white screen) is visible during the ~1s hydration window instead. ## Persisted blob narrowed to trending-only tracks/users query-persister.ts previously let every track and user query through the allowlist regardless of how many the user had browsed. On a long session this produced a large JSON blob that made the AsyncStorage read + JSON.parse at next launch progressively slower. shouldDehydrateQuery now caps track/user persistence to only the IDs present in the trending week lineup (plus the account user's owner data). A short-lived in-memory cache avoids re-querying the client for every entry in a single dehydration pass. Cache buster bumped to v3 to drop any oversized blobs from previous builds. ## Image low-res→high-res flash eliminated When useImageSize had a smaller cached URL (e.g. 150x150) and needed to load a larger one (e.g. 480x480), it set imageUrl to the small URL then switched to the large URL once fetched. That source change caused Image.tsx to reset opacity to 0 and re-fade — a visible flash on track pages, profile pages, and playlist pages. useImageSize now sets imageUrl to the target URL immediately (optimistic, consistent with the no-cache path) and returns priorityLowResUrl as a separate value. TrackImage, CollectionImage, and UserImage thread this through as priorityLowResSource on Artwork/ Image, which the component uses as a blurred backdrop while the high-res crossfades in — no opacity reset, no flash. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Member
Author
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Contributor
🌐 Web preview readyPreview URL: https://audius-web-preview-pr-14277.audius.workers.dev Unique preview for this PR (deployed from this branch). |
Dropping canDismiss={!isRestoring} caused the SectionList in
TrendingLineupSkeletons to measure at near-zero height on the first
visible frame, rendering only one tile at the bottom of an empty screen.
ScreenPrimaryContent gates on isScreenReady (InteractionManager +
200ms failsafe). That measurement previously happened under the splash
so the layout was settled before anything became visible. Without the
gate the first user-visible frame precedes the native layout pass.
The splash duration is addressed by the cache blob narrowing in this
branch — only trending tracks/users are persisted, so isRestoring
completes much faster than before.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bumping to v3 dropped the old cache, making isRestoring complete instantly (nothing to restore). With an empty cache the splash starts fading before the SectionList measures its container, producing the same 0-height blank-screen bug. The buster bump was unnecessary: shouldDehydrateQuery only affects writes, not reads. Old v2 caches have the same dehydration shape and load correctly — they're just larger. The new write-time filter will shrink the blob over subsequent sessions without disrupting existing cache data. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.

Summary
Three targeted fixes based on screen recording analysis of the cold-start sequence.
1. Splash drops immediately (no longer gated on
isRestoring)The native splash was held until React Query finished restoring from AsyncStorage (~1.2 s on device). Account data arrives from the synchronous localStorage cache, so
showHomeStackis true even during restoration — no sign-in flash. Removing the gate means the splash drops as soon as React is ready and the lineup skeleton (informative) is visible during hydration instead of a blank white screen.2. Persisted cache blob narrowed to trending-only tracks/users
shouldDehydrateQuerypreviously let every track and user query through, so a long browsing session produced a large blob that made the AsyncStorage read +JSON.parseprogressively slower on the next cold-start. The filter now limitstrack/userpersistence to the IDs in the current trending week lineup plus the account user's owner records. A short-lived in-memory cache avoids re-querying the client on every entry in a single dehydration pass. Cache buster bumped tov3to drop oversized blobs from prior builds.3. Low-res → high-res image flash eliminated
When
useImageSizehad a 150×150 URL in cache but needed 480×480, it setimageUrlto the small URL then switched to the large URL once fetched. That source change triggeredImage.tsxto resetopacity = 0and re-fade — a visible flash on track pages, profile pages, and playlist pages.useImageSizenow setsimageUrlto the target URL optimistically and returnspriorityLowResUrlseparately.TrackImage,CollectionImage, andUserImagethread this through aspriorityLowResSourceonArtwork/Image, which renders it as a blurred backdrop while the high-res crossfades in — no opacity reset, no flash.Test plan
🤖 Generated with Claude Code