feat(series): improve season and episode loading handling

This commit is contained in:
2026-05-25 20:40:10 +02:00
parent 3cd706d449
commit b0ed32ef7c
5 changed files with 167 additions and 99 deletions

View File

@@ -87,7 +87,7 @@ fun SeriesScreen(
}
val seriesData = seriesState.value
if (seriesData != null && seriesData.seasons.isNotEmpty()) {
if (seriesData != null) {
LaunchedEffect(seriesData) {
viewModel.observeSeriesDownloadState(seriesData)
}
@@ -170,22 +170,22 @@ private fun SeriesScreenInternal(
) {
val scheme = MaterialTheme.colorScheme
fun getDefaultSeason(): Season {
return series.seasons.firstOrNull { it.unwatchedEpisodeCount > 0 } ?: series.seasons.first()
fun getDefaultSeason(): Season? {
return series.seasons.firstOrNull { it.unwatchedEpisodeCount > 0 } ?: series.seasons.firstOrNull()
}
var selectedSeasonId by remember(series.id) { mutableStateOf(getDefaultSeason().id) }
var selectedSeasonId by remember(series.id) { mutableStateOf(getDefaultSeason()?.id) }
val selectedSeason =
series.seasons.firstOrNull { it.id == selectedSeasonId } ?: getDefaultSeason()
val nextUpEpisode = selectedSeason.episodes.firstOrNull { !it.watched }
?: selectedSeason.episodes.firstOrNull()
val nextUpEpisode = selectedSeason?.episodes?.firstOrNull { !it.watched }
?: selectedSeason?.episodes?.firstOrNull()
LaunchedEffect(series.id, selectedSeason.id) {
onLoadSeasonEpisodes(series.id, selectedSeason.id)
LaunchedEffect(series.id, selectedSeason?.id) {
selectedSeason?.let { onLoadSeasonEpisodes(series.id, it.id) }
}
LaunchedEffect(selectedSeason.id, selectedSeason.episodes) {
onObserveSeasonDownloadState(selectedSeason.episodes)
LaunchedEffect(selectedSeason?.id, selectedSeason?.episodes) {
selectedSeason?.let { onObserveSeasonDownloadState(it.episodes) }
}
MediaDetailScaffold(
@@ -198,17 +198,19 @@ private fun SeriesScreenInternal(
SeriesHeroContent(series = series)
}
) {
SeriesActionButtons(
nextUpEpisode = nextUpEpisode,
selectedSeason = selectedSeason,
seriesDownloadState = seriesDownloadState,
seasonDownloadState = seasonDownloadState,
isSmartDownloadEnabled = isSmartDownloadEnabled,
offline = offline,
onDownloadOptionSelected = { option ->
onDownloadOptionSelected(option, selectedSeason)
}
)
if (selectedSeason != null) {
SeriesActionButtons(
nextUpEpisode = nextUpEpisode,
selectedSeason = selectedSeason,
seriesDownloadState = seriesDownloadState,
seasonDownloadState = seasonDownloadState,
isSmartDownloadEnabled = isSmartDownloadEnabled,
offline = offline,
onDownloadOptionSelected = { option ->
onDownloadOptionSelected(option, selectedSeason)
}
)
}
MediaSynopsis(
synopsis = series.synopsis,
bodyColor = scheme.onSurface,
@@ -216,14 +218,22 @@ private fun SeriesScreenInternal(
bodyLineHeight = null,
titleSpacing = 8.dp
)
SeasonTabs(
seasons = series.seasons,
selectedSeason = selectedSeason,
onSelect = { selectedSeasonId = it.id }
)
EpisodeCarousel(
episodes = selectedSeason.episodes,
)
if (selectedSeason != null) {
SeasonTabs(
seasons = series.seasons,
selectedSeason = selectedSeason,
onSelect = { selectedSeasonId = it.id }
)
EpisodeCarousel(
episodes = selectedSeason.episodes,
)
} else {
Text(
text = "Loading seasons...",
color = scheme.onSurfaceVariant,
fontSize = 13.sp
)
}
if (series.cast.isNotEmpty()) {
Text(
text = "Cast",

View File

@@ -4,7 +4,6 @@ import android.content.Intent
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -20,8 +19,8 @@ import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add
@@ -333,14 +332,23 @@ internal fun SeasonTabs(
modifier: Modifier = Modifier,
onSelect: (Season) -> Unit
) {
Row(
val selectedSeasonIndex = seasons.indexOf(selectedSeason).coerceAtLeast(0)
val listState = rememberLazyListState()
LaunchedEffect(selectedSeasonIndex, seasons.size) {
if (seasons.isNotEmpty()) {
listState.scrollToItem(selectedSeasonIndex)
}
}
LazyRow(
state = listState,
modifier = modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState()),
.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(20.dp),
verticalAlignment = Alignment.CenterVertically
) {
seasons.forEachIndexed { index, season ->
itemsIndexed(seasons, key = { _, season -> season.id }) { index, season ->
SeasonTab(
name = season.name,
isSelected = season == selectedSeason,