Files
loto/plans/260429-1511-loto-upstream-sync/reports/xia-recon-260429-1511.md
T
tiennm99 0691665b3a chore(plans): consolidate all plans at repo root
Plans were split across three trees: plans/, web/plans/, and
android/plans/. Merge them into plans/ at the repo root.

Sweep the shipped Android experience pass and the two reports for it,
carrying the residual forward into plans/todo.md: the device QA
checklist (open only because this environment has no device or
emulator), the clipped web PWA icons defect, and the untested native
assumptions.

Merge android/plans/todo.md in the same pass, dropping items the
experience pass already delivered -- haptics, back button, safe-area
insets, launcher icon, and splash -- each verified against
MainActivity.java, web/src/app.css, and the res/ tree. Correct two
stale claims while merging: web/ is a plain directory in this monorepo,
not a git submodule, and the serialize-javascript override is held by
@rollup/plugin-terser rather than workbox-build.

The retired native Kotlin/Compose port plan moves as-is; it is
superseded by the Capacitor wrapper but not yet swept.
2026-08-19 16:09:56 +07:00

6.5 KiB
Raw Blame History

Xia Recon — Upstream tiennm99/loto → Android port sync

Source manifest

  • Repo: tiennm99/loto (SvelteKit web app, Svelte 5 + Vite 7)
  • Branch: main
  • Local clone: /config/workspace/tiennm99/loto
  • Latest commit at recon: 2fb35f2 (2026-04-29 14:53 +0700)
  • Port baseline: Android fe52232 (2026-04-27 19:33 +0700) — bundles upstream through ad6291e (2026-04-27 18:57)
  • Window of drift: 2026-04-27 19:33 → 2026-04-29 14:53 (≈ 44 h, 15 commits)

Source map (logic-relevant)

  • src/lib/game-logic.js — pure card gen, persistence, row helpers
  • src/lib/auto-tick.js — pure helper for master→player auto-tick (NEW since baseline)
  • src/lib/call-bus.svelte.js — one-slot bus
  • src/lib/settings-store.svelte.js — settings + DOM apply
  • src/lib/voice.js — bundled-MP3 playback
  • src/lib/vietnamese-number.js — number-to-words
  • src/lib/PlayerBoard.svelte — player UI + bingo/chờ state
  • src/lib/MasterPanel.svelte — host UI
  • src/lib/SettingsButton.svelte — settings modal
  • src/app.css — palette, animations, decorative borders

Local map (Android)

  • game/GameLogic.kt, game/VietnameseNumber.kt — pure logic
  • state/CallBus.kt, state/PlayerBoardViewModel.kt, state/MasterPanelViewModel.kt — coroutine state
  • audio/VoicePlayer.kt, audio/VoiceManifest.kt
  • settings/SettingsRepository.kt, settings/SettingsState.kt
  • ui/board/*, ui/master/*, ui/settings/*, ui/theme/*

Drift analysis

Commits on/after port baseline (15 total). Filtered to logic/UX-relevant:

Commit Subject Layer Port?
2fb35f2 drop gradients, solid-color palette UI YES
a60ea08 persistent Chờ ring + livelier confetti UI + tier YES
2b74b2e "Cả hai" glyph + sticky title/footer settings UI PART
3e6cb90 extract auto-tick into pure helper + tests refactor OPT
ee71bf0 per-mode voice hint copy (+ PWA fixes) copy YES
f7db20c UI polish v2 + PWA UI + web DONE
9f24b6d PWA cache eviction tighten web only NO
7c893aa CSP sha256 hash web only NO
558d0c7 inline-script guard web only NO
d94294d npm vuln overrides web only NO
chore(plans) ×4 plan docs - NO

Behavior delta (the part that matters)

1. Confetti tier rule (PlayerBoardViewModel.kt:166)

  • Was: tier = 2 if celebratedRows.size >= 3 else 1
  • Now: tier = 2 if celebratedRows.size >= 2 OR (celebratedRows.size >= 1 AND any other row in Chờ) else 1
  • Reason: 9-row card rarely hits 3 bingos; old threshold under-celebrated wins.

2. Confetti emoji + size

  • Add 🥢 🎋 🏮 to set; per-piece size jitter 1.5–2.4rem (sp).

3. Section Chờ ring

  • New sectionHasWaiting[3] derived flag — true iff any of its 3 rows is one cell from bingo and not yet completed. Section label gets persistent amber ring/glow (animation respects reduced-motion).

4. Per-mode voice-master hint

  • Mode = both → hint: "Đọc số đã xổ + báo Chờ/Kinh."
  • Mode = master→ hint: "Đọc số đã xổ."
  • Currently Android has no hint at all under the master-voice toggle.

5. Solid-color palette

  • Drop every gradient (Wordmark stays — it's the only intentional brand gradient). Use solid: rose-600 (player+UI), amber-600 (host), emerald-600 (draw), sky-600 (master ≤49).
  • Replaces master ≤49 pink → sky.
  • Player accent: indigo → rose.
  • "Ván mới" amber→rose gradient → solid amber-600.
  • Background warmer cream #fffbeb (light only).

6. Auto-tick pure helper (optional)

  • Upstream extracted processAutoTick({grid, crossed, lastDraw, lastHandledAt, mode}) into src/lib/auto-tick.js.
  • Android PlayerBoardViewModel.consumeBusEvent already implements the same dedup-by-id invariant. Optional refactor for unit-testability parity.

7. Settings sticky title/footer

  • Web fix for iPhone SE viewport (375×667).
  • Android: ModalBottomSheet already gives system-pinned drag handle
    • scroll behavior — same problem already solved by the platform. Skip.

8. "Cả hai" glyph

  • Web mode picker has SVG glyphs; Android ModePicker is text-only (SegmentedButton + Text). Skip.

Decision matrix

Decision Source's way Local equivalent Recommendation
Confetti tier 2nd OR (1st + Chờ) 3+ Port (P0 — game feel)
Confetti emoji+size + hội-chợ + jitter base set, fixed 20.sp Port (P1)
Section Chờ ring amber pulsing band - Port (P1)
Voice-master hint copy per-mode (no hint shown) Port (P2)
Solid-color palette rose/amber/emerald/sky rose/amber/emerald/pink+gr Port (P1)
Auto-tick helper extracted pure fn inline in VM (semantics ✓) Optional (P3)
Sticky modal bands sticky CSS ModalBottomSheet (native) Skip
"Cả hai" glyph inline SVG text-only segment Skip

Risk score

Low. No data-shape changes; no migration. All ports are additive (new state field, new strings, new colors) or threshold tweaks. Tests cover the existing tier rule — must update fixtures to the new threshold. No risk to DataStore schema, audio assets, or audio-call coordination.

Approach

--port mode: rewrite idiomatically for Compose/Kotlin. No transplanting Svelte/CSS — the visual outcomes get expressed in Compose primitives.

Open questions

  • Should the Confetti emoji set still ship with 🥢 🎋 🏮 on devices where the system font lacks coverage? Android default fonts since API 24 cover these. No action, but revisit if QA reports tofu glyphs on older OEM builds.
  • The amber pulsing ring uses prefers-reduced-motion. Compose has no direct equivalent; recommend gating on LocalAccessibilityManager.current reduce-motion or simply using a static glow (no animation) — defer to phase-02 implementation choice.