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.MediaDetailPlaybackSection
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.core.data.navigation.LocalNavigationManager
import hu.bbara.purefin.core.data.navigation.Route
@@ -78,20 +79,24 @@ internal fun EpisodeScreenContent(
}
TvMediaDetailScaffold(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(episode.imageUrlPrefix),
resetScrollKey = episode.id,
modifier = modifier,
heroContent = {
EpisodeHeroSection(
episode = episode,
seriesTitle = seriesTitle,
onPlay = onPlay,
playFocusRequester = playFocusRequester,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
}
modifier = modifier
) {
item {
TvMediaDetailBodyBox(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(episode.imageUrlPrefix),
modifier = it
) {
EpisodeHeroSection(
episode = episode,
seriesTitle = seriesTitle,
onPlay = onPlay,
playFocusRequester = playFocusRequester,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
}
}
item {
Column(modifier = it.fillMaxWidth()) {
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.MediaDetailPlaybackSection
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.tvMediaDetailBackgroundImageUrl
import hu.bbara.purefin.core.data.navigation.MovieDto
@@ -57,19 +58,23 @@ internal fun MovieScreenContent(
}
TvMediaDetailScaffold(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(movie.imageUrlPrefix),
resetScrollKey = movie.id,
modifier = modifier,
heroContent = {
MovieHeroSection(
movie = movie,
onPlay = onPlay,
playFocusRequester = playFocusRequester,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
}
modifier = modifier
) {
item {
TvMediaDetailBodyBox(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(movie.imageUrlPrefix),
modifier = it
) {
MovieHeroSection(
movie = movie,
onPlay = onPlay,
playFocusRequester = playFocusRequester,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
}
}
item {
Column(modifier = it.fillMaxWidth()) {
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.components.MediaDetailOverviewSection
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.tvMediaDetailBackgroundImageUrl
import hu.bbara.purefin.core.data.navigation.SeriesDto
@@ -70,21 +71,25 @@ internal fun SeriesScreenContent(
}
TvMediaDetailScaffold(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(series.imageUrlPrefix),
resetScrollKey = series.id,
modifier = modifier,
heroContent = {
SeriesHeroSection(
series = series,
nextUpEpisode = nextUpEpisode,
onPlayEpisode = { onPlayEpisode(it.id) },
playFocusRequester = playFocusRequester,
firstContentFocusRequester = firstContentFocusRequester,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
}
modifier = modifier
) {
item {
TvMediaDetailBodyBox(
backgroundImageUrl = tvMediaDetailBackgroundImageUrl(series.imageUrlPrefix),
modifier = it
) {
SeriesHeroSection(
series = series,
nextUpEpisode = nextUpEpisode,
onPlayEpisode = { onPlayEpisode(it.id) },
playFocusRequester = playFocusRequester,
firstContentFocusRequester = firstContentFocusRequester,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
}
}
item {
Column(modifier = it.fillMaxWidth()) {
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.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.layout.ContentScale
@@ -31,14 +32,12 @@ import org.jellyfin.sdk.model.api.ImageType
internal val MediaDetailHorizontalPadding = 48.dp
private val MediaDetailHeaderTopPadding = 104.dp
private val MediaDetailHeaderBottomPadding = 36.dp
private const val MediaDetailBodyImageWidthFraction = 0.56f
@Composable
internal fun TvMediaDetailScaffold(
backgroundImageUrl: String,
resetScrollKey: Any,
modifier: Modifier = Modifier,
headerHeightFraction: Float = 0.48f,
heroContent: @Composable ColumnScope.() -> Unit,
bodyContent: LazyListScope.(Modifier) -> Unit = { _ -> }
) {
val scheme = MaterialTheme.colorScheme
@@ -55,36 +54,33 @@ internal fun TvMediaDetailScaffold(
.fillMaxSize()
.background(scheme.background)
) {
item {
TvMediaDetailHeader(
backgroundImageUrl = backgroundImageUrl,
headerHeightFraction = headerHeightFraction,
heroContent = heroContent
)
}
bodyContent(contentPadding)
}
}
@Composable
private fun TvMediaDetailHeader(
internal fun TvMediaDetailBodyBox(
backgroundImageUrl: String,
headerHeightFraction: Float,
heroContent: @Composable ColumnScope.() -> Unit
modifier: Modifier = Modifier,
heightFraction: Float = 0.48f,
content: @Composable ColumnScope.() -> Unit
) {
val scheme = MaterialTheme.colorScheme
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val headerHeight = screenHeight * headerHeightFraction
val bodyHeight = screenHeight * heightFraction
Box(
modifier = Modifier
modifier = modifier
.fillMaxWidth()
.heightIn(min = headerHeight)
.heightIn(min = bodyHeight)
) {
PurefinAsyncImage(
model = backgroundImageUrl,
contentDescription = null,
modifier = Modifier.fillMaxSize(),
modifier = Modifier
.fillMaxSize()
.fillMaxWidth(MediaDetailBodyImageWidthFraction)
.align(Alignment.TopEnd),
contentScale = ContentScale.Crop
)
Box(
@@ -118,13 +114,11 @@ private fun TvMediaDetailHeader(
modifier = Modifier
.fillMaxWidth()
.padding(
start = MediaDetailHorizontalPadding,
top = MediaDetailHeaderTopPadding,
end = MediaDetailHorizontalPadding,
bottom = MediaDetailHeaderBottomPadding
)
) {
heroContent()
content()
}
}
}