From 3bb6b3d63129d9b6abfc6cd913c1ea17ab68700f Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Fri, 14 Aug 2026 15:20:32 +0700 Subject: [PATCH] feat(android): close behaviour gaps between the APK and the browser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../android/app/src/main/AndroidManifest.xml | 7 + .../java/com/miti99/loto/MainActivity.java | 71 ++++++++- .../app/src/main/res/values/strings.xml | 10 +- .../app/src/main/res/values/styles.xml | 15 ++ web/src/app.css | 36 +++++ web/src/app.html | 7 +- web/src/lib/MasterPanel.svelte | 19 ++- web/src/lib/PlayerBoard.svelte | 17 +- web/src/lib/SettingsButton.svelte | 57 ++++++- web/src/lib/overlay-history.js | 92 +++++++++++ web/src/lib/overlay-history.test.js | 107 +++++++++++++ web/src/lib/settings-store.svelte.js | 29 ++++ web/src/lib/settings-store.test.js | 60 +++++++ web/src/lib/wake-lock.js | 128 +++++++++++++++ web/src/lib/wake-lock.test.js | 148 ++++++++++++++++++ 15 files changed, 790 insertions(+), 13 deletions(-) create mode 100644 web/src/lib/overlay-history.js create mode 100644 web/src/lib/overlay-history.test.js create mode 100644 web/src/lib/wake-lock.js create mode 100644 web/src/lib/wake-lock.test.js diff --git a/android/android/app/src/main/AndroidManifest.xml b/android/android/app/src/main/AndroidManifest.xml index 1f75722..a902c34 100644 --- a/android/android/app/src/main/AndroidManifest.xml +++ b/android/android/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ + + + diff --git a/android/android/app/src/main/java/com/miti99/loto/MainActivity.java b/android/android/app/src/main/java/com/miti99/loto/MainActivity.java index a424a24..8213258 100644 --- a/android/android/app/src/main/java/com/miti99/loto/MainActivity.java +++ b/android/android/app/src/main/java/com/miti99/loto/MainActivity.java @@ -1,5 +1,74 @@ package com.miti99.loto; +import android.media.AudioManager; +import android.os.Bundle; +import android.webkit.WebView; +import androidx.activity.OnBackPressedCallback; +import androidx.appcompat.app.AlertDialog; +import com.getcapacitor.Bridge; import com.getcapacitor.BridgeActivity; -public class MainActivity extends BridgeActivity {} +public class MainActivity extends BridgeActivity { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + WebView webView = webView(); + if (webView != null) { + // The player card is a fixed 9-column grid, so the system font + // scale (users routinely run 130-200%) clips two-digit numbers + // out of their cells. Pinning the zoom is only defensible + // because the app ships its own size control in Settings + // ("Cỡ chữ bảng") as the accessible replacement. + webView.getSettings().setTextZoom(100); + } + + // Calling numbers aloud is the app's whole job, so the volume rocker + // should reach the media stream even before the first clip plays. + setVolumeControlStream(AudioManager.STREAM_MUSIC); + + // Android 16 (targetSdk 36) no longer calls onBackPressed() and no + // longer dispatches KEYCODE_BACK, so back has to come through the + // dispatcher. Each open overlay pushes one history entry (see + // web/src/lib/overlay-history.js), which makes "the WebView can go + // back" mean exactly "an overlay is open". + getOnBackPressedDispatcher() + .addCallback( + this, + new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + WebView wv = webView(); + if (wv != null && wv.canGoBack()) { + wv.goBack(); + return; + } + confirmExit(); + } + } + ); + } + + /** Null-safe accessor — the bridge is built during super.onCreate(). */ + private WebView webView() { + Bridge bridge = getBridge(); + return bridge == null ? null : bridge.getWebView(); + } + + /** + * Auto-call runs untouched for minutes at a time, so a stray back press + * at the root would otherwise drop the caller out of a live round. + */ + private void confirmExit() { + // Explicit AppCompat dialog theme: the activity runs on + // AppTheme.NoActionBarLaunch (parent Theme.SplashScreen), which is + // not guaranteed to be AppCompat-derived at dialog time. + new AlertDialog.Builder(this, R.style.AppTheme_ExitDialog) + .setTitle(R.string.exit_title) + .setMessage(R.string.exit_message) + .setNegativeButton(R.string.exit_cancel, null) + .setPositiveButton(R.string.exit_confirm, (dialog, which) -> finish()) + .show(); + } +} diff --git a/android/android/app/src/main/res/values/strings.xml b/android/android/app/src/main/res/values/strings.xml index a9d2fb9..78696c9 100644 --- a/android/android/app/src/main/res/values/strings.xml +++ b/android/android/app/src/main/res/values/strings.xml @@ -1,7 +1,13 @@ - Lo To - Lo To + Lô tô + Lô tô com.miti99.loto com.miti99.loto + + + Thoát Lô tô? + Ván đang chơi sẽ được lưu lại. + Thoát + Ở lại diff --git a/android/android/app/src/main/res/values/styles.xml b/android/android/app/src/main/res/values/styles.xml index be874e5..aeffeb8 100644 --- a/android/android/app/src/main/res/values/styles.xml +++ b/android/android/app/src/main/res/values/styles.xml @@ -17,6 +17,21 @@ + + +