mirror of
https://github.com/bbara04/Purefin.git
synced 2026-04-01 01:30:08 +02:00
refactor: Extract and generalize MediaHero component. Now MovieScreen, SeriesScreen and EpisodeScreen also use the same Component.
This commit is contained in:
@@ -27,9 +27,9 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.hilt.navigation.compose.hiltViewModel
|
||||
@@ -38,9 +38,9 @@ import hu.bbara.purefin.common.ui.MediaCastMember
|
||||
import hu.bbara.purefin.common.ui.MediaCastRow
|
||||
import hu.bbara.purefin.common.ui.MediaFloatingPlayButton
|
||||
import hu.bbara.purefin.common.ui.MediaGhostIconButton
|
||||
import hu.bbara.purefin.common.ui.MediaHero
|
||||
import hu.bbara.purefin.common.ui.MediaMetaChip
|
||||
import hu.bbara.purefin.common.ui.MediaPlaybackSettings
|
||||
import hu.bbara.purefin.common.ui.components.MediaHero
|
||||
import hu.bbara.purefin.common.ui.toMediaDetailColors
|
||||
import hu.bbara.purefin.player.PlayerActivity
|
||||
|
||||
@@ -68,27 +68,6 @@ internal fun EpisodeTopBar(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun EpisodeHero(
|
||||
episode: EpisodeUiModel,
|
||||
height: Dp,
|
||||
isWide: Boolean,
|
||||
onPlayClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val colors = rememberEpisodeColors().toMediaDetailColors()
|
||||
MediaHero(
|
||||
imageUrl = episode.heroImageUrl,
|
||||
colors = colors,
|
||||
height = height,
|
||||
isWide = isWide,
|
||||
modifier = modifier,
|
||||
showPlayButton = true,
|
||||
playButtonSize = if (isWide) 96.dp else 80.dp,
|
||||
onPlayClick = onPlayClick
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
internal fun EpisodeDetails(
|
||||
@@ -164,6 +143,7 @@ internal fun EpisodeDetails(
|
||||
@Composable
|
||||
fun EpisodeCard(
|
||||
episode: EpisodeUiModel,
|
||||
backGroundColor: Color,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val colors = rememberEpisodeColors().toMediaDetailColors()
|
||||
@@ -187,11 +167,10 @@ fun EpisodeCard(
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
if (isWide) {
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
EpisodeHero(
|
||||
episode = episode,
|
||||
MediaHero(
|
||||
imageUrl = episode.heroImageUrl,
|
||||
height = 300.dp,
|
||||
isWide = true,
|
||||
onPlayClick = playAction,
|
||||
backgroundColor = backGroundColor,
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(0.5f)
|
||||
@@ -216,11 +195,10 @@ fun EpisodeCard(
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
EpisodeHero(
|
||||
episode = episode,
|
||||
MediaHero(
|
||||
imageUrl = episode.heroImageUrl,
|
||||
backgroundColor = backGroundColor,
|
||||
height = 400.dp,
|
||||
isWide = false,
|
||||
onPlayClick = playAction,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
EpisodeDetails(
|
||||
@@ -242,7 +220,8 @@ fun EpisodeCard(
|
||||
|
||||
if (!isWide) {
|
||||
MediaFloatingPlayButton(
|
||||
colors = colors,
|
||||
containerColor = colors.primary,
|
||||
onContainerColor = colors.onPrimary,
|
||||
onClick = playAction,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomEnd)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package hu.bbara.purefin.app.content.episode
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
@@ -24,7 +25,8 @@ fun EpisodeScreen(
|
||||
if (episode.value != null) {
|
||||
EpisodeCard(
|
||||
episode = episode.value!!,
|
||||
modifier = modifier
|
||||
modifier = modifier,
|
||||
backGroundColor = MaterialTheme.colorScheme.background
|
||||
)
|
||||
} else {
|
||||
PurefinWaitingScreen()
|
||||
|
||||
@@ -22,6 +22,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.outlined.Cast
|
||||
import androidx.compose.material.icons.outlined.MoreVert
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
@@ -29,7 +30,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
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.hilt.navigation.compose.hiltViewModel
|
||||
@@ -38,9 +38,9 @@ import hu.bbara.purefin.common.ui.MediaCastMember
|
||||
import hu.bbara.purefin.common.ui.MediaCastRow
|
||||
import hu.bbara.purefin.common.ui.MediaFloatingPlayButton
|
||||
import hu.bbara.purefin.common.ui.MediaGhostIconButton
|
||||
import hu.bbara.purefin.common.ui.MediaHero
|
||||
import hu.bbara.purefin.common.ui.MediaMetaChip
|
||||
import hu.bbara.purefin.common.ui.MediaPlaybackSettings
|
||||
import hu.bbara.purefin.common.ui.components.MediaHero
|
||||
import hu.bbara.purefin.common.ui.toMediaDetailColors
|
||||
import hu.bbara.purefin.player.PlayerActivity
|
||||
|
||||
@@ -68,27 +68,6 @@ internal fun MovieTopBar(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun MovieHero(
|
||||
movie: MovieUiModel,
|
||||
height: Dp,
|
||||
isWide: Boolean,
|
||||
onPlayClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val colors = rememberMovieColors().toMediaDetailColors()
|
||||
MediaHero(
|
||||
imageUrl = movie.heroImageUrl,
|
||||
colors = colors,
|
||||
height = height,
|
||||
isWide = isWide,
|
||||
modifier = modifier,
|
||||
showPlayButton = true,
|
||||
playButtonSize = if (isWide) 96.dp else 80.dp,
|
||||
onPlayClick = onPlayClick
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
internal fun MovieDetails(
|
||||
@@ -161,12 +140,13 @@ internal fun MovieDetails(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Composable
|
||||
fun MovieCard(
|
||||
movie: MovieUiModel,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val colors = rememberMovieColors().toMediaDetailColors()
|
||||
val context = LocalContext.current
|
||||
val playAction = remember(movie.id) {
|
||||
{
|
||||
@@ -179,7 +159,7 @@ fun MovieCard(
|
||||
BoxWithConstraints(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(colors.background)
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
) {
|
||||
val isWide = maxWidth >= 900.dp
|
||||
val contentPadding = if (isWide) 32.dp else 20.dp
|
||||
@@ -187,11 +167,10 @@ fun MovieCard(
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
if (isWide) {
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
MovieHero(
|
||||
movie = movie,
|
||||
MediaHero(
|
||||
imageUrl = movie.heroImageUrl,
|
||||
backgroundColor = MaterialTheme.colorScheme.background,
|
||||
height = 300.dp,
|
||||
isWide = true,
|
||||
onPlayClick = playAction,
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(0.5f)
|
||||
@@ -216,11 +195,10 @@ fun MovieCard(
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
MovieHero(
|
||||
movie = movie,
|
||||
MediaHero(
|
||||
imageUrl = movie.heroImageUrl,
|
||||
height = 400.dp,
|
||||
isWide = false,
|
||||
onPlayClick = playAction,
|
||||
backgroundColor = MaterialTheme.colorScheme.background,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
MovieDetails(
|
||||
@@ -242,7 +220,9 @@ fun MovieCard(
|
||||
|
||||
if (!isWide) {
|
||||
MediaFloatingPlayButton(
|
||||
colors = colors,
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
onContainerColor = MaterialTheme.colorScheme.onPrimary,
|
||||
|
||||
onClick = playAction,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomEnd)
|
||||
|
||||
@@ -29,6 +29,7 @@ import androidx.compose.material.icons.outlined.Cast
|
||||
import androidx.compose.material.icons.outlined.MoreVert
|
||||
import androidx.compose.material.icons.outlined.PlayCircle
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -47,8 +48,8 @@ import hu.bbara.purefin.common.ui.MediaActionButtons
|
||||
import hu.bbara.purefin.common.ui.MediaCastMember
|
||||
import hu.bbara.purefin.common.ui.MediaCastRow
|
||||
import hu.bbara.purefin.common.ui.MediaGhostIconButton
|
||||
import hu.bbara.purefin.common.ui.MediaHero
|
||||
import hu.bbara.purefin.common.ui.MediaMetaChip
|
||||
import hu.bbara.purefin.common.ui.components.MediaHero
|
||||
import hu.bbara.purefin.common.ui.toMediaDetailColors
|
||||
|
||||
@Composable
|
||||
@@ -83,12 +84,9 @@ internal fun SeriesHero(
|
||||
val colors = rememberSeriesColors().toMediaDetailColors()
|
||||
MediaHero(
|
||||
imageUrl = imageUrl,
|
||||
colors = colors,
|
||||
backgroundColor = MaterialTheme.colorScheme.background,
|
||||
height = height,
|
||||
isWide = false,
|
||||
modifier = modifier,
|
||||
showPlayButton = false,
|
||||
horizontalGradientOnWide = false
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
@@ -128,71 +127,6 @@ fun MediaGhostIconButton(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MediaHero(
|
||||
imageUrl: String,
|
||||
colors: MediaDetailColors,
|
||||
height: Dp,
|
||||
isWide: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
showPlayButton: Boolean = false,
|
||||
playButtonSize: Dp = 80.dp,
|
||||
onPlayClick: (() -> Unit)? = null,
|
||||
horizontalGradientOnWide: Boolean = true
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.height(height)
|
||||
.background(colors.background)
|
||||
) {
|
||||
AsyncImage(
|
||||
model = imageUrl,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
colors.background.copy(alpha = 0.4f),
|
||||
colors.background
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
if (horizontalGradientOnWide && isWide) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.background(
|
||||
Brush.horizontalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
colors.background.copy(alpha = 0.8f)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
if (showPlayButton && onPlayClick != null) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
MediaPlayButton(
|
||||
colors = colors,
|
||||
size = playButtonSize,
|
||||
onClick = onPlayClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MediaMetaChip(
|
||||
colors: MediaDetailColors,
|
||||
@@ -469,7 +403,8 @@ fun MediaPlayButton(
|
||||
|
||||
@Composable
|
||||
fun MediaFloatingPlayButton(
|
||||
colors: MediaDetailColors,
|
||||
containerColor: Color,
|
||||
onContainerColor: Color,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
@@ -478,14 +413,14 @@ fun MediaFloatingPlayButton(
|
||||
.size(56.dp)
|
||||
.shadow(20.dp, CircleShape)
|
||||
.clip(CircleShape)
|
||||
.background(colors.primary)
|
||||
.background(containerColor)
|
||||
.clickable { onClick() },
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.PlayArrow,
|
||||
contentDescription = "Play",
|
||||
tint = colors.onPrimary
|
||||
tint = onContainerColor
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package hu.bbara.purefin.common.ui.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import coil3.compose.AsyncImage
|
||||
|
||||
@Composable
|
||||
fun MediaHero(
|
||||
imageUrl: String,
|
||||
backgroundColor: Color,
|
||||
height: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.height(height)
|
||||
.background(backgroundColor)
|
||||
) {
|
||||
AsyncImage(
|
||||
model = imageUrl,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor.copy(alpha = 0.4f),
|
||||
backgroundColor
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.matchParentSize()
|
||||
.background(
|
||||
Brush.horizontalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
backgroundColor.copy(alpha = 0.8f)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user