refactor(android): Web-Adresse aus BuildConfig statt als vierte Einstellung
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
dea0485a54
commit
83570b22b5
6 files changed
+23
-32
No files matched your search
+5
-2
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user