fix(android): große Offline-Playlists ließen sich nicht abspielen
Die Warteschlange wurde aus allen Titeln einer Gruppe gebaut, ohne den Download-Zustand zu prüfen. Die Map für lokale Dateien kennt aber nur state = 'DONE' — für wartende oder fehlgeschlagene Titel lieferte streamUrl() die Netz-Adresse, die offline nichts tut. Bei 100 Titeln ist der Download durch, bei 1900 nicht; steht so ein Titel vorn, scheitert die Wiedergabe sofort. Play und Shuffle nehmen jetzt nur fertige Titel, ein Toast nennt die Zahl der übersprungenen. Die Liste zeigt weiter alle, damit sichtbar bleibt, was fehlt; Tippen auf einen unfertigen sagt es ebenfalls. Nicht die Ursache: Media3 reicht große Listen als BundleListRetriever durch, die 1-MB-Binder-Grenze greift dort nicht. Dazu Backlog-Notiz: Künstler/Alben liken als Basis für "Künstler folgen". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cb5ea26c77
commit
35e36067af
3 files changed
+59
-4
No files matched your search
@@ -31,6 +31,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import coil.compose.AsyncImage
|
||||
import com.novasonic.app.api.model.Song
|
||||
import com.novasonic.app.offline.DownloadState
|
||||
import com.novasonic.app.offline.toSong
|
||||
import com.novasonic.app.player.PlayerState
|
||||
import com.novasonic.app.ui.component.SongRow
|
||||
@@ -62,6 +63,20 @@ fun OfflineDetailScreen(
|
||||
return
|
||||
}
|
||||
val songs = remember(tracks) { tracks.map { it.toSong() } }
|
||||
// Nur FERTIGE Titel sind offline abspielbar. Die Liste zeigt weiter alle (auch wartende und
|
||||
// fehlgeschlagene), aber in die Warteschlange dürfen sie nicht: für sie gibt es keine lokale
|
||||
// Datei, also liefert streamUrl() die Netz-Adresse — und die tut offline genau nichts.
|
||||
val spielbar = remember(tracks) {
|
||||
tracks.filter { it.state == DownloadState.DONE }.map { it.toSong() }
|
||||
}
|
||||
val ctx = androidx.compose.ui.platform.LocalContext.current
|
||||
val spieleAb: (List<com.novasonic.app.api.model.Song>, Int) -> Unit = { liste, i ->
|
||||
val fehlend = songs.size - spielbar.size
|
||||
if (fehlend > 0) android.widget.Toast.makeText(
|
||||
ctx, "$fehlend Titel noch nicht heruntergeladen — übersprungen",
|
||||
android.widget.Toast.LENGTH_SHORT).show()
|
||||
onPlay(liste, i)
|
||||
}
|
||||
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
item {
|
||||
@@ -123,7 +138,7 @@ fun OfflineDetailScreen(
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
) {
|
||||
Button(
|
||||
onClick = { if (songs.isNotEmpty()) onPlay(songs, 0) },
|
||||
onClick = { if (spielbar.isNotEmpty()) spieleAb(spielbar, 0) },
|
||||
modifier = Modifier.weight(1f).height(46.dp),
|
||||
colors = ButtonDefaults.buttonColors(containerColor = NsAccent, contentColor = Color.White),
|
||||
shape = RoundedCornerShape(14.dp),
|
||||
@@ -133,7 +148,7 @@ fun OfflineDetailScreen(
|
||||
Text("Play", fontFamily = Outfit, fontWeight = FontWeight.Bold, fontSize = 15.sp)
|
||||
}
|
||||
OutlinedButton(
|
||||
onClick = { if (songs.isNotEmpty()) onPlay(songs.shuffled(), 0) },
|
||||
onClick = { if (spielbar.isNotEmpty()) spieleAb(spielbar.shuffled(), 0) },
|
||||
modifier = Modifier.weight(1f).height(46.dp),
|
||||
border = ButtonDefaults.outlinedButtonBorder(enabled = true).copy(brush = SolidColor(NsAccent.copy(alpha = 0.55f))),
|
||||
shape = RoundedCornerShape(14.dp),
|
||||
@@ -169,7 +184,15 @@ fun OfflineDetailScreen(
|
||||
song = song,
|
||||
coverUrl = coverUrl(song.coverArt),
|
||||
isPlaying = playerState.currentSong?.id == song.id,
|
||||
onPlay = { onPlay(songs, index) },
|
||||
// Position in der abspielbaren Liste suchen — die Anzeige enthält auch
|
||||
// Titel, die noch fehlen, die Indizes decken sich also nicht.
|
||||
onPlay = {
|
||||
val i = spielbar.indexOfFirst { it.id == song.id }
|
||||
if (i >= 0) onPlay(spielbar, i)
|
||||
else android.widget.Toast.makeText(
|
||||
ctx, "Dieser Titel ist noch nicht heruntergeladen",
|
||||
android.widget.Toast.LENGTH_SHORT).show()
|
||||
},
|
||||
)
|
||||
}
|
||||
if (editMode) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import com.novasonic.app.api.model.Song
|
||||
import com.novasonic.app.app
|
||||
import com.novasonic.app.offline.DownloadGroupEntity
|
||||
import com.novasonic.app.offline.DownloadState
|
||||
import com.novasonic.app.offline.toSong
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
@@ -27,6 +28,11 @@ class OfflineViewModel(app: Application) : AndroidViewModel(app) {
|
||||
viewModelScope.launch { offlineRepo.deleteGroup(groupId) }
|
||||
}
|
||||
|
||||
/** Nur FERTIGE Titel: wartende oder fehlgeschlagene haben keine lokale Datei und wuerden aus
|
||||
* dem Netz gezogen — offline schlaegt die Wiedergabe dann fehl, bei grossen Playlists
|
||||
* gleich beim ersten Titel. */
|
||||
suspend fun songsForGroup(groupId: String): List<Song> =
|
||||
offlineRepo.tracksForGroup(groupId).map { it.toSong() }
|
||||
offlineRepo.tracksForGroup(groupId)
|
||||
.filter { it.state == DownloadState.DONE }
|
||||
.map { it.toSong() }
|
||||
}
|
||||
Reference in new issue
Block a user