feat(offline): gate the offline toggle on dictionary readiness
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 1m10s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 1s
CI / deploy (pull_request) Successful in 1m44s

Flipping the Settings toggle to offline now checks that every enabled variant's
dictionary is on the device before entering offline mode: it fetches missing ones
cache-first and waits up to ~5 s (raceOfflineReady + the lazy dict/offlineready),
greying the toggle meanwhile. If they cannot be readied in time it stays online and
shows a 'needs internet' note, while the fetch keeps warming the cache in the
background so a later flip is instant. Leaving offline is never gated.

Prevents entering a half-baked offline mode (no dawg -> cannot create/play a local
game) when the background preload has not finished (poor connection, or an immediate
flip right after install).

- offline.ts: raceOfflineReady (pure, injected sleep; unit-tested red->green)
- dict/offlineready.ts: ensureOfflineDicts (cache-first preloadDicts, lazy chunk)
- offline.svelte.ts: requestOffline + TOGGLE_READY_BUDGET_MS
- Settings.svelte: checking/needsData state, disabled toggle, inline note
- i18n: settings.offlineChecking / settings.offlineNeedsData (en+ru)
- docs: FUNCTIONAL(+_ru) offline story + ARCHITECTURE offline paragraph
This commit is contained in:
Ilia Denisov
2026-07-06 20:03:12 +02:00
parent 05c445e4da
commit 30770a759b
10 changed files with 153 additions and 9 deletions
+5 -1
View File
@@ -1259,7 +1259,11 @@ eligible installed PWA (standalone web + confirmed email) **background-preloads*
— on lobby entry and on a variant-preference change — through the same three-tier loader, retried
with backoff and honouring the session miss-breaker; the move generator, the loader and the preload
orchestration stay in lazy chunks. A first-lobby preload failure shows a *poor-connection* notice in
the ad-banner slot. A **cold launch already in offline mode** boots from the persisted session and
the ad-banner slot. Flipping the Settings toggle **to** offline runs that same cache-first fetch
bounded by a ~5 s UI wait (`raceOfflineReady` + the lazy `dict/offlineready`): it enters offline only
once every enabled variant is ready, otherwise it stays online with a *needs internet* note while the
fetch finishes in the background (the next flip is then instant). A **cold launch already in offline
mode** boots from the persisted session and
profile (the profile is saved on every online adopt/refresh) — `bootstrap` skips the session
adoption and profile fetch that would otherwise hang with no network, and lands straight in the
offline lobby; without a cached profile (an install that was never online) it drops the sticky flag