Fresh Kotlin 2.2 + Jetpack Compose app at feature parity with web/
(game logic, settings contract, voice semantics ported one-to-one with
twinned tests; 104 unit + 9 instrumentation tests). Fully offline:
VIBRATE is the only permission; Media3's ACCESS_NETWORK_STATE is
stripped. Voice clips mount from web/static/audio at build time.
Same applicationId, signing env contract, and Play alpha track;
versionCode 7 / 0.2.0. CI Android job is Gradle-only (lint, test,
debug + R8 release APK) and the release workflow fails fast on an
unbumped versionCode.
BREAKING CHANGE: WebView localStorage (settings, in-progress round)
is not migrated; wrapper users start clean.
Replace the native Kotlin/Compose port with a Capacitor 8 wrapper around
the upstream loto SvelteKit PWA. Loto is consumed as a git submodule and
its static build is bundled into the APK at sync time. The wrapper has
no INTERNET permission, so fully offline is enforced rather than
conventional.
- loto/ submodule pinned to dfb1c1e
- android/ scaffolded by cap add android; signing wired via env vars
- All 184 voice MP3s + service worker bundled in assets/public/
- CI checkouts submodule, runs npm build, then Gradle inside android/
- Native port preserved in git history at e7fb3d0 and 8b8d46e
- Remove gradient brush from "Kinh!" title, use solid BrandAmber600.
- Align with solid-color palette refactor (phase 03).
- Update button and text colors to new palette.
Upstream: a60ea08
- Minor UI alignment and spacing adjustments across master panel and
player board screens.
- Improve code consistency and readability in Compose components.
- Update project todo list with implementation notes.
Upstream: a60ea08 (sync completion)
- Add mode-specific voice hint messages (player vs master mode).
- Update VoiceToggles to show contextual hint based on current mode.
- Improve UX clarity in settings sheet.
Upstream: a60ea08
- Add sectionHasWaiting state to track which sections have rows one cell
from bingo (in Chờ state).
- Render amber ring + 1.5s pulse on section labels when section has waiting.
- Skip animation if accessibility motion is disabled.
- Add BrandAmberLight color for the ring.
Upstream: a60ea08
- Fire confetti on 2nd bingo OR 1st bingo when another row is in Chờ
(waiting for one number). Replaces old ≥3 threshold that rarely fired.
- Add Vietnamese hội-chợ emoji: 🥢🎋🏮 (chopsticks, bamboo, lantern)
- Per-particle size jitter (1.5–2.4x) for visual interest
Upstream: a60ea08
Native Android port of the SvelteKit Lô tô hội chợ Tân Tân web app.
Stack:
- Kotlin 2.1 + Jetpack Compose + Material 3
- Single Activity, single Gradle module (:app)
- Audio: AndroidX Media3 ExoPlayer with bundled MP3 voice clips
- Settings: DataStore Preferences with legacy masterMode migration
- minSdk 24, targetSdk 35, JDK 17
Game logic:
- 9x9 player card with exactly 5 numbers per row AND per column
- Soft constraint: no 3 consecutive filled columns (rejection-sampled)
- 11x9 ones-digit-aligned master tracking board
- Bingo / Cho ("waiting") state machine ported from PlayerBoard.svelte
- Forward-only auto-tick from MasterPanel via app-scoped CallBus
Audio:
- 184 MP3s pre-generated with Microsoft Edge TTS (Hoai My, Nam Minh)
- ExoPlayer playlist for cho + N gapless sequence
- Token-based cancellation matching the web voice.js semantics
CI:
- build-debug.yml: lint + test + assembleDebug on push/PR
- release.yml: signed AAB+APK on v* tag, env-driven keystore