15 Commits
Author SHA1 Message Date
tiennm99 e314ae01c8 feat(android)!: replace the Capacitor wrapper with a native Kotlin/Compose app
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.
2026-08-31 13:28:48 +07:00
tiennm99 6587df5209 ci(android): publish tagged releases to the closed testing track
Internal testing is a separate track and does not count toward the
12-tester, 14-day requirement for production access -- only a closed
test does. Releases were landing on internal, so reaching the testers
meant promoting each build by hand in the Console.

Point tracks: at alpha, the closed track, and update the publishing
guide and android README to match. An unknown track id fails the step
with the list of valid tracks rather than publishing somewhere
unintended, so the id is checked at upload time.

Builds up to v0.1.1 remain on the internal track.
2026-08-20 09:11:14 +07:00
tiennm99 1c1bab8733 build: move web/ from pnpm to npm
Replace pnpm-lock.yaml with package-lock.json and drop pnpm-workspace.yaml.
The three security overrides move to package.json#overrides, which npm reads
natively; allowBuilds for esbuild is unnecessary because npm runs dependency
build scripts by default.

android/build:web drove the web build through corepack pnpm, so it would have
broken once web/pnpm-lock.yaml was gone. It now uses npm --prefix.

Fresh resolution picks up patched versions the old lockfile had pinned below,
so npm audit reports no advisories where pnpm audit reported eight.
2026-08-17 11:54:24 +07:00
tiennm99 48d56eee30 docs(android): document permissions, back behaviour, and icon pipeline
Records what a maintainer cannot infer from the wrapper: why VIBRATE is
declared when the web build needs no equivalent, when the wake lock is
held and why it re-acquires on visibilitychange, how back maps to
overlay history, and why the textZoom pin and the in-app size setting
ship together.

Also documents where launcher art comes from, that regenerating needs
Roboto Condensed converted out of the .woff fontsource ships, and the
clipping bug still present in source.svg.

The "Why no INTERNET permission?" section is unchanged — the offline
guarantee still holds.
2026-08-14 15:21:03 +07:00
tiennm99 c6c839fd95 ci: consolidate web and android workflows into one pipeline
Both subprojects ship from the same commit, so ordinary CI is now a single
ci.yml; only the tag-driven release stands apart. The web app is built twice
per run — once per base path — and every consumer downloads the artifact
instead of rebuilding, replacing three redundant base-"" builds on main.

Nothing deploys unless the test job is green, and android-release runs the
suite before signing (ci.yml does not fire on tags, so it was the only gap).

Shared toolchain setup moves into composite actions, which puts the web build
and the APK on the same Node version for the first time. The Firebase PR path
was still on npm ci against a stale web/package-lock.json that could resolve a
different tree than pnpm-lock.yaml; drop the lockfile and the npm path with it.

Also: least-privilege permissions widened per job, persist-credentials off on
every checkout, concurrency groups that cancel superseded PRs but never a live
deploy, npm caching for android, and the Firebase action pinned by commit SHA
to match how the release actions were already pinned.
2026-08-09 15:21:23 +07:00
tiennm99 7eabfa27f9 docs: add Play Store auto-publish setup guide 2026-08-05 14:00:35 +07:00
tiennm99 d1b68b2fe4 build(android): build from web/ instead of the loto submodule
web/ and android/ now live in one repository, so the pinned submodule at
android/loto is redundant. Point Capacitor's webDir and the build script at
../web directly, and drop the pin-bumping workflow from the docs.
2026-08-03 18:02:13 +07:00
tiennm99 fe639c13c5 docs: document Android release signing 2026-07-21 14:38:08 +07:00
tiennm99 4c8fff0a25 fix: build loto submodule with pnpm 2026-07-02 09:16:14 +07:00
tiennm99 07bbefee0b feat(ci): optional Play Store auto-publish on release tags
Adds a gated step in release.yml that uploads the signed AAB to the
Google Play Console internal track when PLAY_SERVICE_ACCOUNT_JSON is
configured. No-op if the secret is missing, so existing tag releases
keep working unchanged.

Default track is 'internal' for safety; change to alpha/beta/production
once trusted. Promotion can also be done via Play Console UI.

First Play Store upload must still be manual (Google policy).
2026-05-10 02:57:35 +07:00
tiennm99 f842deb46c feat(android): make APK installable on BlueStacks and other emulators
- Declare touchscreen/faketouch/screen.portrait/screen.landscape as
  uses-feature required=false so emulators (BlueStacks reports faketouch)
  and Play Store device filters do not exclude the app.
- Drop explicit webContentsDebuggingEnabled override so Capacitor
  auto-enables WebView inspection in debug builds (chrome://inspect over
  ADB) and disables in release.
- Document the install + troubleshoot path in README.
2026-05-10 02:45:26 +07:00
tiennm99 df1bcdced1 fix(ci): bump JDK to 21 (Capacitor 8 compiles with sourceCompatibility 21) 2026-05-10 02:11:32 +07:00
tiennm99 b2c839c902 fix(ci): bump Node to 22 (Capacitor 8 CLI requires >=22) 2026-05-10 02:05:06 +07:00
tiennm99 7840aa419d feat: migrate to Capacitor wrapper for fully-offline Android
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
2026-05-10 02:03:16 +07:00
miti99 90a9dd1d1a feat: initial Android port of tiennm99/loto
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
2026-04-27 19:33:16 +07:00