From 4300c8ce8477426fafb1fd3a9bc4d90926655821 Mon Sep 17 00:00:00 2001 From: Barnabas Balogh Date: Wed, 4 Feb 2026 14:20:34 +0100 Subject: [PATCH] feat: add MediaProgressBar component and integrate into SeriesComponents for episode progress display --- .../app/content/series/SeriesComponents.kt | 23 ++++++--- .../bbara/purefin/app/home/ui/HomeSections.kt | 22 +++------ .../common/ui/components/MediaProgressBar.kt | 47 +++++++++++++++++++ 3 files changed, 69 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/hu/bbara/purefin/common/ui/components/MediaProgressBar.kt diff --git a/app/src/main/java/hu/bbara/purefin/app/content/series/SeriesComponents.kt b/app/src/main/java/hu/bbara/purefin/app/content/series/SeriesComponents.kt index 9cce516..d4a38c8 100644 --- a/app/src/main/java/hu/bbara/purefin/app/content/series/SeriesComponents.kt +++ b/app/src/main/java/hu/bbara/purefin/app/content/series/SeriesComponents.kt @@ -50,6 +50,7 @@ import hu.bbara.purefin.common.ui.MediaCastRow import hu.bbara.purefin.common.ui.MediaMetaChip import hu.bbara.purefin.common.ui.components.GhostIconButton import hu.bbara.purefin.common.ui.components.MediaActionButton +import hu.bbara.purefin.common.ui.components.MediaProgressBar import hu.bbara.purefin.common.ui.components.PurefinAsyncImage import hu.bbara.purefin.common.ui.components.WatchStateIndicator import hu.bbara.purefin.data.model.CastMember @@ -255,13 +256,21 @@ private fun EpisodeCard( fontWeight = FontWeight.Bold ) } - WatchStateIndicator( - watched = episode.watched, - started = (episode.progress ?: 0.0) > 0.0, - modifier = Modifier - .align(Alignment.TopEnd) - .padding(8.dp) - ) + if (episode.watched.not() && (episode.progress ?: 0.0) > 0) { + MediaProgressBar( + progress = (episode.progress ?: 0.0).toFloat().div(100), + modifier = Modifier + .align(Alignment.BottomStart) + ) + } else { + WatchStateIndicator( + watched = episode.watched, + started = (episode.progress ?: 0.0) > 0.0, + modifier = Modifier + .align(Alignment.TopEnd) + .padding(8.dp) + ) + } } Column( ) { diff --git a/app/src/main/java/hu/bbara/purefin/app/home/ui/HomeSections.kt b/app/src/main/java/hu/bbara/purefin/app/home/ui/HomeSections.kt index 5c065b6..4236698 100644 --- a/app/src/main/java/hu/bbara/purefin/app/home/ui/HomeSections.kt +++ b/app/src/main/java/hu/bbara/purefin/app/home/ui/HomeSections.kt @@ -10,10 +10,8 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.aspectRatio -import androidx.compose.foundation.layout.fillMaxHeight 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.layout.size import androidx.compose.foundation.layout.width @@ -42,6 +40,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import coil3.request.ImageRequest import hu.bbara.purefin.common.ui.PosterCard +import hu.bbara.purefin.common.ui.components.MediaProgressBar import hu.bbara.purefin.common.ui.components.PurefinAsyncImage import hu.bbara.purefin.player.PlayerActivity import org.jellyfin.sdk.model.UUID @@ -136,22 +135,13 @@ fun ContinueWatchingCard( }, contentScale = ContentScale.Crop, ) - Box( + MediaProgressBar( + progress = item.progress.toFloat().nextUp().div(100), + foregroundColor = scheme.onSurface, + backgroundColor = scheme.primary, modifier = Modifier .align(Alignment.BottomStart) - .padding(bottom = 8.dp, start = 8.dp, end = 8.dp) - .clip(RoundedCornerShape(24.dp)) - .fillMaxWidth() - .height(4.dp) - .background(scheme.onBackground.copy(alpha = 0.2f)) - ) { - Box( - modifier = Modifier - .fillMaxHeight() - .fillMaxWidth(item.progress.toFloat().nextUp().div(100)) - .background(scheme.primary) - ) - } + ) IconButton( modifier = Modifier .align(Alignment.BottomEnd) diff --git a/app/src/main/java/hu/bbara/purefin/common/ui/components/MediaProgressBar.kt b/app/src/main/java/hu/bbara/purefin/common/ui/components/MediaProgressBar.kt new file mode 100644 index 0000000..fc78788 --- /dev/null +++ b/app/src/main/java/hu/bbara/purefin/common/ui/components/MediaProgressBar.kt @@ -0,0 +1,47 @@ +package hu.bbara.purefin.common.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +/** + * A progress bar component for displaying media playback progress. + * + * @param progress The progress value between 0f and 1f, where 0f is no progress and 1f is complete. + * @param foregroundColor The color of the progress indicator. + * @param backgroundColor The color of the background/unfilled portion of the progress bar. + * @param modifier The modifier to be applied to the Box. Modifier should contain the Alignment. + */ +@Composable +fun MediaProgressBar( + progress: Float, + foregroundColor: Color = MaterialTheme.colorScheme.onSurface, + backgroundColor: Color = MaterialTheme.colorScheme.primary, + modifier: Modifier +) { + Box( + modifier = modifier + .padding(bottom = 8.dp, start = 8.dp, end = 8.dp) + .clip(RoundedCornerShape(24.dp)) + .fillMaxWidth() + .height(4.dp) + .background(backgroundColor.copy(alpha = 0.2f)) + ) { + Box( + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth(progress) + .background(foregroundColor) + ) + } +} \ No newline at end of file