From e37006486edc544585a2632fae9bad8a19ac5b10 Mon Sep 17 00:00:00 2001 From: Barnabas Balogh Date: Tue, 17 Mar 2026 19:10:48 +0100 Subject: [PATCH] Add series link to episode top bar --- .../app/content/episode/EpisodeComponents.kt | 33 +++++++++++++++++++ .../app/content/episode/EpisodeScreen.kt | 7 ++++ .../content/episode/EpisodeScreenViewModel.kt | 12 +++++++ 3 files changed, 52 insertions(+) diff --git a/app/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeComponents.kt b/app/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeComponents.kt index 1ab28c6..6b285e1 100644 --- a/app/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeComponents.kt +++ b/app/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeComponents.kt @@ -1,7 +1,10 @@ package hu.bbara.purefin.app.content.episode import android.content.Intent +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.FlowRow @@ -13,6 +16,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Add import androidx.compose.material.icons.outlined.ArrowBack @@ -28,8 +32,10 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import hu.bbara.purefin.common.ui.MediaCastRow @@ -45,9 +51,12 @@ import hu.bbara.purefin.player.PlayerActivity @Composable internal fun EpisodeTopBar( + seriesTitle: String?, onBack: () -> Unit, + onSeriesClick: () -> Unit, modifier: Modifier = Modifier ) { + val scheme = MaterialTheme.colorScheme Row( modifier = modifier .fillMaxWidth() @@ -61,6 +70,30 @@ internal fun EpisodeTopBar( contentDescription = "Back", onClick = onBack ) + if (!seriesTitle.isNullOrBlank()) { + Box( + modifier = Modifier + .weight(1f) + .padding(horizontal = 12.dp), + contentAlignment = Alignment.Center + ) { + Text( + text = seriesTitle, + color = scheme.onBackground, + fontSize = 14.sp, + fontWeight = FontWeight.SemiBold, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + modifier = Modifier + .clip(RoundedCornerShape(999.dp)) + .background(scheme.background.copy(alpha = 0.65f)) + .clickable(onClick = onSeriesClick) + .padding(horizontal = 16.dp, vertical = 10.dp) + ) + } + } else { + Spacer(modifier = Modifier.weight(1f)) + } Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { }) GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = { }) diff --git a/app/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeScreen.kt b/app/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeScreen.kt index e89e2df..6669aea 100644 --- a/app/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/app/content/episode/EpisodeScreen.kt @@ -41,6 +41,7 @@ fun EpisodeScreen( } val episode = viewModel.episode.collectAsState() + val seriesTitle = viewModel.seriesTitle.collectAsState() val downloadState = viewModel.downloadState.collectAsState() val notificationPermissionLauncher = rememberLauncherForActivityResult( @@ -67,8 +68,10 @@ fun EpisodeScreen( EpisodeScreenInternal( episode = episode.value!!, + seriesTitle = seriesTitle.value, downloadState = downloadState.value, onBack = viewModel::onBack, + onSeriesClick = viewModel::onSeriesClick, onPlaybackStarted = viewModel::onPlaybackStarted, onDownloadClick = onDownloadClick, modifier = modifier @@ -78,8 +81,10 @@ fun EpisodeScreen( @Composable private fun EpisodeScreenInternal( episode: Episode, + seriesTitle: String?, downloadState: DownloadState, onBack: () -> Unit, + onSeriesClick: () -> Unit, onPlaybackStarted: () -> Unit, onDownloadClick: () -> Unit, modifier: Modifier = Modifier, @@ -90,7 +95,9 @@ private fun EpisodeScreenInternal( containerColor = MaterialTheme.colorScheme.background, topBar = { EpisodeTopBar( + seriesTitle = seriesTitle, onBack = onBack, + onSeriesClick = onSeriesClick, modifier = Modifier ) } diff --git a/feature/shared/src/main/java/hu/bbara/purefin/feature/shared/content/episode/EpisodeScreenViewModel.kt b/feature/shared/src/main/java/hu/bbara/purefin/feature/shared/content/episode/EpisodeScreenViewModel.kt index 560b101..2957db2 100644 --- a/feature/shared/src/main/java/hu/bbara/purefin/feature/shared/content/episode/EpisodeScreenViewModel.kt +++ b/feature/shared/src/main/java/hu/bbara/purefin/feature/shared/content/episode/EpisodeScreenViewModel.kt @@ -37,6 +37,13 @@ class EpisodeScreenViewModel @Inject constructor( id?.let { episodesMap[it] } }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null) + val seriesTitle: StateFlow = combine( + _seriesId, + appContentRepository.series + ) { seriesId, seriesMap -> + seriesId?.let { id -> seriesMap[id]?.name } + }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null) + private val _downloadState = MutableStateFlow(DownloadState.NotDownloaded) val downloadState: StateFlow = _downloadState.asStateFlow() @@ -55,6 +62,11 @@ class EpisodeScreenViewModel @Inject constructor( navigationManager.navigate(Route.SeriesRoute(SeriesDto(id = seriesId))) } + fun onSeriesClick() { + val seriesId = _seriesId.value ?: return + navigationManager.navigate(Route.SeriesRoute(SeriesDto(id = seriesId))) + } + fun selectEpisode(seriesId: UUID, seasonId: UUID, episodeId: UUID) { _episodeId.value = episodeId _seriesId.value = seriesId