mirror of
https://github.com/bbara04/Purefin.git
synced 2026-07-24 03:36:51 +00:00
Remove status and progress overlays from TV hero section
Removes eyebrow text, watched status chips, and progress bars from the focused hero component on the TV home screen. The underlying model and UI are simplified to display only the title and basic metadata.
This commit is contained in:
@@ -16,12 +16,8 @@ import kotlin.math.roundToInt
|
||||
internal data class TvFocusedHeroModel(
|
||||
val id: UUID,
|
||||
val backdropImageUrl: String,
|
||||
val eyebrowText: String,
|
||||
val title: String,
|
||||
val metadata: List<String>,
|
||||
val watchedText: String?,
|
||||
val progressFraction: Float?,
|
||||
val progressLabel: String?,
|
||||
) {
|
||||
val metadataText: String?
|
||||
get() = metadata.takeIf { it.isNotEmpty() }?.joinToString(" • ")
|
||||
@@ -30,16 +26,16 @@ internal data class TvFocusedHeroModel(
|
||||
internal fun FocusableItem.toTvFocusedHeroModel(): TvFocusedHeroModel {
|
||||
return when (this) {
|
||||
is ContinueWatchingItem -> when (type) {
|
||||
BaseItemKind.MOVIE -> movie!!.toTvFocusedHeroModel(sourceLabel = "Continue watching")
|
||||
BaseItemKind.EPISODE -> episode!!.toTvFocusedHeroModel(sourceLabel = "Continue watching")
|
||||
BaseItemKind.MOVIE -> movie!!.toTvFocusedHeroModel()
|
||||
BaseItemKind.EPISODE -> episode!!.toTvFocusedHeroModel()
|
||||
else -> unsupportedType(type)
|
||||
}
|
||||
|
||||
is NextUpItem -> episode.toTvFocusedHeroModel(sourceLabel = "Next up")
|
||||
is NextUpItem -> episode.toTvFocusedHeroModel()
|
||||
is PosterItem -> when (type) {
|
||||
BaseItemKind.MOVIE -> movie!!.toTvFocusedHeroModel(sourceLabel = "Movie")
|
||||
BaseItemKind.EPISODE -> episode!!.toTvFocusedHeroModel(sourceLabel = "Episode")
|
||||
BaseItemKind.SERIES -> series!!.toTvFocusedHeroModel(sourceLabel = "Series")
|
||||
BaseItemKind.MOVIE -> movie!!.toTvFocusedHeroModel()
|
||||
BaseItemKind.EPISODE -> episode!!.toTvFocusedHeroModel()
|
||||
BaseItemKind.SERIES -> series!!.toTvFocusedHeroModel()
|
||||
else -> unsupportedType(type)
|
||||
}
|
||||
}
|
||||
@@ -50,32 +46,25 @@ internal fun backdropImageUrl(imageUrlPrefix: String?, fallbackImageUrl: String)
|
||||
return backdropImageUrl.ifBlank { fallbackImageUrl }
|
||||
}
|
||||
|
||||
private fun Movie.toTvFocusedHeroModel(sourceLabel: String): TvFocusedHeroModel {
|
||||
val progressFraction = progressFraction(progress)
|
||||
private fun Movie.toTvFocusedHeroModel(): TvFocusedHeroModel {
|
||||
return TvFocusedHeroModel(
|
||||
id = id,
|
||||
backdropImageUrl = backdropImageUrl(
|
||||
imageUrlPrefix = imageUrlPrefix,
|
||||
fallbackImageUrl = JellyfinImageHelper.finishImageUrl(imageUrlPrefix, ImageType.PRIMARY)
|
||||
),
|
||||
eyebrowText = sourceLabel,
|
||||
title = title,
|
||||
metadata = listOf(year, rating, runtime, format).compactMetadata(),
|
||||
watchedText = "Watched".takeIf { watched },
|
||||
progressFraction = progressFraction.takeIf { !watched && it != null },
|
||||
progressLabel = progressLabel(progressFraction).takeIf { !watched && progressFraction != null },
|
||||
)
|
||||
}
|
||||
|
||||
private fun Episode.toTvFocusedHeroModel(sourceLabel: String): TvFocusedHeroModel {
|
||||
val progressFraction = progressFraction(progress)
|
||||
private fun Episode.toTvFocusedHeroModel(): TvFocusedHeroModel {
|
||||
return TvFocusedHeroModel(
|
||||
id = id,
|
||||
backdropImageUrl = backdropImageUrl(
|
||||
imageUrlPrefix = imageUrlPrefix,
|
||||
fallbackImageUrl = JellyfinImageHelper.finishImageUrl(imageUrlPrefix, ImageType.PRIMARY)
|
||||
),
|
||||
eyebrowText = sourceLabel,
|
||||
title = title,
|
||||
metadata = listOf(
|
||||
"Episode $index",
|
||||
@@ -84,13 +73,10 @@ private fun Episode.toTvFocusedHeroModel(sourceLabel: String): TvFocusedHeroMode
|
||||
rating,
|
||||
format
|
||||
).compactMetadata(),
|
||||
watchedText = "Watched".takeIf { watched },
|
||||
progressFraction = progressFraction.takeIf { !watched && it != null },
|
||||
progressLabel = progressLabel(progressFraction).takeIf { !watched && progressFraction != null },
|
||||
)
|
||||
}
|
||||
|
||||
private fun Series.toTvFocusedHeroModel(sourceLabel: String): TvFocusedHeroModel {
|
||||
private fun Series.toTvFocusedHeroModel(): TvFocusedHeroModel {
|
||||
val unwatchedText = if (unwatchedEpisodeCount > 0) {
|
||||
"$unwatchedEpisodeCount unwatched"
|
||||
} else {
|
||||
@@ -103,12 +89,8 @@ private fun Series.toTvFocusedHeroModel(sourceLabel: String): TvFocusedHeroModel
|
||||
imageUrlPrefix = imageUrlPrefix,
|
||||
fallbackImageUrl = JellyfinImageHelper.finishImageUrl(imageUrlPrefix, ImageType.PRIMARY)
|
||||
),
|
||||
eyebrowText = sourceLabel,
|
||||
title = name,
|
||||
metadata = listOf(year, seasonLabel(seasonCount), unwatchedText).compactMetadata(),
|
||||
watchedText = null,
|
||||
progressFraction = null,
|
||||
progressLabel = null,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,39 +3,29 @@ package hu.bbara.purefin.tv.home.ui
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
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.graphics.Brush
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import hu.bbara.purefin.common.ui.components.MediaProgressBar
|
||||
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
|
||||
|
||||
internal const val TvHomeHeroTitleTag = "tv-home-hero-title"
|
||||
internal const val TvHomeHeroStatusTag = "tv-home-hero-status"
|
||||
internal const val TvHomeHeroProgressLabelTag = "tv-home-hero-progress-label"
|
||||
|
||||
private const val TvHomeHeroAnimationMillis = 180
|
||||
@@ -107,13 +97,6 @@ internal fun TvFocusedItemHero(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.widthIn(max = 720.dp)
|
||||
) {
|
||||
Text(
|
||||
text = hero.eyebrowText.uppercase(),
|
||||
color = scheme.primary,
|
||||
fontSize = 10.sp,
|
||||
letterSpacing = 1.2.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = hero.title,
|
||||
color = scheme.onBackground,
|
||||
@@ -134,54 +117,6 @@ internal fun TvFocusedItemHero(
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
if (hero.watchedText != null || hero.progressFraction != null) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(22.dp))
|
||||
.background(scheme.surfaceContainerHigh.copy(alpha = 0.92f))
|
||||
.border(1.dp, scheme.outlineVariant.copy(alpha = 0.6f), RoundedCornerShape(22.dp))
|
||||
.padding(horizontal = 12.dp, vertical = 10.dp)
|
||||
) {
|
||||
hero.watchedText?.let { watchedText ->
|
||||
TvHomeMetaChip(
|
||||
text = watchedText,
|
||||
highlighted = true,
|
||||
modifier = Modifier.testTag(TvHomeHeroStatusTag)
|
||||
)
|
||||
}
|
||||
if (hero.progressFraction != null && hero.progressLabel != null) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = Modifier.width(188.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Progress",
|
||||
color = scheme.onSurfaceVariant.copy(alpha = 0.85f),
|
||||
fontSize = 10.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
MediaProgressBar(
|
||||
progress = hero.progressFraction,
|
||||
foregroundColor = scheme.primary,
|
||||
backgroundColor = scheme.surfaceVariant,
|
||||
contentPadding = PaddingValues(0.dp),
|
||||
barHeight = 6.dp,
|
||||
modifier = Modifier
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = hero.progressLabel,
|
||||
color = scheme.onBackground,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
textAlign = TextAlign.End,
|
||||
modifier = Modifier.testTag(TvHomeHeroProgressLabelTag)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user