Move TV detail hero content into body

This commit is contained in:
2026-04-06 19:12:52 +02:00
parent 9083a08f95
commit 34ae15d645
4 changed files with 65 additions and 56 deletions

View File

@@ -17,6 +17,7 @@ import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection
import hu.bbara.purefin.common.ui.components.MediaDetailPlaybackSection import hu.bbara.purefin.common.ui.components.MediaDetailPlaybackSection
import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle
import hu.bbara.purefin.common.ui.components.TvMediaDetailBodyBox
import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold
import hu.bbara.purefin.core.data.navigation.LocalNavigationManager import hu.bbara.purefin.core.data.navigation.LocalNavigationManager
import hu.bbara.purefin.core.data.navigation.Route import hu.bbara.purefin.core.data.navigation.Route
@@ -78,10 +79,14 @@ internal fun EpisodeScreenContent(
} }
TvMediaDetailScaffold( TvMediaDetailScaffold(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(episode.imageUrlPrefix),
resetScrollKey = episode.id, resetScrollKey = episode.id,
modifier = modifier, modifier = modifier
heroContent = { ) {
item {
TvMediaDetailBodyBox(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(episode.imageUrlPrefix),
modifier = it
) {
EpisodeHeroSection( EpisodeHeroSection(
episode = episode, episode = episode,
seriesTitle = seriesTitle, seriesTitle = seriesTitle,
@@ -91,7 +96,7 @@ internal fun EpisodeScreenContent(
) )
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
} }
) { }
item { item {
Column(modifier = it.fillMaxWidth()) { Column(modifier = it.fillMaxWidth()) {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))

View File

@@ -17,6 +17,7 @@ import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection
import hu.bbara.purefin.common.ui.components.MediaDetailPlaybackSection import hu.bbara.purefin.common.ui.components.MediaDetailPlaybackSection
import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle
import hu.bbara.purefin.common.ui.components.TvMediaDetailBodyBox
import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold
import hu.bbara.purefin.common.ui.components.tvMediaDetailBackgroundImageUrl import hu.bbara.purefin.common.ui.components.tvMediaDetailBackgroundImageUrl
import hu.bbara.purefin.core.data.navigation.MovieDto import hu.bbara.purefin.core.data.navigation.MovieDto
@@ -57,10 +58,14 @@ internal fun MovieScreenContent(
} }
TvMediaDetailScaffold( TvMediaDetailScaffold(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(movie.imageUrlPrefix),
resetScrollKey = movie.id, resetScrollKey = movie.id,
modifier = modifier, modifier = modifier
heroContent = { ) {
item {
TvMediaDetailBodyBox(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(movie.imageUrlPrefix),
modifier = it
) {
MovieHeroSection( MovieHeroSection(
movie = movie, movie = movie,
onPlay = onPlay, onPlay = onPlay,
@@ -69,7 +74,7 @@ internal fun MovieScreenContent(
) )
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
} }
) { }
item { item {
Column(modifier = it.fillMaxWidth()) { Column(modifier = it.fillMaxWidth()) {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))

View File

@@ -18,6 +18,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection
import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle
import hu.bbara.purefin.common.ui.components.TvMediaDetailBodyBox
import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold
import hu.bbara.purefin.common.ui.components.tvMediaDetailBackgroundImageUrl import hu.bbara.purefin.common.ui.components.tvMediaDetailBackgroundImageUrl
import hu.bbara.purefin.core.data.navigation.SeriesDto import hu.bbara.purefin.core.data.navigation.SeriesDto
@@ -70,10 +71,14 @@ internal fun SeriesScreenContent(
} }
TvMediaDetailScaffold( TvMediaDetailScaffold(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(series.imageUrlPrefix),
resetScrollKey = series.id, resetScrollKey = series.id,
modifier = modifier, modifier = modifier
heroContent = { ) {
item {
TvMediaDetailBodyBox(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(series.imageUrlPrefix),
modifier = it
) {
SeriesHeroSection( SeriesHeroSection(
series = series, series = series,
nextUpEpisode = nextUpEpisode, nextUpEpisode = nextUpEpisode,
@@ -84,7 +89,7 @@ internal fun SeriesScreenContent(
) )
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
} }
) { }
item { item {
Column(modifier = it.fillMaxWidth()) { Column(modifier = it.fillMaxWidth()) {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))

View File

@@ -17,6 +17,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
@@ -31,14 +32,12 @@ import org.jellyfin.sdk.model.api.ImageType
internal val MediaDetailHorizontalPadding = 48.dp internal val MediaDetailHorizontalPadding = 48.dp
private val MediaDetailHeaderTopPadding = 104.dp private val MediaDetailHeaderTopPadding = 104.dp
private val MediaDetailHeaderBottomPadding = 36.dp private val MediaDetailHeaderBottomPadding = 36.dp
private const val MediaDetailBodyImageWidthFraction = 0.56f
@Composable @Composable
internal fun TvMediaDetailScaffold( internal fun TvMediaDetailScaffold(
backgroundImageUrl: String,
resetScrollKey: Any, resetScrollKey: Any,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
headerHeightFraction: Float = 0.48f,
heroContent: @Composable ColumnScope.() -> Unit,
bodyContent: LazyListScope.(Modifier) -> Unit = { _ -> } bodyContent: LazyListScope.(Modifier) -> Unit = { _ -> }
) { ) {
val scheme = MaterialTheme.colorScheme val scheme = MaterialTheme.colorScheme
@@ -55,36 +54,33 @@ internal fun TvMediaDetailScaffold(
.fillMaxSize() .fillMaxSize()
.background(scheme.background) .background(scheme.background)
) { ) {
item {
TvMediaDetailHeader(
backgroundImageUrl = backgroundImageUrl,
headerHeightFraction = headerHeightFraction,
heroContent = heroContent
)
}
bodyContent(contentPadding) bodyContent(contentPadding)
} }
} }
@Composable @Composable
private fun TvMediaDetailHeader( internal fun TvMediaDetailBodyBox(
backgroundImageUrl: String, backgroundImageUrl: String,
headerHeightFraction: Float, modifier: Modifier = Modifier,
heroContent: @Composable ColumnScope.() -> Unit heightFraction: Float = 0.48f,
content: @Composable ColumnScope.() -> Unit
) { ) {
val scheme = MaterialTheme.colorScheme val scheme = MaterialTheme.colorScheme
val screenHeight = LocalConfiguration.current.screenHeightDp.dp val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val headerHeight = screenHeight * headerHeightFraction val bodyHeight = screenHeight * heightFraction
Box( Box(
modifier = Modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
.heightIn(min = headerHeight) .heightIn(min = bodyHeight)
) { ) {
PurefinAsyncImage( PurefinAsyncImage(
model = backgroundImageUrl, model = backgroundImageUrl,
contentDescription = null, contentDescription = null,
modifier = Modifier.fillMaxSize(), modifier = Modifier
.fillMaxSize()
.fillMaxWidth(MediaDetailBodyImageWidthFraction)
.align(Alignment.TopEnd),
contentScale = ContentScale.Crop contentScale = ContentScale.Crop
) )
Box( Box(
@@ -118,13 +114,11 @@ private fun TvMediaDetailHeader(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding( .padding(
start = MediaDetailHorizontalPadding,
top = MediaDetailHeaderTopPadding, top = MediaDetailHeaderTopPadding,
end = MediaDetailHorizontalPadding,
bottom = MediaDetailHeaderBottomPadding bottom = MediaDetailHeaderBottomPadding
) )
) { ) {
heroContent() content()
} }
} }
} }