Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f1b246679 | ||
|
|
3a7eb8c612 |
@@ -61,6 +61,14 @@ make some moves, force-quit from the task switcher and reopen — everything
|
|||||||
should come back, paused. That is the check that proves the app's storage is
|
should come back, paused. That is the check that proves the app's storage is
|
||||||
working, and it fails silently rather than loudly.
|
working, and it fails silently rather than loudly.
|
||||||
|
|
||||||
|
**Let the turn run at least 40 seconds before you quit.** This is the whole
|
||||||
|
check, and doing it any faster proves nothing: for the first 12 seconds of a
|
||||||
|
turn the delay absorbs everything and the reserve clock is *supposed* to sit
|
||||||
|
still, so a clock that has lost its place looks exactly like one that hasn't.
|
||||||
|
Quit well past the delay and the time must come back lower than it was at the
|
||||||
|
turn switch — and the delay counter must not be sitting at a full 12. That is
|
||||||
|
how a broken save hid from this check from 1.0 to 1.3.
|
||||||
|
|
||||||
## 5. Commit, tag, push
|
## 5. Commit, tag, push
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ android {
|
|||||||
applicationId = "nl.hansdezwart.bgclock"
|
applicationId = "nl.hansdezwart.bgclock"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 4
|
versionCode = 5
|
||||||
versionName = "1.3"
|
versionName = "1.4"
|
||||||
}
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
|||||||
@@ -121,8 +121,15 @@ public class MainActivity extends Activity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// forwarded so the page's visibilitychange fires — that is what calls
|
// Forwarded so the WebView stops its timers, animations and audio while the
|
||||||
// saveGame() and nudges the audio context back after backgrounding
|
// app is in the background, and picks them up again on return.
|
||||||
|
//
|
||||||
|
// This does NOT drive the page's visibilitychange — an earlier comment here
|
||||||
|
// claimed it did, and the saved match quietly depended on that being true.
|
||||||
|
// Document visibility follows the WebView's view and window visibility, not
|
||||||
|
// this call, so the page can be killed without ever hearing about it. The
|
||||||
|
// page no longer relies on being told: it writes the match to localStorage
|
||||||
|
// once a second while a clock is running.
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
Fixes a match not coming back correctly after the app is force-quit. The clock
|
||||||
|
returned to where it stood at the last turn change, losing the time spent on
|
||||||
|
the turn that was interrupted. The match is now written down once a second
|
||||||
|
while a clock is running, so at most a second can be lost.
|
||||||
+16
-1
@@ -1051,11 +1051,26 @@
|
|||||||
if(st.phase === PAUSE && st.active < 0) st.phase = IDLE; // can't be mid-turn with no turn
|
if(st.phase === PAUSE && st.active < 0) st.phase = IDLE; // can't be mid-turn with no turn
|
||||||
}
|
}
|
||||||
|
|
||||||
// the only hooks iOS reliably fires before killing an app
|
// The hooks iOS fires before killing an app. Android's WebView is the problem
|
||||||
|
// child: neither of these is guaranteed there, whatever MainActivity's
|
||||||
|
// onPause() forwarding suggests, and when they don't fire the newest save is
|
||||||
|
// the one tap() wrote — which carries held ≈ 0, because tap() sets turnAt and
|
||||||
|
// saves in the same breath. Reopening then hands back the entire turn, and
|
||||||
|
// the bug hides in plain sight: quit inside the delay window and a clock that
|
||||||
|
// correctly hasn't moved looks exactly like a clock that lost its place.
|
||||||
document.addEventListener("visibilitychange", function(){
|
document.addEventListener("visibilitychange", function(){
|
||||||
if(document.visibilityState === "hidden") saveGame();
|
if(document.visibilityState === "hidden") saveGame();
|
||||||
});
|
});
|
||||||
window.addEventListener("pagehide", saveGame);
|
window.addEventListener("pagehide", saveGame);
|
||||||
|
// a different signal from visibilitychange, and it does fire when Android's
|
||||||
|
// task switcher opens. saveGame() is idempotent, so an extra call is free
|
||||||
|
window.addEventListener("blur", saveGame);
|
||||||
|
|
||||||
|
// and the one that doesn't depend on being told anything: a second is the
|
||||||
|
// most a force-quit can now cost, which is well inside the delay nobody is
|
||||||
|
// charged for. A timer rather than a hook in loop(), because rAF stops when
|
||||||
|
// the page is hidden — exactly when this matters most.
|
||||||
|
setInterval(function(){ if(st.phase === RUN) saveGame(); }, 1000);
|
||||||
|
|
||||||
/* Reset is a hold, not a tap. It used to be two taps inside 2s, and a test
|
/* Reset is a hold, not a tap. It used to be two taps inside 2s, and a test
|
||||||
user found the button, tapped it once and gave up — which is exactly what
|
user found the button, tapped it once and gave up — which is exactly what
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
/* Cache-first: once installed the clock never touches the network again. */
|
/* Cache-first: once installed the clock never touches the network again. */
|
||||||
const CACHE = "bgclock-v19";
|
const CACHE = "bgclock-v20";
|
||||||
const FILES = [
|
const FILES = [
|
||||||
"./",
|
"./",
|
||||||
"./index.html",
|
"./index.html",
|
||||||
|
|||||||
Reference in New Issue
Block a user