Android speicherte nur die Song-Ids und lud beim Start jeden Titel EINZELN und nacheinander ueber das Netz nach. Das dauerte Sekunden, war unzuverlaessig und ohne Verbindung unmoeglich. Gespeichert werden jetzt die vollstaendigen Songs als JSON — Wiederherstellen ist ein lokaler Lesevorgang, wie im Web. Der Preis ist ein veralteter Titel oder Cover bis zum naechsten Abspielen, was die deutlich kleinere Unschoenheit ist. Dazu sichert MusicService.onTaskRemoved die Warteschlange beim Wegwischen der App: dort feuert onIsPlayingChanged nicht zuverlaessig, genau dieser Fall ging vorher verloren. Service Worker: die Cache-Version stand handgepflegt als ns-v78 in sw.js und wurde beim Ausliefern vergessen — die Aktivierung loescht nur Caches mit abweichendem Namen, also blieb der alte bestehen und Nutzer mussten den Browsercache von Hand leeren. Ein Vite-Plugin setzt sie jetzt aus der Bauzeit, die Quelldatei bleibt unveraendert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
135 lines
5.0 KiB
Kotlin
135 lines
5.0 KiB
Kotlin
plugins {
|
|
alias(libs.plugins.android.application)
|
|
alias(libs.plugins.kotlin.android)
|
|
alias(libs.plugins.kotlin.compose)
|
|
alias(libs.plugins.kotlin.serialization)
|
|
alias(libs.plugins.ksp)
|
|
}
|
|
|
|
android {
|
|
namespace = "com.novasonic.app"
|
|
compileSdk = 35
|
|
|
|
defaultConfig {
|
|
applicationId = "com.novasonic.app"
|
|
minSdk = 26
|
|
targetSdk = 35
|
|
versionCode = 9
|
|
versionName = "1.6"
|
|
// 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.
|
|
val host1 = (project.findProperty("novasonicHost") as String?) ?: "music.example.com"
|
|
// Zweiter Host fuer einen Domainwechsel: solange beide Adressen erreichbar sind, oeffnen
|
|
// Links von der alten UND der neuen in der App. Ohne Angabe wird host1 wiederholt — ein
|
|
// doppelter Eintrag ist harmlos, ein Platzhalter-Host waere es NICHT: auf Android 11 und
|
|
// aelter verifiziert das System nur, wenn ALLE angegebenen Hosts eine gueltige
|
|
// assetlinks.json ausliefern, ein toter Host wuerde also alle blockieren.
|
|
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\"")
|
|
|
|
// Vorgabe-Adressen fuer Backend und Scrobble-Dienst. Sie stehen ohnehin in der
|
|
// docker-compose.yml — sie zusaetzlich auf jedem Geraet einzutippen ist Arbeit ohne Nutzen.
|
|
// Leer gelassen verhaelt sich die App wie bisher (Felder sichtbar, nichts vorbelegt).
|
|
// Zugangsdaten bleiben bewusst aussen vor: die gehoeren pro Person, nicht ins APK.
|
|
val backendUrl = (project.findProperty("novasonicBackend") as String?) ?: ""
|
|
val scrobbleUrl = (project.findProperty("novasonicScrobble") as String?) ?: ""
|
|
val navidromeUrl= (project.findProperty("novasonicNavidrome") as String?) ?: ""
|
|
buildConfigField("String", "DEFAULT_BACKEND_URL", "\"$backendUrl\"")
|
|
buildConfigField("String", "DEFAULT_SCROBBLE_URL", "\"$scrobbleUrl\"")
|
|
buildConfigField("String", "DEFAULT_ND_URL", "\"$navidromeUrl\"")
|
|
}
|
|
|
|
buildFeatures {
|
|
compose = true
|
|
buildConfig = true
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
isMinifyEnabled = true
|
|
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
|
}
|
|
}
|
|
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_11
|
|
targetCompatibility = JavaVersion.VERSION_11
|
|
}
|
|
|
|
kotlinOptions {
|
|
jvmTarget = "11"
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
// Core
|
|
implementation(libs.androidx.core.ktx)
|
|
implementation(libs.androidx.appcompat)
|
|
implementation(libs.androidx.activity.compose)
|
|
implementation(libs.androidx.splashscreen)
|
|
|
|
// Compose
|
|
implementation(platform(libs.compose.bom))
|
|
implementation(libs.compose.ui)
|
|
implementation(libs.compose.ui.tooling.preview)
|
|
implementation(libs.compose.foundation)
|
|
implementation(libs.compose.material3)
|
|
implementation(libs.compose.icons)
|
|
debugImplementation(libs.compose.ui.tooling)
|
|
|
|
// Navigation
|
|
implementation(libs.navigation.compose)
|
|
|
|
// Lifecycle / ViewModel
|
|
implementation(libs.lifecycle.viewmodel.compose)
|
|
implementation(libs.lifecycle.runtime.compose)
|
|
|
|
// Media3
|
|
implementation(libs.media3.exoplayer)
|
|
implementation(libs.media3.session)
|
|
implementation(libs.media3.common)
|
|
implementation(libs.media3.datasource)
|
|
implementation(libs.media3.ui)
|
|
|
|
// Ktor
|
|
implementation(libs.ktor.client.core)
|
|
implementation(libs.ktor.client.android)
|
|
implementation(libs.ktor.client.content.neg)
|
|
implementation(libs.ktor.serialization.json)
|
|
implementation(libs.ktor.client.logging)
|
|
|
|
// Kotlinx
|
|
implementation(libs.kotlinx.serialization.json)
|
|
implementation(libs.kotlinx.coroutines.android)
|
|
implementation(libs.kotlin.reflect)
|
|
|
|
// Room
|
|
implementation(libs.room.runtime)
|
|
implementation(libs.room.ktx)
|
|
ksp(libs.room.compiler)
|
|
|
|
// WorkManager
|
|
implementation(libs.work.runtime.ktx)
|
|
|
|
// DataStore
|
|
implementation(libs.datastore.preferences)
|
|
|
|
// Coil
|
|
implementation(libs.coil.compose)
|
|
|
|
// Palette (dominant cover color extraction in NowPlaying)
|
|
implementation("androidx.palette:palette-ktx:1.0.0")
|
|
|
|
// MediaStyle for ABS notification (already transitive via media3-session, made explicit)
|
|
implementation("androidx.media:media:1.7.0")
|
|
|
|
// Google Fonts (Outfit)
|
|
implementation(libs.compose.ui.google.fonts)
|
|
}
|