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 974a526a..c31be505 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 @@ -6,8 +6,6 @@ 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 import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -40,7 +38,6 @@ 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 -import hu.bbara.purefin.common.ui.MediaMetaChip import hu.bbara.purefin.common.ui.MediaSynopsis import hu.bbara.purefin.common.ui.components.GhostIconButton import hu.bbara.purefin.common.ui.components.MediaActionButton @@ -114,7 +111,6 @@ internal fun EpisodeTopBar( } } -@OptIn(ExperimentalLayoutApi::class) @Composable internal fun EpisodeDetails( episode: Episode, @@ -134,37 +130,6 @@ internal fun EpisodeDetails( } Column(modifier = modifier) { - Text( - text = episode.title, - color = scheme.onBackground, - fontSize = 32.sp, - fontWeight = FontWeight.Bold, - lineHeight = 38.sp - ) - Spacer(modifier = Modifier.height(4.dp)) - Text( - text = "Episode ${episode.index}", - color = scheme.onBackground, - fontSize = 14.sp, - fontWeight = FontWeight.Medium - ) - Spacer(modifier = Modifier.height(16.dp)) - FlowRow( - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - MediaMetaChip(text = episode.releaseDate) - MediaMetaChip(text = episode.rating) - MediaMetaChip(text = episode.runtime) - MediaMetaChip( - text = episode.format, - background = scheme.primary.copy(alpha = 0.2f), - border = scheme.primary.copy(alpha = 0.3f), - textColor = scheme.primary - ) - } - Spacer(modifier = Modifier.height(24.dp)) - MediaSynopsis( synopsis = episode.synopsis ) 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 51caa518..9c597742 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 @@ -4,30 +4,44 @@ import android.Manifest import android.os.Build import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.foundation.background +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 +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import hu.bbara.purefin.common.ui.MediaMetaChip import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.components.MediaHero import hu.bbara.purefin.core.data.navigation.EpisodeDto import hu.bbara.purefin.core.data.navigation.LocalNavigationBackStack -import hu.bbara.purefin.core.data.navigation.LocalNavigationManager import hu.bbara.purefin.core.data.navigation.Route -import hu.bbara.purefin.core.model.Episode import hu.bbara.purefin.core.model.CastMember +import hu.bbara.purefin.core.model.Episode import hu.bbara.purefin.feature.download.DownloadState import hu.bbara.purefin.feature.shared.content.episode.EpisodeScreenViewModel import hu.bbara.purefin.ui.theme.AppTheme @@ -39,7 +53,6 @@ fun EpisodeScreen( viewModel: EpisodeScreenViewModel = hiltViewModel(), modifier: Modifier = Modifier ) { - val navigationManager = LocalNavigationManager.current val backStack = LocalNavigationBackStack.current val previousRoute = remember(backStack) { backStack.getOrNull(backStack.lastIndex - 1) } @@ -120,12 +133,7 @@ private fun EpisodeScreenInternal( .fillMaxSize() .verticalScroll(rememberScrollState()) ) { - MediaHero( - imageUrl = episode.heroImageUrl, - backgroundColor = MaterialTheme.colorScheme.background, - heightFraction = 0.30f, - modifier = Modifier.fillMaxWidth() - ) + EpisodeHeroSection(episode = episode) EpisodeDetails( episode = episode, downloadState = downloadState, @@ -139,6 +147,86 @@ private fun EpisodeScreenInternal( } } +@Composable +private fun EpisodeHeroSection( + episode: Episode, + modifier: Modifier = Modifier, +) { + val scheme = MaterialTheme.colorScheme + val screenHeight = LocalConfiguration.current.screenHeightDp.dp + val sectionHeight = screenHeight * 0.4f + + Box( + modifier = modifier + .fillMaxWidth() + .height(sectionHeight) + ) { + MediaHero( + imageUrl = episode.heroImageUrl, + backgroundColor = scheme.background, + modifier = Modifier.fillMaxSize() + ) + Box( + modifier = Modifier + .matchParentSize() + .background( + Brush.verticalGradient( + colors = listOf( + Color.Transparent, + Color.Transparent, + scheme.background.copy(alpha = 0.5f), + scheme.background + ) + ) + ) + ) + Column( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomStart) + .padding(16.dp) + ) { + Text( + text = episode.title, + color = scheme.onBackground, + fontSize = 32.sp, + fontWeight = FontWeight.Bold, + lineHeight = 38.sp + ) + Spacer(modifier = Modifier.height(4.dp)) + Text( + text = "Episode ${episode.index}", + color = scheme.onBackground, + fontSize = 14.sp, + fontWeight = FontWeight.Medium + ) + Spacer(modifier = Modifier.height(16.dp)) + EpisodeMetaChips(episode = episode) + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun EpisodeMetaChips(episode: Episode) { + val scheme = MaterialTheme.colorScheme + + FlowRow( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + MediaMetaChip(text = episode.releaseDate) + MediaMetaChip(text = episode.rating) + MediaMetaChip(text = episode.runtime) + MediaMetaChip( + text = episode.format, + background = scheme.primary.copy(alpha = 0.2f), + border = scheme.primary.copy(alpha = 0.3f), + textColor = scheme.primary + ) + } +} + @Preview(showBackground = true) @Composable private fun EpisodeScreenPreview() { diff --git a/app/src/main/java/hu/bbara/purefin/app/content/movie/MovieComponents.kt b/app/src/main/java/hu/bbara/purefin/app/content/movie/MovieComponents.kt index e557a69d..1a3e26e7 100644 --- a/app/src/main/java/hu/bbara/purefin/app/content/movie/MovieComponents.kt +++ b/app/src/main/java/hu/bbara/purefin/app/content/movie/MovieComponents.kt @@ -4,7 +4,6 @@ import android.content.Intent import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -12,9 +11,7 @@ import androidx.compose.foundation.layout.height 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.material.icons.Icons -import androidx.compose.material.icons.outlined.Add import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.Cast import androidx.compose.material.icons.outlined.Close @@ -33,7 +30,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import hu.bbara.purefin.common.ui.MediaCastRow -import hu.bbara.purefin.common.ui.MediaMetaChip import hu.bbara.purefin.common.ui.MediaSynopsis import hu.bbara.purefin.common.ui.components.GhostIconButton import hu.bbara.purefin.common.ui.components.MediaActionButton @@ -89,30 +85,6 @@ internal fun MovieDetails( } Column(modifier = modifier) { - Text( - text = movie.title, - color = scheme.onBackground, - fontSize = 32.sp, - fontWeight = FontWeight.Bold, - lineHeight = 38.sp - ) - Spacer(modifier = Modifier.height(16.dp)) - FlowRow( - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - MediaMetaChip(text = movie.year) - MediaMetaChip(text = movie.rating) - MediaMetaChip(text = movie.runtime) - MediaMetaChip( - text = movie.format, - background = scheme.primary.copy(alpha = 0.2f), - border = scheme.primary.copy(alpha = 0.3f), - textColor = scheme.primary - ) - } - Spacer(modifier = Modifier.height(24.dp)) - MediaSynopsis( synopsis = movie.synopsis ) diff --git a/app/src/main/java/hu/bbara/purefin/app/content/movie/MovieScreen.kt b/app/src/main/java/hu/bbara/purefin/app/content/movie/MovieScreen.kt index 4e9daebe..d25a1972 100644 --- a/app/src/main/java/hu/bbara/purefin/app/content/movie/MovieScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/app/content/movie/MovieScreen.kt @@ -4,21 +4,35 @@ import android.Manifest import android.os.Build import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.FlowRow +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import hu.bbara.purefin.common.ui.MediaMetaChip import hu.bbara.purefin.common.ui.PurefinWaitingScreen import hu.bbara.purefin.common.ui.components.MediaHero import hu.bbara.purefin.core.data.navigation.MovieDto @@ -93,12 +107,7 @@ private fun MovieScreenInternal( .fillMaxSize() .verticalScroll(rememberScrollState()) ) { - MediaHero( - imageUrl = movie.heroImageUrl, - backgroundColor = MaterialTheme.colorScheme.background, - heightFraction = 0.30f, - modifier = Modifier.fillMaxWidth() - ) + MediaHeroSection(movie = movie) MovieDetails( movie = movie, downloadState = downloadState, @@ -112,6 +121,69 @@ private fun MovieScreenInternal( } } +@Composable +fun MediaHeroSection( + movie: Movie, + modifier: Modifier = Modifier) { + + val scheme = MaterialTheme.colorScheme + val screenHeight = LocalConfiguration.current.screenHeightDp.dp + val sectionHeight = screenHeight * 0.4f + + Box ( + modifier = modifier + .height(sectionHeight) + ) { + MediaHero( + imageUrl = movie.heroImageUrl, + backgroundColor = MaterialTheme.colorScheme.background, + modifier = Modifier.fillMaxSize() + ) + Box( + modifier = Modifier + .matchParentSize() + .background( + Brush.verticalGradient( + colors = listOf( + Color.Transparent, + Color.Transparent, + scheme.background.copy(alpha = 0.5f), + scheme.background + ) + ) + ) + ) + Column ( + modifier = Modifier.fillMaxWidth() + .align(Alignment.BottomStart) + .padding(16.dp) + ) { + Text( + text = movie.title, + color = scheme.onBackground, + fontSize = 32.sp, + fontWeight = FontWeight.Bold, + lineHeight = 38.sp + ) + Spacer(modifier = Modifier.height(16.dp)) + FlowRow( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + MediaMetaChip(text = movie.year) + MediaMetaChip(text = movie.rating) + MediaMetaChip(text = movie.runtime) + MediaMetaChip( + text = movie.format, + background = scheme.primary.copy(alpha = 0.2f), + border = scheme.primary.copy(alpha = 0.3f), + textColor = scheme.primary + ) + } + } + } +} + @Preview(showBackground = true) @Composable private fun MovieScreenPreview() { diff --git a/app/src/main/java/hu/bbara/purefin/app/content/series/SeriesScreen.kt b/app/src/main/java/hu/bbara/purefin/app/content/series/SeriesScreen.kt index b56903b1..cdef6ddb 100644 --- a/app/src/main/java/hu/bbara/purefin/app/content/series/SeriesScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/app/content/series/SeriesScreen.kt @@ -19,7 +19,13 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.Alignment +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -128,28 +134,13 @@ private fun SeriesScreenInternal( .fillMaxSize() .verticalScroll(rememberScrollState()) ) { - MediaHero( - imageUrl = series.heroImageUrl, - heightFraction = 0.30f, - backgroundColor = MaterialTheme.colorScheme.background, - modifier = Modifier.fillMaxWidth() - ) + SeriesHeroSection(series = series) Column( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp) .padding(bottom = innerPadding.calculateBottomPadding()) ) { - Text( - text = series.name, - color = scheme.onBackground, - fontSize = 30.sp, - fontWeight = FontWeight.Bold, - lineHeight = 36.sp - ) - Spacer(modifier = Modifier.height(16.dp)) - SeriesMetaChips(series = series) - Spacer(modifier = Modifier.height(24.dp)) SeriesActionButtons( nextUpEpisode = nextUpEpisode, seriesDownloadState = seriesDownloadState, @@ -192,6 +183,58 @@ private fun SeriesScreenInternal( } } +@Composable +private fun SeriesHeroSection( + series: Series, + modifier: Modifier = Modifier, +) { + val scheme = MaterialTheme.colorScheme + val screenHeight = LocalConfiguration.current.screenHeightDp.dp + val sectionHeight = screenHeight * 0.4f + + Box( + modifier = modifier + .fillMaxWidth() + .height(sectionHeight) + ) { + MediaHero( + imageUrl = series.heroImageUrl, + backgroundColor = scheme.background, + modifier = Modifier.fillMaxSize() + ) + Box( + modifier = Modifier + .matchParentSize() + .background( + Brush.verticalGradient( + colors = listOf( + Color.Transparent, + Color.Transparent, + scheme.background.copy(alpha = 0.5f), + scheme.background + ) + ) + ) + ) + Column( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.BottomStart) + .padding(16.dp) + ) { + Text( + text = series.name, + color = scheme.onBackground, + fontSize = 30.sp, + fontWeight = FontWeight.Bold, + lineHeight = 36.sp + ) + Spacer(modifier = Modifier.height(16.dp)) + SeriesMetaChips(series = series) + } + } +} + @Preview(showBackground = true) @Composable private fun SeriesScreenPreview() {