Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac144f2eb1 | ||
|
|
31fcaf8282 | ||
|
|
b6d8f4e234 | ||
|
|
862b029953 | ||
|
|
a672268a8f |
@@ -6,6 +6,10 @@ Backgammon Galaxy control. Defaults to 3:00 + 12s.
|
||||
|
||||
Plain HTML, CSS and JavaScript. No frameworks, no fonts, no images, no network.
|
||||
|
||||
There's an Android package too, in `android/` — a WebView around the same
|
||||
`public_html/`, so the two can't drift. It declares no permissions at all. See
|
||||
[RELEASING.md](RELEASING.md) for how to cut a new version for F-Droid.
|
||||
|
||||
## Getting it onto your phone
|
||||
|
||||
Chrome will only offer a real install over HTTPS, so the file needs a host.
|
||||
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
# Releasing a new version
|
||||
|
||||
The clock lives in two places: the web app in `public_html/`, which you host
|
||||
yourself, and the Android app on F-Droid, which is built from a git tag.
|
||||
|
||||
**Everything F-Droid needs comes from a tag in this repository.** After the first
|
||||
release was accepted there is nothing to do in F-Droid's own repo — their bot
|
||||
watches the tags here and writes the build entry itself. Don't open a merge
|
||||
request against `fdroiddata` for a new version.
|
||||
|
||||
Worked example below bumps 1.0 to 1.1. Substitute your own numbers.
|
||||
|
||||
## 1. Make the change
|
||||
|
||||
Both versions share one copy of the app. Edit `public_html/index.html` and the
|
||||
Android build picks it up automatically — the Gradle build reads `public_html/`
|
||||
directly rather than keeping a second copy, so the two can't drift.
|
||||
|
||||
If you changed anything visible, bump the service worker cache or installed web
|
||||
users will keep the old page:
|
||||
|
||||
```
|
||||
# public_html/sw.js
|
||||
const CACHE = "bgclock-v18"; # any new value; it only has to differ
|
||||
```
|
||||
|
||||
## 2. Bump the version
|
||||
|
||||
In `android/app/build.gradle.kts`:
|
||||
|
||||
```kotlin
|
||||
versionCode = 2 // an integer, +1 every release, never reused
|
||||
versionName = "1.1" // what people see
|
||||
```
|
||||
|
||||
`versionCode` is what Android uses to decide one version is newer than another.
|
||||
It must go up every single release, even for a one-character fix.
|
||||
|
||||
## 3. Write the changelog
|
||||
|
||||
A new file named after the **versionCode**, not the version name:
|
||||
|
||||
```
|
||||
fastlane/metadata/android/en-US/changelogs/2.txt
|
||||
```
|
||||
|
||||
Maximum 500 characters. This is what shows up in F-Droid's "What's New".
|
||||
|
||||
## 4. Build it and put it on your phone
|
||||
|
||||
```bash
|
||||
export ANDROID_HOME="$HOME/Android/Sdk" # already in ~/.bashrc
|
||||
cd android
|
||||
./gradlew assembleDebug
|
||||
adb install -r app/build/outputs/apk/debug/app-debug.apk
|
||||
./gradlew --stop # the daemon holds ~500 MB otherwise
|
||||
```
|
||||
|
||||
Play a real game before tagging. Worth checking specifically: start a match,
|
||||
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
|
||||
working, and it fails silently rather than loudly.
|
||||
|
||||
## 5. Commit, tag, push
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "…"
|
||||
git tag -a v1.1 -m "Backgammon Clock 1.1"
|
||||
git push
|
||||
git push origin v1.1
|
||||
```
|
||||
|
||||
Keep tags in the `v1.1` shape for consistency, but nothing depends on it:
|
||||
`UpdateCheckMode: Tags` with no pattern matches every tag whatever it's called,
|
||||
and F-Droid's bot resolves whichever tag it finds to a commit hash before it
|
||||
writes the build entry.
|
||||
|
||||
Never move or delete a tag that has been pushed — F-Droid may already have built
|
||||
it. If a release is wrong, bump the version and release again. (The recipe pins
|
||||
a hash, so a moved tag can't retroactively change a version they already built;
|
||||
it would just leave your repo disagreeing with what's on people's phones.)
|
||||
|
||||
**If you ever write a build entry by hand**, its `commit:` must be a full 40-char
|
||||
commit hash — never a tag, never a branch. Tags are mutable, so a tag there means
|
||||
the thing F-Droid builds and signs can change under them, and they reject it on
|
||||
sight. This came up on the very first submission and is easy to get wrong,
|
||||
because `fdroid lint` doesn't check it under `UpdateCheckMode: Tags` — the
|
||||
pipeline goes green and a human catches it days later. Get the hash with:
|
||||
|
||||
```bash
|
||||
git rev-parse v1.1^{commit} # ^{commit}, or an annotated tag gives you the
|
||||
# tag object's hash instead of the commit's
|
||||
```
|
||||
|
||||
This doesn't come up in a normal release: the bot writes the entry, and the bot
|
||||
writes hashes.
|
||||
|
||||
## 6. Wait
|
||||
|
||||
Their bot notices the new tag, adds a build entry, and the build server picks it
|
||||
up on its next cycle. Expect a day or two. Nothing to do.
|
||||
|
||||
## Deploying the web version
|
||||
|
||||
Separate from all of the above, and manual: upload the six files in
|
||||
`public_html/` — `index.html`, `manifest.webmanifest`, `sw.js`, `icon-192.png`,
|
||||
`icon-512.png`, `icon-maskable-512.png` — to the web host. `README.md` and
|
||||
`RELEASING.md` stay out of it; they live in the repo root for that reason.
|
||||
|
||||
## If the screenshots need redoing
|
||||
|
||||
`fastlane/metadata/android/en-US/images/phoneScreenshots/` holds five shots at
|
||||
1170×2532. They are generated from `public_html/index.html` itself with headless
|
||||
Chromium, not taken on a phone, so they can be regenerated exactly. Two traps if
|
||||
you do it by hand:
|
||||
|
||||
- The capture lands whenever the virtual-time budget runs out, not when your
|
||||
script finishes — so freeze the render loop (`requestAnimationFrame = () => 0`)
|
||||
once the frame you want is on screen.
|
||||
- CSS transitions don't advance under `--virtual-time-budget`, so a panel caught
|
||||
mid-transition photographs in its *old* colour. Disable transitions in the
|
||||
screenshot build.
|
||||
|
||||
## Reference
|
||||
|
||||
- App ID: `nl.hansdezwart.bgclock` — fixed forever; changing it makes a new app.
|
||||
- F-Droid listing text: `fastlane/metadata/android/en-US/` (title ≤50 chars,
|
||||
summary ≤80, description ≤4000, changelog ≤500). Only these HTML tags work in
|
||||
the description: `b big blockquote br cite em i li ol small strike strong sub
|
||||
sup tt u ul`.
|
||||
- The original submission: https://gitlab.com/fdroid/fdroiddata/-/merge_requests/45478
|
||||
- F-Droid signs the APK with their key, not yours. Reproducible builds were
|
||||
declined at submission and can't be enabled later for this app ID.
|
||||
@@ -12,8 +12,8 @@ android {
|
||||
applicationId = "nl.hansdezwart.bgclock"
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
versionCode = 2
|
||||
versionName = "1.1"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
|
||||
@@ -95,23 +95,29 @@ public class MainActivity extends Activity {
|
||||
if (hasFocus) hideSystemBars();
|
||||
}
|
||||
|
||||
/** The page calls requestFullscreen(), which a WebView ignores. This is that. */
|
||||
/**
|
||||
* The page calls requestFullscreen(), which a WebView ignores. This is that.
|
||||
*
|
||||
* Only the status bar goes. The navigation bar stays: it is how you leave the
|
||||
* app, and leaving it visible makes that obvious rather than a remembered
|
||||
* swipe. statusBars() rather than systemBars() — the latter is the union of
|
||||
* the two.
|
||||
*/
|
||||
private void hideSystemBars() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
WindowInsetsController c = getWindow().getInsetsController();
|
||||
if (c != null) {
|
||||
c.hide(WindowInsets.Type.systemBars());
|
||||
c.hide(WindowInsets.Type.statusBars());
|
||||
c.setSystemBarsBehavior(
|
||||
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
|
||||
}
|
||||
} else {
|
||||
// no IMMERSIVE_STICKY or HIDE_NAVIGATION here: immersive only governs
|
||||
// a hidden navigation bar, and this one stays
|
||||
getWindow().getDecorView().setSystemUiVisibility(
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
The navigation bar at the bottom of the screen now stays visible while you
|
||||
play, so switching to another app is easy. Only the status bar is hidden.
|
||||
|
||||
The description in F-Droid has been rewritten to spell out what the clock can
|
||||
actually do.
|
||||
@@ -1,21 +1,21 @@
|
||||
A backgammon clock for two players sharing one phone between them. Reserve time plus a fixed number of free seconds each turn that never carry over. Defaults to 3:00 with a 12 second delay.
|
||||
A backgammon clock and scorekeeper for two players sharing one phone between them.
|
||||
|
||||
It asks for no permissions at all. There is no network access, no analytics, no accounts, no ads, and nothing to configure before you can play. The whole clock is a single HTML file inside the app.
|
||||
The app asks for no permissions at all. There is no network access, no analytics, no accounts, no ads, and nothing to configure before you can use it. The whole clock is a single HTML file inside the app.
|
||||
|
||||
Tap your own half to end your turn and start your opponent's clock.
|
||||
<b>Features</b>
|
||||
|
||||
<b>Matches</b>
|
||||
- Large area with the remaining total time/delay time for this move. Tap on your half to end your turn and start your opponent's clock.
|
||||
- Set the number of points to play for (1, 3, 5, 7, …, 29).
|
||||
- Set the reserve time per point (e.g. 2 minutes or 3 minutes), in 15-second increments.
|
||||
- Set the delay (free seconds every turn which don't carry over to the next turn), in 1 second increments.
|
||||
- Choose 1 of 5 colour schemes.
|
||||
- Turn sounds (for the turn change, when the delay runs out, and when the time runs out) on or off.
|
||||
- Pause/play the clocks.
|
||||
- Number of moves for this game and current score (when playing a multi-point match) are always shown.
|
||||
- Once a game is done, click the score icon in the middle to set the score. The clocks stay at their current time.
|
||||
- Adjust the clocks from the score sheet, if necessary.
|
||||
- Press the reset button twice (within 2 seconds, so you can't press it accidentally) to reset the clock and scores and start a new match.
|
||||
- Keeps running in the background, returns to the last known clock timings and scores after a crash or forced quit.
|
||||
- The screen stays awake while you play.
|
||||
|
||||
Set the match length to any odd number of points up to 29. The time you set is per point, so a 5-point match at 2:00 a point puts 10:00 on each clock. Each half of the screen reads the score from that player's own side of the board, so both players see their own score on the top line.
|
||||
|
||||
At one point there is no match to keep score of, and the score lines disappear entirely — you get a plain single-game clock with a move count.
|
||||
|
||||
<b>It survives being closed</b>
|
||||
|
||||
Settings and the match in progress are kept on the device: the score, both clocks, the move counts, whose turn it is and how much delay was left. Force-quit it mid-match and it all comes back. The one thing it can't restore is time that passed while the app was closed, so it returns paused rather than charging anyone for the gap — a crash shouldn't decide a game.
|
||||
|
||||
Pause freezes mid-turn and resumes exactly where it stopped, delay included. Reset takes two taps, so one stray thumb can't wipe a live match.
|
||||
|
||||
Five colour schemes, three sounds generated on the fly, and the screen stays awake while you play.
|
||||
|
||||
Design is by Hans de Zwart, partially inspired by the Chess.com clock. Code is by Claude Opus.
|
||||
Functional design is by Hans de Zwart, partially inspired by the open sourced Chess.com clock. Code is by Claude Opus.
|
||||
|
||||
@@ -1 +1 @@
|
||||
A flexible two-player backgammon match clock with a visible delay.
|
||||
A flexible two-player backgammon match clock and scorekeeper.
|
||||
|
||||
Reference in New Issue
Block a user