feat(offline): implicit net-state model, two-tier version gate, unified lobby
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m14s
CI / conformance (pull_request) Successful in 12s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Failing after 22s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 21s
CI / ui (pull_request) Successful in 1m14s
CI / conformance (pull_request) Successful in 12s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Failing after 22s
Land the offline-model redesign (ANDROID_PLAN.md O1-O7): replace the explicit offline toggle with a single detected net-state machine, unify the lobby, and add a two-tier client-version gate. Contour-safe: both version vars empty => dormant, and the wire change is additive, so web/pwa/vk/tg behaviour is unchanged unless the gate is deliberately configured. O1 pure net-state reducer (test-first). O2 reactive store + event wiring (connection/offline become thin shims; +@capacitor/network). O3 remove the offline toggle + migrate the pref. O4 two-tier gate: hard update_required degrades to an offline Update/Play-offline notice (not terminal); soft GATEWAY_RECOMMENDED_CLIENT_VERSION -> X-Update-Recommended nudge. O5 unified lobby (device-local + greyed-from-cache server games; self-set identity; closes G-step-0). O6 create flows (with-friends online/offline segment + offline dict guard). O7 docs (ARCHITECTURE, FUNCTIONAL +_ru, TESTING, deploy/README). Also disable the manual android-build CI workflow for now (rename to .disabled); the Android APK release comes later. Tests: gateway go green, svelte-check 0/0, vitest 617, e2e 122/122 (chromium + webkit).
This commit is contained in:
+30
-23
@@ -277,22 +277,25 @@ add-friend are off. AI games are **practice** — they never count toward a play
|
||||
statistics.
|
||||
|
||||
### Offline mode
|
||||
An installed web PWA signed in with a confirmed email can switch to a deliberate **offline mode**
|
||||
(Settings → Play mode). Offline, the app never touches the network: the header turns blue with an
|
||||
*Offline* chip, the lobby lists only the games stored on the device, and online-only surfaces are
|
||||
disabled or hidden (the Stats tab; the *random opponent* option in New Game).
|
||||
A New Game against the robot creates a device-local **vs_ai** game — it
|
||||
plays entirely in the browser with no backend. Local games are kept on the device, visible only in
|
||||
offline mode, and never sync to the account. So a game can be created and played with no connection,
|
||||
the app quietly preloads the dictionaries for the player's enabled variants while still online, and
|
||||
(once installed) launches from a precached shell even with no network. Switching **to** offline first
|
||||
checks that the enabled variants' dictionaries are on the device — if any are missing it fetches them
|
||||
and waits briefly, and if they cannot be readied it stays online with a short *needs internet* note
|
||||
(the download keeps running in the background, so a later switch is instant). The mode is
|
||||
device-scoped and sticky across launches.
|
||||
The app plays **offline automatically** — there is **no on/off switch**. When it cannot reach the
|
||||
server the header turns blue with an *Offline* chip and play is confined to games on the device; a
|
||||
momentary blip is ridden out as a quiet *"Connecting…"* (it never drops you offline), and when the
|
||||
connection returns the app goes back online on its own with a brief *back online* toast. Offline, the
|
||||
app never touches the network.
|
||||
|
||||
Offline, New Game's **with friends** starts a **local pass-and-play** game for 2-4 people sharing one
|
||||
device. You first set a **host (leader) password** — a 4-digit PIN entered on a lock-screen-style
|
||||
The **lobby stays unified**: your device-local games are active, while your server games are still
|
||||
listed but **greyed out** — visible but un-openable until you are back online (a tap explains why).
|
||||
Online-only surfaces (the Stats tab) are disabled and invitations are hidden while offline. A New Game
|
||||
against the robot creates a device-local **vs_ai** game that plays entirely on the device with no
|
||||
backend; local games are kept on the device and never sync to the account, so a game can be created and
|
||||
played with no connection. The app quietly preloads the dictionaries for the player's enabled variants
|
||||
while still online, and (once installed, or on the native app) launches from bundled/precached data even
|
||||
with no network; if a variant's dictionary is not available offline, creating that game is disabled with
|
||||
a short note.
|
||||
|
||||
New Game's **with friends** offers a choice — **invite a friend** to play online, or a **local
|
||||
pass-and-play** game for 2-4 people sharing one device; with no network only pass-and-play is available.
|
||||
In pass-and-play you first set a **host (leader) password** — a 4-digit PIN entered on a lock-screen-style
|
||||
keypad; until it is set the player rows stay locked. The app then asks whether you are playing too —
|
||||
if so you take the first seat with your profile name. You name each player (2 to 4; add or remove
|
||||
rows, where a removal asks for the leader password) and may give any seat its **own optional PIN**.
|
||||
@@ -305,14 +308,18 @@ pass-and-play game. A game that finishes normally is saved to the offline lobby
|
||||
deleting any pass-and-play game — running or finished — from the lobby asks for the leader password,
|
||||
so no one can wipe a game the moment they have moved.
|
||||
|
||||
The app also **enters offline mode on its own** when it cannot reach the network. On a cold launch
|
||||
with no connection it switches to offline for that session; when the device is online but the gateway
|
||||
stays silent for a few seconds it asks first — *No connection. Switch to offline mode?*, with
|
||||
**Switch** (go offline) or **Wait for network** (keep retrying online). While the app is open, losing
|
||||
the network — airplane mode — switches to offline automatically, and restoring it returns online by
|
||||
itself. A self-entered offline is temporary: it reverts to online the moment the network is back, and
|
||||
the next launch re-checks. A **deliberate** offline — the Settings toggle, or **Switch** in that
|
||||
dialog — is the player's choice: it is kept, and never undone automatically.
|
||||
Going offline and coming back are both **automatic**. On a cold launch with no connection the app
|
||||
starts straight in the offline lobby; while it is open, losing the network — airplane mode — turns it
|
||||
offline on its own, and restoring the network returns it online by itself. There is no dialog and no
|
||||
switch to remember: a brief drop is ridden out quietly and only a sustained loss turns the chrome
|
||||
offline, so you are never interrupted for a hiccup.
|
||||
|
||||
### Staying up to date
|
||||
When a new client version is required, the app does not lock you out. On the **native** app a
|
||||
too-old build shows a notice with **Update** (opens the store) and **Play offline** (dismiss and keep
|
||||
playing your on-device games); on the web it offers **Update** (reload) instead. A softer,
|
||||
non-blocking **"update available"** banner appears in the lobby when a newer — but not yet
|
||||
required — version exists; you can update or dismiss it, and play continues either way.
|
||||
|
||||
### Native app (Android)
|
||||
The game also ships as a standalone **Android app** (first on **RuStore**), a packaged build of the same
|
||||
|
||||
Reference in New Issue
Block a user