From 83570b22b5ba5b30070ec4fc49150efac44ba67a Mon Sep 17 00:00:00 2001 From: marc Date: Sun, 6 Sep 2026 20:27:27 +0200 Subject: [PATCH] refactor(android): Web-Adresse aus BuildConfig statt als vierte Einstellung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Host stand ohnehin schon beim Bauen fest, weil die App-Links ihn im Manifest brauchen. Ihn zusaetzlich als Einstellung zu fuehren hiess: eine vierte Adresse pflegen, die vom Manifest abweichen kann, ohne dass es jemand merkt — und der Teilen-Eintrag versteckte sich, solange sie leer war, was beim Suchen schlicht wie ein fehlendes Feature aussah. Jetzt kommt beides aus -PnovasonicHost=…: das Manifest fuer eingehende Links, BuildConfig.SHARE_HOST fuer ausgehende. Die Einstellung samt Speicherfeld ist entfernt, Teilen ist immer sichtbar. versionCode 5 / 1.2, APK hochgeladen. Co-Authored-By: Claude Opus 5 --- CHANGELOG.md | 7 ++++-- android/app/build.gradle.kts | 8 ++++-- .../com/novasonic/app/data/PrefsStore.kt | 5 ---- .../com/novasonic/app/ui/AppNavigation.kt | 25 +++++++++---------- .../novasonic/app/ui/screen/SettingsScreen.kt | 6 ----- .../app/viewmodel/SettingsViewModel.kt | 4 --- 6 files changed, 23 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c692e6..9e814c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -150,6 +150,10 @@ Versioning: two-part `MAJOR.MINOR` — each release bumps the minor (features an mutiert, um unter Windows das Neuaufbauen der Medienkachel zu vermeiden. Über MPRIS kam davon nichts an: Plasma-Widgets zeigten dauerhaft den zuerst gespielten Titel. Bei echtem Titelwechsel wird jetzt ein neues `MediaMetadata` zugewiesen, sonst weiter in-place (Cover-Nachladen). +- **Android 1.2 (versionCode 5)** — die Web-Adresse ist keine Einstellung mehr, sondern kommt aus + `BuildConfig.SHARE_HOST`, also aus **derselben** Angabe (`-PnovasonicHost=…`), die ohnehin für die + App-Links ins Manifest wandert. Damit gibt es keine vierte Adresse zu pflegen, „Teilen" ist immer + sichtbar, und ein- und ausgehende Links können nicht mehr auseinanderlaufen. - **Android 1.1 (versionCode 4)** — erste Version mit Teilen-Link, Songlöschen, Playlist aus dem Import und Duell-Anzeigetafel. Wichtig für den In-App-Updater: er vergleicht den `versionCode` aus der Gitea-Release-Beschreibung mit dem der installierten App. Wird die Version nicht angehoben @@ -163,8 +167,7 @@ Versioning: two-part `MAJOR.MINOR` — each release bumps the minor (features an nicht erneut losspielt. Als installierte PWA landet der Link dank `launch_handler` im bereits offenen Fenster. Android teilt über den Systemdialog (`ACTION_SEND`) und empfängt Links per App-Link-Intent-Filter; der Host kommt beim Bauen aus `-PnovasonicHost=…`, die Web-Adresse für - ausgehende Links aus den Einstellungen — **ohne diese Einstellung erscheint „Teilen" im - Kontextmenü nicht**, weil es ohne Adresse keinen Link zu bauen gäbe. Für das Öffnen ohne Nachfrage muss der SHA-256 des + ausgehende Links aus derselben Angabe (seit 1.2, vorher eine eigene Einstellung). Für das Öffnen ohne Nachfrage muss der SHA-256 des Release-Schlüssels in `public/.well-known/assetlinks.json` stehen — Anleitung in `docs/share-links.md`. Ohne diesen Schritt öffnet der Link die Web-App im Browser. - **Android: Songs von der Festplatte löschen** — im Song-Kontextmenü, unten abgesetzt und rot, mit diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 2972057..3d3657e 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -14,8 +14,8 @@ android { applicationId = "com.novasonic.app" minSdk = 26 targetSdk = 35 - versionCode = 4 - versionName = "1.1" + versionCode = 5 + versionName = "1.2" // Host der eigenen NovaSonic-Web-App — Ziel der geteilten Links. Einmal in // gradle.properties setzen (novasonicHost=music.example.com); ohne Angabe bleibt der // Platzhalter stehen und der App-Link greift schlicht nicht. @@ -28,6 +28,10 @@ android { val host2 = (project.findProperty("novasonicHost2") as String?) ?: host1 manifestPlaceholders["shareHost"] = host1 manifestPlaceholders["shareHost2"] = host2 + // Derselbe Host auch fuer AUSGEHENDE Links. Er steht ohnehin schon fest im Manifest, eine + // zusaetzliche Einstellung in der App waere also nur eine weitere Adresse zum Pflegen — + // und eine, die vom Manifest abweichen koennte, ohne dass es jemand merkt. + buildConfigField("String", "SHARE_HOST", "\"$host1\"") } buildFeatures { diff --git a/android/app/src/main/kotlin/com/novasonic/app/data/PrefsStore.kt b/android/app/src/main/kotlin/com/novasonic/app/data/PrefsStore.kt index f6e45ef..76da7c3 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/data/PrefsStore.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/data/PrefsStore.kt @@ -19,8 +19,6 @@ class PrefsStore(private val context: Context) { val KEY_LASTFM_KEY = stringPreferencesKey("lastfm_key") val KEY_BACKEND_URL = stringPreferencesKey("backend_url") val KEY_SCROBBLE_URL = stringPreferencesKey("scrobble_url") - // Adresse der eigenen NovaSonic-Web-App — Basis der geteilten Links. - val KEY_WEB_URL = stringPreferencesKey("web_url") val KEY_SCROBBLE_MODE = stringPreferencesKey("scrobble_mode") val KEY_SHOW_COUNT = booleanPreferencesKey("show_play_count") val KEY_THEME = stringPreferencesKey("theme") @@ -44,7 +42,6 @@ class PrefsStore(private val context: Context) { val lastFmKey: String = "", val backendUrl: String = "", val scrobbleUrl: String = "", - val webUrl: String = "", val scrobbleMode: String = "30s", val showPlayCount: Boolean = false, val theme: String = "dark-ocean", @@ -76,7 +73,6 @@ class PrefsStore(private val context: Context) { lastFmKey = prefs[KEY_LASTFM_KEY] ?: "", backendUrl = prefs[KEY_BACKEND_URL] ?: "", scrobbleUrl = prefs[KEY_SCROBBLE_URL] ?: "", - webUrl = prefs[KEY_WEB_URL] ?: "", scrobbleMode = prefs[KEY_SCROBBLE_MODE] ?: "30s", showPlayCount = prefs[KEY_SHOW_COUNT] ?: false, theme = prefs[KEY_THEME] ?: "dark-ocean", @@ -112,7 +108,6 @@ class PrefsStore(private val context: Context) { prefs[KEY_LASTFM_KEY] = settings.lastFmKey prefs[KEY_BACKEND_URL] = settings.backendUrl prefs[KEY_SCROBBLE_URL] = settings.scrobbleUrl - prefs[KEY_WEB_URL] = settings.webUrl.trimEnd('/') prefs[KEY_SCROBBLE_MODE] = settings.scrobbleMode prefs[KEY_SHOW_COUNT] = settings.showPlayCount prefs[KEY_THEME] = settings.theme diff --git a/android/app/src/main/kotlin/com/novasonic/app/ui/AppNavigation.kt b/android/app/src/main/kotlin/com/novasonic/app/ui/AppNavigation.kt index 1048e83..9742c8e 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/ui/AppNavigation.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/ui/AppNavigation.kt @@ -609,19 +609,18 @@ fun AppNavigation() { contextMenuSong = null }, // Link auf die eigene Web-App, den der Empfaenger mit SEINEN Zugangsdaten oeffnet — - // uebertragen wird nur die Song-Id, kein Geheimnis. Ohne konfigurierten Host waere - // der Link unbrauchbar, deshalb erscheint der Eintrag dann gar nicht erst. - onShare = appSettings.webUrl.takeIf { it.isNotBlank() }?.let { host -> - { - val link = "${host.trimEnd('/')}/?song=${song.id}" - val text = listOfNotNull(song.title, song.artist).joinToString(" — ") - context.startActivity(android.content.Intent.createChooser( - android.content.Intent(android.content.Intent.ACTION_SEND).apply { - type = "text/plain" - putExtra(android.content.Intent.EXTRA_SUBJECT, text) - putExtra(android.content.Intent.EXTRA_TEXT, "$text\n$link") - }, "Song teilen")) - } + // uebertragen wird nur die Song-Id, kein Geheimnis. Der Host kommt aus BuildConfig + // (dieselbe Angabe wie fuer die App-Links im Manifest), damit es keine vierte + // Adresse zum Pflegen gibt und beide Richtungen nie auseinanderlaufen koennen. + onShare = { + val link = "https://${com.novasonic.app.BuildConfig.SHARE_HOST}/?song=${song.id}" + val text = listOfNotNull(song.title, song.artist).joinToString(" — ") + context.startActivity(android.content.Intent.createChooser( + android.content.Intent(android.content.Intent.ACTION_SEND).apply { + type = "text/plain" + putExtra(android.content.Intent.EXTRA_SUBJECT, text) + putExtra(android.content.Intent.EXTRA_TEXT, "$text\n$link") + }, "Song teilen")) }, // Nur mit Backend: das Loeschen laeuft ueber /api/delete-song, Navidrome allein // kann keine Dateien entfernen. diff --git a/android/app/src/main/kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt b/android/app/src/main/kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt index d385bd4..98f7893 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/ui/screen/SettingsScreen.kt @@ -210,12 +210,6 @@ fun SettingsScreen(onOpenStats: () -> Unit = {}, onOpenCompare: () -> Unit = {}) ) ConnStatusRow(status = state.scrobbleStatus, label = "Nicht konfiguriert", onTest = vm::testScrobble) - NsTextField( - value = state.webUrl, onValueChange = vm::onWebUrl, - label = "NovaSonic Web-Adresse", - hint = "Basis der geteilten Links, z. B. https://music.example.com", - keyboardType = KeyboardType.Uri, - ) Spacer(Modifier.height(4.dp)) diff --git a/android/app/src/main/kotlin/com/novasonic/app/viewmodel/SettingsViewModel.kt b/android/app/src/main/kotlin/com/novasonic/app/viewmodel/SettingsViewModel.kt index 98d6c13..71fb74c 100644 --- a/android/app/src/main/kotlin/com/novasonic/app/viewmodel/SettingsViewModel.kt +++ b/android/app/src/main/kotlin/com/novasonic/app/viewmodel/SettingsViewModel.kt @@ -30,7 +30,6 @@ data class SettingsUiState( val lastFmKey: String = "", val backendUrl: String = "", val scrobbleUrl: String = "", - val webUrl: String = "", val scrobbleMode: String = "30s", val showPlayCount: Boolean = false, val theme: String = "dark-ocean", @@ -63,7 +62,6 @@ class SettingsViewModel(app: Application) : AndroidViewModel(app) { lastFmKey = s.lastFmKey, backendUrl = s.backendUrl, scrobbleUrl = s.scrobbleUrl, - webUrl = s.webUrl, scrobbleMode = s.scrobbleMode, showPlayCount = s.showPlayCount, theme = s.theme, @@ -81,7 +79,6 @@ class SettingsViewModel(app: Application) : AndroidViewModel(app) { fun onLastFmKey(v: String) = update { it.copy(lastFmKey = v, savedOk = false) } fun onBackendUrl(v: String) = update { it.copy(backendUrl = v, savedOk = false, backendStatus = ConnStatus.Idle) } fun onScrobbleUrl(v: String) = update { it.copy(scrobbleUrl = v, savedOk = false, scrobbleStatus = ConnStatus.Idle) } - fun onWebUrl(v: String) = update { it.copy(webUrl = v, savedOk = false) } fun onScrobbleMode(v: String) = update { it.copy(scrobbleMode = v, savedOk = false) } fun onShowPlayCount(v: Boolean) = update { it.copy(showPlayCount = v, savedOk = false) } fun onAbsUrl(v: String) = update { it.copy(absUrl = v, savedOk = false, absStatus = ConnStatus.Idle) } @@ -174,7 +171,6 @@ class SettingsViewModel(app: Application) : AndroidViewModel(app) { lastFmKey = s.lastFmKey.trim(), backendUrl = s.backendUrl.trimEnd('/'), scrobbleUrl = s.scrobbleUrl.trimEnd('/'), - webUrl = s.webUrl.trimEnd('/'), scrobbleMode = s.scrobbleMode, showPlayCount = s.showPlayCount, theme = s.theme,