From 9d2699cf968b47ea76d96993d94c105d05955eee Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Thu, 30 Apr 2026 21:34:06 +0700 Subject: [PATCH] refactor(active-tab): rename tab-lock to active-tab for clarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "lock" framing was misleading — there's no OS-level mutex; this is a soft coordinator that decides which tab is the active one. Rename makes the role obvious at the import site. - file: tab-lock.svelte.js → active-tab.svelte.js (+ test) - export: tabLock → activeTab - field: .frozen → .inactive (positive form: this tab is inactive) - fn: startTabLock → watchActiveTab - fn: reclaimTab → claimActiveTab - BroadcastChannel name: loto_tab_lock → loto_active_tab No behavior change. Banner copy already updated separately. --- docs/codebase-summary.md | 2 +- src/lib/active-tab.svelte.js | 61 +++++++++++++++++++ .../{tab-lock.test.js => active-tab.test.js} | 52 ++++++++-------- src/lib/tab-lock.svelte.js | 58 ------------------ src/routes/+layout.svelte | 16 ++--- 5 files changed, 96 insertions(+), 93 deletions(-) create mode 100644 src/lib/active-tab.svelte.js rename src/lib/{tab-lock.test.js => active-tab.test.js} (51%) delete mode 100644 src/lib/tab-lock.svelte.js diff --git a/docs/codebase-summary.md b/docs/codebase-summary.md index ef60dd0..5136c2f 100644 --- a/docs/codebase-summary.md +++ b/docs/codebase-summary.md @@ -23,7 +23,7 @@ |------|---------| | `src/lib/game-logic.js` | Stateless utilities: generateGrid (constraint-aware picker — exact 5 per row & per col, ascending-sorted columns, soft "no 3 consecutive filled cols per row" via rejection sampling), saveGrid, loadGrid, saveCrossedState, loadCrossedState, isRowComplete, getWaitingNumber. | | `src/lib/master-store.svelte.js` | Shared reactive `{called, remaining}` $state for the master deck, persisted to `loto_master`. Exports `masterState`, `loadMaster`, `saveMaster`, `startNewGame`, `drawNext`, `resetMaster`. Hydrated once via `+layout.svelte`'s `onMount` so player-side reads see the full history regardless of mount order. Replaced the single-slot `call-bus` to fix history-loss bugs (regen, reload, multi-tab) — see `plans/reports/code-reviewer-260430-2024-both-mode-consistency.md`. | -| `src/lib/tab-lock.svelte.js` | Single-tab guard via `BroadcastChannel`. New tab broadcasts `claim`; old tab sets `tabLock.frozen = true`. `+layout.svelte` mounts it on boot and renders a fullscreen overlay banner ("Loto đã mở ở tab khác. Tap để chuyển về tab này.") when frozen — tap calls `reclaimTab` which broadcasts back, freezing the other tab in turn. No-op in browsers without `BroadcastChannel` (legacy iOS Safari ≤15.4). Prevents double auto-call intervals, double localStorage writers, and overlapping audio across tabs. | +| `src/lib/active-tab.svelte.js` | Single-active-tab coordinator via `BroadcastChannel`. New tab broadcasts `claim`; old tab sets `activeTab.inactive = true`. `+layout.svelte` mounts `watchActiveTab()` on boot and renders a fullscreen overlay banner ("Phiên Lô tô đang chạy ở tab khác. Nhấn để tiếp tục tại đây.") when inactive — nhấn calls `claimActiveTab()` which broadcasts back, inactivating the other tab in turn. Soft coordination only (cooperating tabs); no-op in browsers without `BroadcastChannel` (legacy iOS Safari ≤15.4). Prevents double auto-call intervals, double localStorage writers, and overlapping audio across tabs. | | `src/lib/player-auto-cross.js` | Pure `applyMasterCalls({grid, crossed, called, lastHandledIndex, manualUnticks, mode})`. Cursor-by-index dedup (vs the retired `at`-timestamp model), so any caller can pass `lastHandledIndex: 0` to replay master's full history (used by player regen + "Xoá đánh dấu" in both mode). Manual unticks suppress re-cross on replay. | | `src/lib/vietnamese-number.js` | `numberToVietnamese(n)` — pure utility mapping 0..90 to spoken Vietnamese, with tonal exceptions (15 → "mười lăm", 21 → "hai mươi mốt", 25 → "hai mươi lăm"). Out-of-range falls back to `String(n)`. | | `src/lib/voice.js` | Bundled-MP3 playback. Exports `playNumber(n)`, `playWaiting(n)` (sequences cho + N), `playBingo()`, `cancelPlayback()`. Lazy `