130 lines
6.4 KiB
Markdown
130 lines
6.4 KiB
Markdown
# Splash & mascot — open notes
|
||
|
||
State of play after the connection-indicator (`SyncIndicator`) work landed.
|
||
Anything in this file is **deferred / future work**, not active. Treat it as
|
||
context for the next person to pick up the splash topic.
|
||
|
||
## Current visible chain (cold load, web/desktop)
|
||
|
||
1. **Initial blank** — HTML loaded, React mounts. ~50ms. `body` background
|
||
is `#0d0e11` (the `--vojo-safe-area-bg` var), so it's a dark frame, not
|
||
white.
|
||
2. **`ConfigConfigLoading` mascot splash** —
|
||
[`pages/ConfigConfig.tsx`](../../src/app/pages/ConfigConfig.tsx) renders
|
||
`<AuthSplashScreen />` (mascot + footer) while `/config.json` is fetched.
|
||
~50–300ms on Caddy-served static.
|
||
3. **`SpecVersions` mascot splash** —
|
||
[`pages/client/SpecVersions.tsx`](../../src/app/pages/client/SpecVersions.tsx)
|
||
renders `<AuthSplashScreen />` while `/_matrix/client/versions` is fetched
|
||
from the homeserver. **0.5–2s, network-bound, the longest of the chain.**
|
||
4. **`ClientRoot` mascot splash** —
|
||
[`pages/client/ClientRoot.tsx`](../../src/app/pages/client/ClientRoot.tsx)
|
||
`loading || !mx ? <ClientRootLoading /> : ...`. Shown while `initClient`
|
||
runs (IndexedDB open + crypto WASM init, ~300–700ms) AND while waiting
|
||
for `SyncState.Prepared` (the `useSyncState` gate at line ~200). The
|
||
Prepared wait can be 1–30s depending on cache warmth and account size.
|
||
5. App tree mounts. `SyncIndicator` takes over for the residual sync
|
||
activity (green slide while sync is still settling, hidden once Syncing).
|
||
|
||
## Current visible chain (Android native)
|
||
|
||
1. **OS system splash** — Android 12+ enforces a system splash with the
|
||
launcher icon centered over `windowBackground`. Configured via
|
||
[`android/app/src/main/res/values/styles.xml`](../../android/app/src/main/res/values/styles.xml)
|
||
`AppTheme.NoActionBarLaunch` → `windowBackground=@android:color/black`.
|
||
Cannot be fully eliminated; ~300–500ms while Android starts the process
|
||
and Capacitor loads the WebView.
|
||
2. Then the web chain (steps 1–5 above).
|
||
|
||
So an Android cold-launch sees: black-icon (OS) → black blank (HTML) →
|
||
mascot (config + spec-versions + initClient + Prepared) → app.
|
||
|
||
## What we tried and reverted (during the SyncIndicator work)
|
||
|
||
In the 0.3.0 attempt that got reverted, we made several aggressive changes
|
||
to shorten the chain. They worked, but introduced subtle bugs that the user
|
||
chose to roll back to keep the diff clean. Specifically:
|
||
|
||
### A. SpecVersions made non-blocking
|
||
|
||
[Commit reverted in `ff01e6c`.] The change made `SpecVersions` render
|
||
children immediately with `versions: []` and hydrate the real value in the
|
||
background (with retry on `online` event). This eliminated the 0.5–2s
|
||
mascot in step 3.
|
||
|
||
**Why reverted**: it surfaced a latent bug in
|
||
[`components/message/content/ImageContent.tsx`](../../src/app/components/message/content/ImageContent.tsx)
|
||
and `VideoContent.tsx`. While `versions: []`, `useMediaAuthentication()`
|
||
returns false, autoPlay images load with unauth URLs, the server rejects,
|
||
the local `error=true` flag latches and is never cleared on the post-
|
||
hydration retry. The reviewer flagged this as a blocker.
|
||
|
||
**Fix attempted**: reset `error` and `load` state in the `loadSrc`-deps
|
||
useEffect AND in `handleLoad` — both `ImageContent.tsx` and
|
||
`VideoContent.tsx`. The fix was correct but the user judged it as out-of-
|
||
scope scope-creep for the connection-indicator feature and rolled the
|
||
whole change back.
|
||
|
||
**To redo cleanly**: ship SpecVersions-non-blocking and the
|
||
ImageContent/VideoContent fix together, in a separate dedicated commit
|
||
(scope = "make boot non-blocking", not bundled with the indicator).
|
||
|
||
### B. ClientRoot loading paths replaced with `null`
|
||
|
||
[`pages/ConfigConfig.tsx::ConfigConfigLoading`](../../src/app/pages/ConfigConfig.tsx)
|
||
returned `null` instead of `<AuthSplashScreen />`. Same for the `!mx` branch
|
||
in `ClientRoot`. Eliminated the mascot during steps 2 and 4-init-only.
|
||
Reverted as part of the same revert.
|
||
|
||
**To redo**: low risk on its own. Change those two callsites to render
|
||
`null` (the dark body background shows through). Skip the Prepared gate
|
||
removal (that's the deeper change).
|
||
|
||
### C. ClientRoot Prepared gate removed
|
||
|
||
The ambitious move: render `MatrixClientProvider` as soon as `mx` is created
|
||
(after `initClient`), not after `Prepared`. Eliminates the 1–30s wait for
|
||
first sync — app shell renders against the IndexedDB cache while sync
|
||
populates new events in background.
|
||
|
||
**Why reverted**: needed an extra fix in
|
||
[`pages/client/direct/RoomProvider.tsx`](../../src/app/pages/client/direct/RoomProvider.tsx)
|
||
to add `useAtomValue(allRoomsAtom)` so cold-start deep-links (push tap)
|
||
re-render when the room arrives. Plus arguably exposes a brief empty-UI
|
||
flash on first-time logins.
|
||
|
||
**To redo**: do it after a careful audit of every consumer of
|
||
`mx.getRoom()` / `mx.getRooms()` to make sure they all tolerate empty
|
||
stores. The deep-link re-render fix in `direct/RoomProvider.tsx` is the
|
||
mechanical trigger; there may be others.
|
||
|
||
## What's open
|
||
|
||
In rough priority order:
|
||
|
||
1. **SpecVersions non-blocking + media-auth race fix** (B above).
|
||
Biggest win for cold-start time-to-interactive (~1.5s saved). Bundle
|
||
with the ImageContent/VideoContent error reset in one commit.
|
||
2. **`null` instead of mascot during ConfigConfig + `!mx` loading**
|
||
(B above, simpler half). ~400ms shaved.
|
||
3. **Drop the Prepared gate** (C above). Most invasive; needs full audit.
|
||
Could wait until `dm_1x1_redesign.md` or another major-mode change is
|
||
ready to absorb the risk.
|
||
4. **OS system splash on Android** — currently iconic-on-black via
|
||
`AppTheme.NoActionBarLaunch`. Can't eliminate on Android 12+ but can
|
||
be tuned (different background color, different icon) via
|
||
`android/app/src/main/res/values/styles.xml`. Not user-reported as a
|
||
problem, just noting the lever exists.
|
||
|
||
## Don't break
|
||
|
||
- **`body { background: var(--vojo-safe-area-bg, #0d0e11) }`** in
|
||
`src/index.css` — the dark frame is what makes a `null` loading path
|
||
look intentional. Without it the user sees a white flash.
|
||
- **Mascot on auth pages** (`/login`, `/register`) is INTENDED — those
|
||
pages design the mascot in deliberately. Don't gate-remove it there.
|
||
Only the loading-state mascot is the candidate for removal.
|
||
- **The error-retry mascot in `ClientRoot`** (the
|
||
`<AuthSplashScreen>{retry-dialog}</AuthSplashScreen>` branch in
|
||
`ClientRoot.tsx`) is the rare case where the mascot is fine to keep —
|
||
it's a hard-error context that needs anchoring for the dialog.
|