Add series link to episode top bar

This commit is contained in:
2026-03-17 19:10:48 +01:00
parent 92342f1f35
commit e37006486e
3 changed files with 52 additions and 0 deletions

View File

@@ -1,7 +1,10 @@
package hu.bbara.purefin.app.content.episode package hu.bbara.purefin.app.content.episode
import android.content.Intent 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.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow 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.sizeIn
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Add import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.ArrowBack
@@ -28,8 +32,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.MediaCastRow import hu.bbara.purefin.common.ui.MediaCastRow
@@ -45,9 +51,12 @@ import hu.bbara.purefin.player.PlayerActivity
@Composable @Composable
internal fun EpisodeTopBar( internal fun EpisodeTopBar(
seriesTitle: String?,
onBack: () -> Unit, onBack: () -> Unit,
onSeriesClick: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val scheme = MaterialTheme.colorScheme
Row( Row(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
@@ -61,6 +70,30 @@ internal fun EpisodeTopBar(
contentDescription = "Back", contentDescription = "Back",
onClick = onBack 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)) { Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { }) GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { })
GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = { }) GhostIconButton(icon = Icons.Outlined.MoreVert, contentDescription = "More", onClick = { })

View File

@@ -41,6 +41,7 @@ fun EpisodeScreen(
} }
val episode = viewModel.episode.collectAsState() val episode = viewModel.episode.collectAsState()
val seriesTitle = viewModel.seriesTitle.collectAsState()
val downloadState = viewModel.downloadState.collectAsState() val downloadState = viewModel.downloadState.collectAsState()
val notificationPermissionLauncher = rememberLauncherForActivityResult( val notificationPermissionLauncher = rememberLauncherForActivityResult(
@@ -67,8 +68,10 @@ fun EpisodeScreen(
EpisodeScreenInternal( EpisodeScreenInternal(
episode = episode.value!!, episode = episode.value!!,
seriesTitle = seriesTitle.value,
downloadState = downloadState.value, downloadState = downloadState.value,
onBack = viewModel::onBack, onBack = viewModel::onBack,
onSeriesClick = viewModel::onSeriesClick,
onPlaybackStarted = viewModel::onPlaybackStarted, onPlaybackStarted = viewModel::onPlaybackStarted,
onDownloadClick = onDownloadClick, onDownloadClick = onDownloadClick,
modifier = modifier modifier = modifier
@@ -78,8 +81,10 @@ fun EpisodeScreen(
@Composable @Composable
private fun EpisodeScreenInternal( private fun EpisodeScreenInternal(
episode: Episode, episode: Episode,
seriesTitle: String?,
downloadState: DownloadState, downloadState: DownloadState,
onBack: () -> Unit, onBack: () -> Unit,
onSeriesClick: () -> Unit,
onPlaybackStarted: () -> Unit, onPlaybackStarted: () -> Unit,
onDownloadClick: () -> Unit, onDownloadClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@@ -90,7 +95,9 @@ private fun EpisodeScreenInternal(
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
topBar = { topBar = {
EpisodeTopBar( EpisodeTopBar(
seriesTitle = seriesTitle,
onBack = onBack, onBack = onBack,
onSeriesClick = onSeriesClick,
modifier = Modifier modifier = Modifier
) )
} }

View File

@@ -37,6 +37,13 @@ class EpisodeScreenViewModel @Inject constructor(
id?.let { episodesMap[it] } id?.let { episodesMap[it] }
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null) }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
val seriesTitle: StateFlow<String?> = combine(
_seriesId,
appContentRepository.series
) { seriesId, seriesMap ->
seriesId?.let { id -> seriesMap[id]?.name }
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
private val _downloadState = MutableStateFlow<DownloadState>(DownloadState.NotDownloaded) private val _downloadState = MutableStateFlow<DownloadState>(DownloadState.NotDownloaded)
val downloadState: StateFlow<DownloadState> = _downloadState.asStateFlow() val downloadState: StateFlow<DownloadState> = _downloadState.asStateFlow()
@@ -55,6 +62,11 @@ class EpisodeScreenViewModel @Inject constructor(
navigationManager.navigate(Route.SeriesRoute(SeriesDto(id = seriesId))) 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) { fun selectEpisode(seriesId: UUID, seasonId: UUID, episodeId: UUID) {
_episodeId.value = episodeId _episodeId.value = episodeId
_seriesId.value = seriesId _seriesId.value = seriesId