refactor media screens to use Scaffold and standard layout components

- Replace `BoxWithConstraints` with `Scaffold` in `MovieScreen`, `EpisodeScreen`, and `SeriesScreen`.
- Move `MovieTopBar`, `EpisodeTopBar`, and `SeriesTopBar` into the `topBar` slot of `Scaffold`.
- Implement `statusBarsPadding` and standard padding in top bar components.
- Decouple top bar components from ViewModels by passing an `onBack` callback.
- Simplify hero image heights and remove complex offsets and conditional wide-screen layouts.
- Use `floatingActionButton` slot for the play button in movie and episode screens.
- Standardize background handling using `MaterialTheme.colorScheme.background`.
This commit is contained in:
2026-01-21 22:43:50 +01:00
parent decb8cd0cb
commit ce45139f74
6 changed files with 171 additions and 248 deletions

View File

@@ -6,7 +6,10 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Cast import androidx.compose.material.icons.outlined.Cast
@@ -18,7 +21,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
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 androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.MediaActionButtons import hu.bbara.purefin.common.ui.MediaActionButtons
import hu.bbara.purefin.common.ui.MediaCastMember import hu.bbara.purefin.common.ui.MediaCastMember
import hu.bbara.purefin.common.ui.MediaCastRow import hu.bbara.purefin.common.ui.MediaCastRow
@@ -29,12 +31,15 @@ import hu.bbara.purefin.common.ui.toMediaDetailColors
@Composable @Composable
internal fun EpisodeTopBar( internal fun EpisodeTopBar(
viewModel: EpisodeScreenViewModel = hiltViewModel(), onBack: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val colors = rememberEpisodeColors().toMediaDetailColors() val colors = rememberEpisodeColors().toMediaDetailColors()
Row( Row(
modifier = modifier, modifier = modifier
.fillMaxWidth()
.statusBarsPadding()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -42,7 +47,7 @@ internal fun EpisodeTopBar(
colors = colors, colors = colors,
icon = Icons.Outlined.ArrowBack, icon = Icons.Outlined.ArrowBack,
contentDescription = "Back", contentDescription = "Back",
onClick = { viewModel.onBack() } onClick = onBack
) )
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
MediaGhostIconButton(colors = colors, icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { }) MediaGhostIconButton(colors = colors, icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { })

View File

@@ -1,26 +1,19 @@
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.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -29,7 +22,6 @@ import hu.bbara.purefin.app.content.ContentMockData
import hu.bbara.purefin.common.ui.MediaFloatingPlayButton import hu.bbara.purefin.common.ui.MediaFloatingPlayButton
import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaHero import hu.bbara.purefin.common.ui.components.MediaHero
import hu.bbara.purefin.common.ui.toMediaDetailColors
import hu.bbara.purefin.navigation.ItemDto import hu.bbara.purefin.navigation.ItemDto
import hu.bbara.purefin.player.PlayerActivity import hu.bbara.purefin.player.PlayerActivity
@@ -52,19 +44,18 @@ fun EpisodeScreen(
} }
EpisodeScreenInternal( EpisodeScreenInternal(
episode = episode.value!!, episode = episode.value!!,
modifier = modifier, onBack = viewModel::onBack,
backGroundColor = MaterialTheme.colorScheme.background modifier = modifier
) )
} }
@Composable @Composable
private fun EpisodeScreenInternal( private fun EpisodeScreenInternal(
episode: EpisodeUiModel, episode: EpisodeUiModel,
backGroundColor: Color, onBack: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val colors = rememberEpisodeColors().toMediaDetailColors()
val context = LocalContext.current val context = LocalContext.current
val playAction = remember(episode.id) { val playAction = remember(episode.id) {
{ {
@@ -74,78 +65,43 @@ private fun EpisodeScreenInternal(
} }
} }
BoxWithConstraints( Scaffold(
modifier = modifier modifier = modifier,
.fillMaxSize() containerColor = MaterialTheme.colorScheme.background,
.background(colors.background) topBar = {
) {
val isWide = maxWidth >= 900.dp
val contentPadding = if (isWide) 32.dp else 20.dp
Box(modifier = Modifier.fillMaxSize()) {
if (isWide) {
Row(modifier = Modifier.fillMaxSize()) {
MediaHero(
imageUrl = episode.heroImageUrl,
height = 300.dp,
backgroundColor = backGroundColor,
modifier = Modifier
.fillMaxHeight()
.weight(0.5f)
)
EpisodeDetails(
episode = episode,
modifier = Modifier
.weight(0.5f)
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.padding(
start = contentPadding,
end = contentPadding,
top = 96.dp,
bottom = 32.dp
)
)
}
} else {
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
MediaHero(
imageUrl = episode.heroImageUrl,
backgroundColor = backGroundColor,
height = 400.dp,
modifier = Modifier.fillMaxWidth()
)
EpisodeDetails(
episode = episode,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = contentPadding)
.offset(y = (-48).dp)
.padding(bottom = 96.dp)
)
}
}
EpisodeTopBar( EpisodeTopBar(
onBack = onBack,
modifier = Modifier
)
},
floatingActionButton = {
MediaFloatingPlayButton(
containerColor = MaterialTheme.colorScheme.primary,
onContainerColor = MaterialTheme.colorScheme.onPrimary,
onClick = playAction,
modifier = Modifier
.padding(16.dp)
)
}
) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
MediaHero(
imageUrl = episode.heroImageUrl,
backgroundColor = MaterialTheme.colorScheme.background,
height = 200.dp,
modifier = Modifier.fillMaxWidth()
)
EpisodeDetails(
episode = episode,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp) .padding(horizontal = 16.dp)
.padding(bottom = innerPadding.calculateBottomPadding())
) )
if (!isWide) {
MediaFloatingPlayButton(
containerColor = colors.primary,
onContainerColor = colors.onPrimary,
onClick = playAction,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(20.dp)
)
}
} }
} }
} }
@@ -155,6 +111,6 @@ private fun EpisodeScreenInternal(
fun EpisodeScreenPreview() { fun EpisodeScreenPreview() {
EpisodeScreenInternal( EpisodeScreenInternal(
episode = ContentMockData.episode(), episode = ContentMockData.episode(),
backGroundColor = MaterialTheme.colorScheme.background onBack = {}
) )
} }

View File

@@ -6,7 +6,10 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Cast import androidx.compose.material.icons.outlined.Cast
@@ -18,7 +21,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
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 androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.MediaActionButtons import hu.bbara.purefin.common.ui.MediaActionButtons
import hu.bbara.purefin.common.ui.MediaCastMember import hu.bbara.purefin.common.ui.MediaCastMember
import hu.bbara.purefin.common.ui.MediaCastRow import hu.bbara.purefin.common.ui.MediaCastRow
@@ -29,12 +31,15 @@ import hu.bbara.purefin.common.ui.toMediaDetailColors
@Composable @Composable
internal fun MovieTopBar( internal fun MovieTopBar(
viewModel: MovieScreenViewModel = hiltViewModel(), onBack: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val colors = rememberMovieColors().toMediaDetailColors() val colors = rememberMovieColors().toMediaDetailColors()
Row( Row(
modifier = modifier, modifier = modifier
.fillMaxWidth()
.statusBarsPadding()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -42,7 +47,7 @@ internal fun MovieTopBar(
colors = colors, colors = colors,
icon = Icons.Outlined.ArrowBack, icon = Icons.Outlined.ArrowBack,
contentDescription = "Back", contentDescription = "Back",
onClick = { viewModel.onBack() } onClick = onBack
) )
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
MediaGhostIconButton(colors = colors, icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { }) MediaGhostIconButton(colors = colors, icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { })

View File

@@ -1,24 +1,18 @@
package hu.bbara.purefin.app.content.movie package hu.bbara.purefin.app.content.movie
import android.content.Intent import android.content.Intent
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@@ -43,7 +37,9 @@ fun MovieScreen(
if (movieItem.value != null) { if (movieItem.value != null) {
MovieScreenInternal( MovieScreenInternal(
movie = movieItem.value!!, modifier = modifier movie = movieItem.value!!,
onBack = viewModel::onBack,
modifier = modifier
) )
} else { } else {
PurefinWaitingScreen() PurefinWaitingScreen()
@@ -53,6 +49,7 @@ fun MovieScreen(
@Composable @Composable
private fun MovieScreenInternal( private fun MovieScreenInternal(
movie: MovieUiModel, movie: MovieUiModel,
onBack: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val context = LocalContext.current val context = LocalContext.current
@@ -64,85 +61,53 @@ private fun MovieScreenInternal(
} }
} }
BoxWithConstraints( Scaffold(
modifier = modifier modifier = modifier,
.fillMaxSize() containerColor = MaterialTheme.colorScheme.background,
.background(MaterialTheme.colorScheme.background) topBar = {
) {
val isWide = maxWidth >= 900.dp
val contentPadding = if (isWide) 32.dp else 20.dp
Box(modifier = Modifier.fillMaxSize()) {
if (isWide) {
Row(modifier = Modifier.fillMaxSize()) {
MediaHero(
imageUrl = movie.heroImageUrl,
backgroundColor = MaterialTheme.colorScheme.background,
height = 300.dp,
modifier = Modifier
.fillMaxHeight()
.weight(0.5f)
)
MovieDetails(
movie = movie,
modifier = Modifier
.weight(0.5f)
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.padding(
start = contentPadding,
end = contentPadding,
top = 96.dp,
bottom = 32.dp
)
)
}
} else {
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
MediaHero(
imageUrl = movie.heroImageUrl,
height = 400.dp,
backgroundColor = MaterialTheme.colorScheme.background,
modifier = Modifier.fillMaxWidth()
)
MovieDetails(
movie = movie,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = contentPadding)
.offset(y = (-48).dp)
.padding(bottom = 96.dp)
)
}
}
MovieTopBar( MovieTopBar(
onBack = onBack,
modifier = Modifier
)
},
floatingActionButton = {
MediaFloatingPlayButton(
containerColor = MaterialTheme.colorScheme.primary,
onContainerColor = MaterialTheme.colorScheme.onPrimary,
onClick = playAction,
modifier = Modifier
.padding(16.dp)
)
}
) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
) {
MediaHero(
imageUrl = movie.heroImageUrl,
backgroundColor = MaterialTheme.colorScheme.background,
height = 200.dp,
modifier = Modifier.fillMaxWidth()
)
MovieDetails(
movie = movie,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp) .padding(horizontal = 16.dp)
.padding(bottom = innerPadding.calculateBottomPadding())
) )
if (!isWide) {
MediaFloatingPlayButton(
containerColor = MaterialTheme.colorScheme.primary,
onContainerColor = MaterialTheme.colorScheme.onPrimary,
onClick = playAction,
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(20.dp)
)
}
} }
} }
} }
@Preview @Preview
@Composable @Composable
fun MovieScreenPreview() { fun MovieScreenPreview() {
MovieScreenInternal(movie = ContentMockData.movie()) MovieScreenInternal(
movie = ContentMockData.movie(),
onBack = {}
)
} }

View File

@@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
@@ -54,18 +55,21 @@ import hu.bbara.purefin.common.ui.toMediaDetailColors
@Composable @Composable
internal fun SeriesTopBar( internal fun SeriesTopBar(
viewModel: SeriesViewModel = hiltViewModel(), onBack: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val colors = rememberSeriesColors().toMediaDetailColors() val colors = rememberSeriesColors().toMediaDetailColors()
Row( Row(
modifier = modifier, modifier = modifier
.fillMaxWidth()
.statusBarsPadding()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
MediaGhostIconButton( MediaGhostIconButton(
colors = colors, colors = colors,
onClick = { viewModel.onBack() }, onClick = onBack,
icon = Icons.Outlined.ArrowBack, icon = Icons.Outlined.ArrowBack,
contentDescription = "Back") contentDescription = "Back")
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {

View File

@@ -1,21 +1,19 @@
package hu.bbara.purefin.app.content.series package hu.bbara.purefin.app.content.series
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
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.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@@ -41,6 +39,7 @@ fun SeriesScreen(
if (series.value != null) { if (series.value != null) {
SeriesScreenInternal( SeriesScreenInternal(
series = series.value!!, series = series.value!!,
onBack = viewModel::onBack,
modifier = modifier modifier = modifier
) )
} else { } else {
@@ -51,16 +50,21 @@ fun SeriesScreen(
@Composable @Composable
private fun SeriesScreenInternal( private fun SeriesScreenInternal(
series: SeriesUiModel, series: SeriesUiModel,
onBack: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val colors = rememberSeriesColors() val colors = rememberSeriesColors()
BoxWithConstraints( Scaffold(
modifier = modifier modifier = modifier,
.fillMaxSize() containerColor = MaterialTheme.colorScheme.background,
.background(colors.background) topBar = {
) { SeriesTopBar(
val heroHeight = maxHeight * 0.4f onBack = onBack,
modifier = Modifier
)
}
) { innerPadding ->
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -68,89 +72,73 @@ private fun SeriesScreenInternal(
) { ) {
SeriesHero( SeriesHero(
imageUrl = series.heroImageUrl, imageUrl = series.heroImageUrl,
height = heroHeight height = 200.dp,
modifier = Modifier.fillMaxWidth()
) )
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.offset(y = (-96).dp) .padding(horizontal = 16.dp)
.padding(bottom = innerPadding.calculateBottomPadding())
) { ) {
Column( Text(
modifier = Modifier text = series.title,
.fillMaxWidth() color = colors.textPrimary,
.padding(horizontal = 20.dp) fontSize = 30.sp,
) { fontWeight = FontWeight.Bold,
Text( lineHeight = 36.sp
text = series.title, )
color = colors.textPrimary, Spacer(modifier = Modifier.height(16.dp))
fontSize = 30.sp, SeriesMetaChips(series = series)
fontWeight = FontWeight.Bold, Spacer(modifier = Modifier.height(24.dp))
lineHeight = 36.sp SeriesActionButtons()
) Spacer(modifier = Modifier.height(24.dp))
Spacer(modifier = Modifier.height(16.dp)) Text(
SeriesMetaChips(series = series) text = "Synopsis",
Spacer(modifier = Modifier.height(24.dp)) color = colors.textPrimary,
SeriesActionButtons() fontSize = 18.sp,
Spacer(modifier = Modifier.height(24.dp)) fontWeight = FontWeight.Bold
Text( )
text = "Synopsis", Spacer(modifier = Modifier.height(8.dp))
color = colors.textPrimary, Text(
fontSize = 18.sp, text = series.synopsis,
fontWeight = FontWeight.Bold color = colors.textMutedStrong,
) fontSize = 13.sp,
Spacer(modifier = Modifier.height(8.dp)) )
Text( Spacer(modifier = Modifier.height(28.dp))
text = series.synopsis, Text(
color = colors.textMutedStrong, text = "Episodes",
fontSize = 13.sp, color = colors.textPrimary,
) fontSize = 18.sp,
Spacer(modifier = Modifier.height(28.dp)) fontWeight = FontWeight.Bold
Text( )
text = "Episodes", Spacer(modifier = Modifier.height(28.dp))
color = colors.textPrimary, SeasonTabs(seasons = series.seasonTabs)
fontSize = 18.sp, Spacer(modifier = Modifier.height(16.dp))
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.height(28.dp))
SeasonTabs(seasons = series.seasonTabs)
Spacer(modifier = Modifier.height(16.dp))
}
EpisodeCarousel( EpisodeCarousel(
episodes = series.seasonTabs.firstOrNull { it.isSelected }?.episodes episodes = series.seasonTabs.firstOrNull { it.isSelected }?.episodes
?: series.seasonTabs.firstOrNull()?.episodes ?: series.seasonTabs.firstOrNull()?.episodes
?: emptyList() ?: emptyList()
) )
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(32.dp))
Column( Text(
modifier = Modifier text = "Cast",
.fillMaxWidth() color = colors.textPrimary,
.padding(top = 0.dp, bottom = 0.dp) fontSize = 18.sp,
) { fontWeight = FontWeight.Bold
Text( )
text = "Cast", Spacer(modifier = Modifier.height(12.dp))
color = colors.textPrimary, CastRow(cast = series.cast)
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(horizontal = 20.dp)
)
Spacer(modifier = Modifier.height(12.dp))
CastRow(cast = series.cast)
}
} }
} }
SeriesTopBar(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp)
.align(Alignment.TopCenter)
)
} }
} }
@Preview @Preview
@Composable @Composable
fun SeriesScreenPreview() { fun SeriesScreenPreview() {
SeriesScreenInternal(series = ContentMockData.series()) SeriesScreenInternal(
series = ContentMockData.series(),
onBack = {}
)
} }