feat: use MediaResumeButton with progress in Movie and Episode screens

Replace MediaPlayButton with MediaResumeButton in both MovieComponents
and EpisodeComponents, converting Double progress (0-100) to Float (0-1).
This commit is contained in:
2026-02-19 20:20:13 +01:00
parent 17ddc0b160
commit 6191098158
7 changed files with 137 additions and 19 deletions

View File

@@ -135,6 +135,7 @@ object ContentMockData {
heroImageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuD3hBjDpw00tDCQsK5xNcnJra301k1T4LksWVZzHieH9KHQItEQkVzhwevJvf8RkaQKdVKvObzRlfDDqa3_PNwLUlUQc1LpDih8p94VTGobEV62qi7QrmNyQm_o55KRMNWiTG3zLLpblGqo3uUNQcYmPFqfNML95dClXQ4lQNl85-zgerPPAbGPr23dswbIYCigyTAaXgrmdV_nbNQ5LdDB0Wh5cMHtP0uxz6k3ARjNom6clhphGIUF9e6YSvKuwuiZ-1lMYFg8C_4", heroImageUrl = "https://lh3.googleusercontent.com/aida-public/AB6AXuD3hBjDpw00tDCQsK5xNcnJra301k1T4LksWVZzHieH9KHQItEQkVzhwevJvf8RkaQKdVKvObzRlfDDqa3_PNwLUlUQc1LpDih8p94VTGobEV62qi7QrmNyQm_o55KRMNWiTG3zLLpblGqo3uUNQcYmPFqfNML95dClXQ4lQNl85-zgerPPAbGPr23dswbIYCigyTAaXgrmdV_nbNQ5LdDB0Wh5cMHtP0uxz6k3ARjNom6clhphGIUF9e6YSvKuwuiZ-1lMYFg8C_4",
audioTrack = "English (Dolby Atmos)", audioTrack = "English (Dolby Atmos)",
subtitles = "English, Spanish, French", subtitles = "English, Spanish, French",
progress = 45.0,
cast = castMembers cast = castMembers
) )
} }

View File

@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Spacer
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.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -34,8 +35,8 @@ import hu.bbara.purefin.common.ui.MediaMetaChip
import hu.bbara.purefin.common.ui.MediaSynopsis import hu.bbara.purefin.common.ui.MediaSynopsis
import hu.bbara.purefin.common.ui.components.GhostIconButton import hu.bbara.purefin.common.ui.components.GhostIconButton
import hu.bbara.purefin.common.ui.components.MediaActionButton import hu.bbara.purefin.common.ui.components.MediaActionButton
import hu.bbara.purefin.common.ui.components.MediaPlayButton
import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings
import hu.bbara.purefin.common.ui.components.MediaResumeButton
import hu.bbara.purefin.data.model.Episode import hu.bbara.purefin.data.model.Episode
import hu.bbara.purefin.player.PlayerActivity import hu.bbara.purefin.player.PlayerActivity
@@ -119,11 +120,20 @@ internal fun EpisodeDetails(
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
Row() { Row() {
MediaPlayButton( // MediaPlayButton(
backgroundColor = MaterialTheme.colorScheme.primary, // backgroundColor = MaterialTheme.colorScheme.primary,
foregroundColor = MaterialTheme.colorScheme.onPrimary, // foregroundColor = MaterialTheme.colorScheme.onPrimary,
size = 48.dp, // text = if (episode.progress == null) "Play" else "Resume",
onClick = playAction // subText = if (episode.progress == null) null else "${episode.progress.toInt() }%",
// modifier = Modifier.weight(1f),
// size = 48.dp,
// onClick = playAction
// )
MediaResumeButton(
text = if (episode.progress == null) "Play" else "Resume",
progress = episode.progress?.div(100)?.toFloat() ?: 0f,
onClick = playAction,
modifier = Modifier.sizeIn(maxWidth = 200.dp)
) )
VerticalDivider( VerticalDivider(
color = MaterialTheme.colorScheme.secondary, color = MaterialTheme.colorScheme.secondary,

View File

@@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.Spacer
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.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.sizeIn
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@@ -36,8 +37,8 @@ import hu.bbara.purefin.common.ui.MediaMetaChip
import hu.bbara.purefin.common.ui.MediaSynopsis import hu.bbara.purefin.common.ui.MediaSynopsis
import hu.bbara.purefin.common.ui.components.GhostIconButton import hu.bbara.purefin.common.ui.components.GhostIconButton
import hu.bbara.purefin.common.ui.components.MediaActionButton import hu.bbara.purefin.common.ui.components.MediaActionButton
import hu.bbara.purefin.common.ui.components.MediaPlayButton
import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings import hu.bbara.purefin.common.ui.components.MediaPlaybackSettings
import hu.bbara.purefin.common.ui.components.MediaResumeButton
import hu.bbara.purefin.download.DownloadState import hu.bbara.purefin.download.DownloadState
import hu.bbara.purefin.player.PlayerActivity import hu.bbara.purefin.player.PlayerActivity
@@ -117,11 +118,11 @@ internal fun MovieDetails(
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))
Row() { Row() {
MediaPlayButton( MediaResumeButton(
backgroundColor = MaterialTheme.colorScheme.primary, text = if (movie.progress == null) "Play" else "Resume",
foregroundColor = MaterialTheme.colorScheme.onPrimary, progress = movie.progress?.div(100)?.toFloat() ?: 0f,
size = 48.dp, onClick = playAction,
onClick = playAction modifier = Modifier.sizeIn(maxWidth = 200.dp)
) )
VerticalDivider( VerticalDivider(
color = MaterialTheme.colorScheme.secondary, color = MaterialTheme.colorScheme.secondary,

View File

@@ -19,5 +19,6 @@ data class MovieUiModel(
val heroImageUrl: String, val heroImageUrl: String,
val audioTrack: String, val audioTrack: String,
val subtitles: String, val subtitles: String,
val progress: Double?,
val cast: List<CastMember> val cast: List<CastMember>
) )

View File

@@ -84,6 +84,7 @@ class MovieScreenViewModel @Inject constructor(
heroImageUrl = heroImageUrl, heroImageUrl = heroImageUrl,
audioTrack = audioTrack, audioTrack = audioTrack,
subtitles = subtitles, subtitles = subtitles,
progress = progress,
cast = cast.map { CastMember(name = it.name, role = it.role, imageUrl = it.imageUrl) } cast = cast.map { CastMember(name = it.name, role = it.role, imageUrl = it.imageUrl) }
) )
} }

View File

@@ -3,6 +3,7 @@ package hu.bbara.purefin.common.ui.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -26,6 +27,8 @@ import androidx.compose.ui.unit.dp
fun MediaPlayButton( fun MediaPlayButton(
backgroundColor: Color, backgroundColor: Color,
foregroundColor: Color, foregroundColor: Color,
text: String = "Play",
subText: String? = null,
size: Dp, size: Dp,
onClick: () -> Unit, onClick: () -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
@@ -46,13 +49,25 @@ fun MediaPlayButton(
tint = foregroundColor, tint = foregroundColor,
modifier = Modifier.size(42.dp) modifier = Modifier.size(42.dp)
) )
Text( Column() {
text = "Play", Text(
color = foregroundColor, text = text,
fontSize = TextUnit( color = foregroundColor,
value = 16f, fontSize = TextUnit(
type = TextUnitType.Sp value = 16f,
type = TextUnitType.Sp
)
) )
) subText?.let {
Text(
text = subText,
color = foregroundColor.copy(alpha = 0.7f),
fontSize = TextUnit(
value = 14f,
type = TextUnitType.Sp
)
)
}
}
} }
} }

View File

@@ -0,0 +1,89 @@
package hu.bbara.purefin.common.ui.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Row
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.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow
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
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.graphics.drawscope.clipRect
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun MediaResumeButton(
text: String,
progress: Float = 0f,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
val primaryColor = MaterialTheme.colorScheme.primary
val onPrimaryColor = MaterialTheme.colorScheme.onPrimary
BoxWithConstraints(
modifier = modifier
.height(52.dp)
.clip(RoundedCornerShape(50))
.clickable(onClick = onClick)
) {
// Bottom layer: inverted colors (visible for the remaining %)
Box(
modifier = Modifier
.fillMaxSize()
.background(onPrimaryColor),
contentAlignment = Alignment.Center
) {
ButtonContent(text = text, color = primaryColor)
}
// Top layer: primary colors, clipped to the progress %
Box(
modifier = Modifier
.fillMaxSize()
.drawWithContent {
val clipWidth = size.width * progress
clipRect(
left = 0f,
top = 0f,
right = clipWidth,
bottom = size.height
) {
this@drawWithContent.drawContent()
}
}
.background(primaryColor),
contentAlignment = Alignment.Center
) {
ButtonContent(text = text, color = onPrimaryColor)
}
}
}
@Composable
private fun ButtonContent(text: String, color: androidx.compose.ui.graphics.Color) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Text(text, color = color, fontWeight = FontWeight.Bold, fontSize = 16.sp)
Spacer(Modifier.width(8.dp))
Icon(Icons.Filled.PlayArrow, null, tint = color)
}
}