The Android app updates itself from our Gitea releases; feed cards fade in instead of bouncing

- API: GET /app/android/latest reads the latest Gitea release (ANDROID_RELEASES_URL, optional token for a
  private repo) with the APK's SHA-256 from SHA256SUMS; GET /app/android/apk/:name streams that APK.
- App (modules/updater): downloads in the background, checks the SHA-256, and installs through
  PackageInstaller: quietly once when leaving the app (Android 12+), otherwise from the feed banner or
  Settings > App version. F-Droid builds leave it out and drop the install permissions.
- CI: the release notes come from the fastlane changelog; the app shows the part above ---.
- Settings: Create-account and Link Spotify buttons for Last.fm and ListenBrainz.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-15 12:34:04 -04:00
co-authored by Claude Opus 5.5
parent 804493aee0
commit 5cbde5e7f9
29 changed files with 901 additions and 11 deletions
+10 -1
View File
@@ -96,7 +96,16 @@ jobs:
# Reuse the release if this tag was built before.
id=$(curl -fsS -H "$auth" "$api/releases/tags/$REF_NAME" 2>/dev/null | node -p 'JSON.parse(require("fs").readFileSync(0)).id' || true)
if [ -z "$id" ]; then
body=$(node -e 'console.log(JSON.stringify({ tag_name: process.argv[1], name: process.argv[1], body: "Android builds. musicshare-*-foss.apk has no closed-source code (no Google ML Kit)." }))' "$REF_NAME")
# The changelog first (the app shows the text above "---" as what's new), then a note for this page.
body=$(node -e '
const fs = require("fs");
const code = require("../apps/mobile/app.json").expo.android.versionCode;
const file = `../fastlane/metadata/android/en-US/changelogs/${code}.txt`;
const notes = fs.existsSync(file) ? fs.readFileSync(file, "utf8").trim() : "";
const note = "musicshare-*-foss.apk has no closed-source code (no Google ML Kit); it does not update itself.";
const tag = process.argv[1];
console.log(JSON.stringify({ tag_name: tag, name: tag, body: notes ? `${notes}\n\n---\n${note}` : `---\n${note}` }));
' "$REF_NAME")
id=$(curl -fsS -X POST -H "$auth" -H 'Content-Type: application/json' -d "$body" "$api/releases" | node -p 'JSON.parse(require("fs").readFileSync(0)).id')
fi
for f in *.apk SHA256SUMS; do