tiennm99 3bb6b3d631 feat(android): close behaviour gaps between the APK and the browser
Several behaviours diverged between the web build and the Capacitor
wrapper, none of them reproducible on a desktop browser.

- Declare VIBRATE. PlayerBoard calls navigator.vibrate() on every cell
  tap; a WebView app must hold the permission itself, where a browser
  holds it on the page's behalf. Taps were silent in the APK.
- Hold a screen wake lock while numbers remain to be called. Auto-call
  advances on a timer with no touch input, so a round could run 15
  minutes untouched — long enough for the display to sleep and the
  WebView to throttle the interval. Android drops the lock whenever the
  page hides, so wake-lock.js re-acquires on visibilitychange.
- Handle back through OnBackPressedCallback. Android 16 (targetSdk 36)
  no longer calls onBackPressed() nor dispatches KEYCODE_BACK. Each open
  overlay pushes one history entry, so "the WebView can go back" means
  "an overlay is open": back closes the bingo modal or settings sheet,
  and only at the root does it confirm before quitting. Browsers get the
  overlay behaviour too.
- Inset content by env(safe-area-inset-*) with viewport-fit=cover.
  targetSdk 36 forces edge-to-edge, so the WebView painted under the
  status bar and gesture nav. Also fixes the iOS PWA notch.
- Pin the WebView's textZoom to 100 and add a "Cỡ chữ bảng" setting.
  The player card is a fixed 9-column grid that clips at large system
  font scales. Pinning the zoom overrides an accessibility control, so
  the app now owns an equivalent one; the two belong together.
- Point the volume rocker at the media stream, so it works before the
  first clip plays.

strings.xml also gains the exit-dialog strings and picks up the
diacritics in app_name.
2026-08-14 15:20:32 +07:00

Lô Tô

Lô tô hội chợ — Vietnamese fairground bingo. One number caller, two shipping targets: a static web app and a fully-offline Android APK that wraps it.

Live: tiennm99.github.io/loto

Layout

Path What it is
web/ SvelteKit static app — the game itself. pnpm, Vitest, deployed to GitHub Pages and Firebase Hosting.
android/ Capacitor wrapper that bundles web/build into an APK. npm + Gradle; the native project sits in android/android/.

android/ builds web/ as part of its own build, so a change under web/ reaches the APK on the next npm run build in android/. There is no version pin between them — they ship from the same commit.

Quick start

# web
cd web && pnpm install && pnpm dev

# android debug APK (builds web/ first)
cd android && npm ci && npm run build && npm run assemble:debug

Per-project detail lives in web/README.md and android/README.md.

CI

Workflows live at the repository root in .github/workflows/. Because both subprojects ship from the same commit, ordinary CI is a single ci.yml; only the tag-driven release stands apart.

Workflow Trigger Result
ci push to main or PR touching web/ or android/ see the job graph below
android-release tag v*.*.* tests, then a signed AAB + APK on the GH Release, plus Play Store internal-track upload

ci builds the web app exactly twice — once per base path — and every consumer downloads the artifact rather than rebuilding it:

test (pnpm test)
└── build (root, base "")   ── deploy-firebase   push to main
    │                       ├─ preview-firebase  PR from this repo
    │                       └─ android-debug     unsigned APK artifact
    └── build (gh, base /loto) ── deploy-pages    push to main

Nothing deploys unless test is green. Deploy jobs are skipped on pull requests, and the Firebase preview is skipped for PRs from forks, which cannot read the service-account secret.

Shared toolchain setup lives in .github/actions/setup-web and .github/actions/setup-android — composite actions used by both workflows, so Node stays on one version across the web build and the APK.

Release/secret setup for the Play Store pipeline is documented in docs/play-store-publishing.md.

History

This repository is the merge of the former tiennm99/loto (now web/) and tiennm99/loto-android (now android/). Both histories are preserved commit for commit and interleaved in commit-time order under a single root, so git log reads as one timeline and git log -- web/ or git log -- android/ each resolve on the current paths.

License

Apache-2.0 — see LICENSE.

S
Description
Lô Tô (Vietnamese lottery bingo) number board — Next.js web app
Readme
3.7 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 89.9%
CSS 8%
JavaScript 2.1%