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
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:
@@ -40,6 +40,26 @@ export function setOfflineMode(on: boolean, persist = true): void {
|
||||
if (persist) saveOfflinePref(on);
|
||||
}
|
||||
|
||||
/** The toggle-flip readiness wait: entering offline waits at most this long for the enabled
|
||||
* variants' dictionaries before reverting to online (the fetch then continues in the background). */
|
||||
export const TOGGLE_READY_BUDGET_MS = 5000;
|
||||
|
||||
/**
|
||||
* requestOffline attempts to enter offline mode from the Settings toggle. It fetches the enabled
|
||||
* variants' dictionaries cache-first and, if every one is available within the readiness budget,
|
||||
* switches to a deliberate (persisted) offline mode and returns true. Otherwise it stays online and
|
||||
* returns false — the caller shows the "needs internet" note — while the fetch keeps warming the
|
||||
* cache so a later flip is instant. The readiness glue and the dict loader are imported dynamically,
|
||||
* so neither is pulled into the main bundle. Returns false with no profile.
|
||||
*/
|
||||
export async function requestOffline(prof: Profile | null, budgetMs = TOGGLE_READY_BUDGET_MS): Promise<boolean> {
|
||||
if (!prof) return false;
|
||||
const m = await import('./dict/offlineready');
|
||||
const ready = await m.ensureOfflineDicts(prof, budgetMs);
|
||||
if (ready) setOfflineMode(true);
|
||||
return ready;
|
||||
}
|
||||
|
||||
// The dict-preload warning: true when a first-lobby background preload could not fetch every
|
||||
// enabled variant's dictionary (typically a poor connection), so offline mode may be incomplete.
|
||||
// The lobby shows a notice in place of the ad banner while it holds.
|
||||
|
||||
Reference in New Issue
Block a user