fix(offline): return online after flight-mode off; gate online-game actions offline
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 1m11s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m38s
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 1m11s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m38s
Two mid-session issues found on the contour: - Auto-offline did not return to online after the network came back: a single reachability check right after the 'online' event failed (the interface is up before the gateway is actually reachable again). Retry a few times with backoff (tryReturnOnline) — that is what actually gets the app back online. - An online game viewed while offline (flight mode on) still enabled its network actions, so they hit the kill switch and raised 'something went wrong' toasts. Gate them: netReady = isLocalGame || (connection.online && !offlineMode.active) — a local game stays fully usable; an online game's make/exchange/hint/resign disable while offline and re-enable when back. Also suppress the 'offline' code in handleError (a blocked call in offline mode is expected, not a toast).
This commit is contained in:
@@ -304,7 +304,9 @@ export function handleError(err: unknown): void {
|
||||
void enterBlocked();
|
||||
return;
|
||||
}
|
||||
if (isConnectionCode(code) || !connection.online) return;
|
||||
// A blocked call in offline mode ('offline', the transport kill switch) is expected, not an error
|
||||
// to surface — the offline chrome already signals the state; never a red toast.
|
||||
if (isConnectionCode(code) || code === 'offline' || !connection.online) return;
|
||||
haptic('error');
|
||||
showToast(t(code ? errorKey(code) : 'error.generic'), 'error');
|
||||
}
|
||||
@@ -585,18 +587,28 @@ function promptOfflineChoice(): Promise<boolean> {
|
||||
* cold-start dialog) is left as the player's choice. These are passive OS events — no polling, no
|
||||
* battery cost. Web-only and skipped in the mock (the e2e drives connectivity directly).
|
||||
*/
|
||||
// tryReturnOnline is fired from the online event while in auto-offline: the interface being back does
|
||||
// not mean the gateway is reachable yet (DNS/routing settle for a moment after flight mode), so it
|
||||
// re-checks a few times with backoff before returning online, stopping if the player takes over the
|
||||
// state meanwhile. This bounded retry is what actually gets the app back online after flight mode off.
|
||||
async function tryReturnOnline(): Promise<void> {
|
||||
for (let attempt = 0; attempt < 4; attempt++) {
|
||||
if (!offlineMode.active || !offlineMode.auto) return;
|
||||
if (await checkReachable(BOOT_REACHABILITY_TIMEOUT_MS)) {
|
||||
if (offlineMode.active && offlineMode.auto) setOfflineMode(false);
|
||||
return;
|
||||
}
|
||||
await new Promise((r) => setTimeout(r, 600 * (attempt + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
export function initNetworkReactivity(): void {
|
||||
if (typeof window === 'undefined' || import.meta.env.MODE === 'mock') return;
|
||||
window.addEventListener('offline', () => {
|
||||
if (!offlineMode.active) setOfflineMode(true, false); // auto (session) — self-heals below
|
||||
});
|
||||
window.addEventListener('online', () => {
|
||||
if (offlineMode.active && offlineMode.auto) {
|
||||
void checkReachable(BOOT_REACHABILITY_TIMEOUT_MS).then((reachable) => {
|
||||
// Re-read the flags — the player may have chosen offline meanwhile — before returning online.
|
||||
if (reachable && offlineMode.active && offlineMode.auto) setOfflineMode(false);
|
||||
});
|
||||
}
|
||||
if (offlineMode.active && offlineMode.auto) void tryReturnOnline();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user