refactor(web+android): nur Warteschlange und Titel sichern, keine Sekunden

Das Mitschreiben der Abspielposition war zu viel des Guten: es bedeutete
staendiges Schreiben waehrend der Wiedergabe fuer einen Gewinn, den man kaum
bemerkt. Gesichert werden jetzt nur Warteschlange und aktueller Titel, der dann
von vorn beginnt.

Der eigentliche Gewinn bleibt und war der Ausloeser: unter Android war die
Now-Playing-Leiste nach dem Oeffnen leer, bis man einmal auf Play drueckte —
gesichert war nur der letzte Song, nicht die Warteschlange. Das Wiederherstellen
fuellt den Zustand jetzt ueber syncState(), also ohne Abspielen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-06 23:25:06 +02:00
1 parent 65fa950043
commit a2211a62d2
6 files changed
+25 -67

No files matched your search

@@ -169,8 +169,7 @@ class MusicRepository(private val context: Context) {
suspend fun saveTheme(themeId: String) = prefs.saveTheme(themeId)
suspend fun saveQueueState(ids: List<String>, index: Int, positionMs: Long) =
prefs.saveQueueState(ids, index, positionMs)
suspend fun saveQueueState(ids: List<String>, index: Int) = prefs.saveQueueState(ids, index)
suspend fun readQueueState() = prefs.readQueueState()
suspend fun saveLastSong(song: com.novasonic.app.api.model.Song) =
prefs.saveLastSong(song.id, song.title, song.artist ?: "", song.coverArt)
@@ -4,7 +4,6 @@ import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.longPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
@@ -32,10 +31,11 @@ class PrefsStore(private val context: Context) {
val KEY_LAST_SONG_TITLE = stringPreferencesKey("last_song_title")
val KEY_LAST_SONG_ARTIST = stringPreferencesKey("last_song_artist")
val KEY_LAST_SONG_COVER = stringPreferencesKey("last_song_cover")
// Warteschlange fortsetzen: Song-Ids, Position in der Liste und Position im Titel.
// Warteschlange fortsetzen: Song-Ids und Position in der Liste. Bewusst OHNE Sekunde im
// Titel — der zuletzt gehoerte Titel beginnt von vorn, das genuegt und spart staendiges
// Schreiben waehrend der Wiedergabe.
val KEY_QUEUE_IDS = stringPreferencesKey("queue_ids")
val KEY_QUEUE_INDEX = intPreferencesKey("queue_index")
val KEY_QUEUE_POSITION = longPreferencesKey("queue_position_ms")
}
data class Credentials(val serverUrl: String, val username: String, val password: String) {
@@ -148,15 +148,14 @@ class PrefsStore(private val context: Context) {
* Sichert die Warteschlange als Id-Liste samt Position. Nur Ids, keine vollstaendigen Songs:
* Titel und Cover koennen sich aendern (Metadaten-Bearbeitung), die Id ist der stabile Bezug.
*/
suspend fun saveQueueState(ids: List<String>, index: Int, positionMs: Long) {
suspend fun saveQueueState(ids: List<String>, index: Int) {
context.dataStore.edit { prefs ->
prefs[KEY_QUEUE_IDS] = ids.joinToString(",")
prefs[KEY_QUEUE_INDEX] = index.coerceAtLeast(0)
prefs[KEY_QUEUE_POSITION] = positionMs.coerceAtLeast(0)
prefs[KEY_QUEUE_IDS] = ids.joinToString(",")
prefs[KEY_QUEUE_INDEX] = index.coerceAtLeast(0)
}
}
data class QueueState(val ids: List<String>, val index: Int, val positionMs: Long)
data class QueueState(val ids: List<String>, val index: Int)
suspend fun readQueueState(): QueueState? {
val prefs = context.dataStore.data.first()
@@ -164,8 +163,7 @@ class PrefsStore(private val context: Context) {
if (ids.isEmpty()) return null
return QueueState(
ids = ids,
index = (prefs[KEY_QUEUE_INDEX] ?: 0).coerceIn(0, ids.lastIndex),
positionMs = prefs[KEY_QUEUE_POSITION] ?: 0L,
index = (prefs[KEY_QUEUE_INDEX] ?: 0).coerceIn(0, ids.lastIndex),
)
}
@@ -62,16 +62,16 @@ class PlayerController(private val context: Context, private val repo: MusicRepo
}
/**
* Haelt Warteschlange, Listenposition und Position im Titel fest. ABS-Hoerbuecher bleiben aussen
* vor — die haben ihren eigenen Fortschritt auf dem Server.
* Haelt Warteschlange und Listenposition fest — ohne die Sekunde im Titel: der zuletzt gehoerte
* Titel beginnt von vorn. ABS-Hoerbuecher bleiben aussen vor, die haben ihren eigenen
* Fortschritt auf dem Server.
*/
private fun persistQueueState() {
val ctrl = controller ?: return
val ids = queue.map { it.id }
if (ids.isEmpty() || ids.any { it.startsWith("abs:") }) return
val index = ctrl.currentMediaItemIndex
val pos = ctrl.currentPosition
scope.launch { runCatching { repo.saveQueueState(ids, index, pos) } }
scope.launch { runCatching { repo.saveQueueState(ids, index) } }
}
/**
@@ -89,7 +89,7 @@ class PlayerController(private val context: Context, private val repo: MusicRepo
if (songs.isEmpty()) return@launch
val index = zustand.index.coerceIn(0, songs.lastIndex)
queue = songs
ctrl.setMediaItems(songs.map { it.toMediaItem(repo) }, index, zustand.positionMs)
ctrl.setMediaItems(songs.map { it.toMediaItem(repo) }, index, 0L)
ctrl.prepare()
syncState()
}