From 844ea928efd12eaf2d15537362860c119592025d Mon Sep 17 00:00:00 2001 From: be-nj Date: Wed, 26 Aug 2026 01:27:50 +0200 Subject: [PATCH] Channel number in the player overlay (inline before the name) Co-Authored-By: Claude Fable 5 --- app/build.gradle.kts | 4 +- .../java/dev/castarr/tv/ui/PlayerScreen.kt | 50 ++++++++++++++++--- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7d094e6..3b56334 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -12,8 +12,8 @@ android { applicationId = "dev.castarr.tv" minSdk = 26 targetSdk = 35 - versionCode = 20 - versionName = "0.8.4" + versionCode = 21 + versionName = "0.8.5" } // Release signing from environment (see ~/.keys/castarr-release.env on the diff --git a/app/src/main/java/dev/castarr/tv/ui/PlayerScreen.kt b/app/src/main/java/dev/castarr/tv/ui/PlayerScreen.kt index 22e7b37..32069d7 100644 --- a/app/src/main/java/dev/castarr/tv/ui/PlayerScreen.kt +++ b/app/src/main/java/dev/castarr/tv/ui/PlayerScreen.kt @@ -28,7 +28,9 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Path +import androidx.compose.ui.graphics.Shadow import androidx.compose.ui.input.key.Key import androidx.compose.ui.input.key.KeyEventType import androidx.compose.ui.input.key.key @@ -37,6 +39,7 @@ import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.input.key.type import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -98,6 +101,11 @@ fun PlayerScreen(state: AppState) { } } +/** Soft drop shadow so overlay text stays readable on bright video. */ +private val OverlayText = TextStyle( + shadow = Shadow(Color(0xB3000000), Offset(0f, 2f), blurRadius = 8f), +) + private fun formatClock(millis: Long): String = SimpleDateFormat("HH:mm", Locale.GERMANY).format(Date(millis)) @@ -146,7 +154,8 @@ private fun Overlay(state: AppState) { .padding(top = 22.dp, end = 30.dp), verticalAlignment = Alignment.CenterVertically, ) { - Text(name, color = CastarrColors.muted, fontFamily = AppFont, fontSize = 12.sp) + Text(name, color = CastarrColors.muted, fontFamily = AppFont, + style = OverlayText, fontSize = 12.sp) Spacer(Modifier.width(8.dp)) Box( Modifier @@ -178,18 +187,38 @@ private fun Overlay(state: AppState) { statusWord, color = CastarrColors.muted, fontFamily = AppFont, + style = OverlayText, fontSize = 12.sp, ) } Spacer(Modifier.height(4.dp)) } - Text( - state.currentChannel?.name.orEmpty(), - color = CastarrColors.fg, - fontFamily = AppFont, - fontSize = 30.sp, - fontWeight = FontWeight.Medium, - ) + Row(verticalAlignment = Alignment.Bottom) { + // Channel number inline before the name (matches the list + // and the number-pad zapping). + val number = state.currentChannel?.let { current -> + state.activeChannels().indexOfFirst { it.url == current.url } + 1 + } ?: 0 + if (number > 0) { + Text( + "$number", + color = CastarrColors.accent, + fontFamily = AppFont, + style = OverlayText, + fontSize = 30.sp, + fontWeight = FontWeight.SemiBold, + ) + Spacer(Modifier.width(14.dp)) + } + Text( + state.currentChannel?.name.orEmpty(), + color = CastarrColors.fg, + fontFamily = AppFont, + style = OverlayText, + fontSize = 30.sp, + fontWeight = FontWeight.Medium, + ) + } val info = state.currentChannel?.let { state.nowNext(it) } val now = info?.now?.takeUnless { isEpgPlaceholder(it.title) } @@ -200,6 +229,7 @@ private fun Overlay(state: AppState) { now.title, color = CastarrColors.fg, fontFamily = AppFont, + style = OverlayText, fontSize = 18.sp, ) Spacer(Modifier.width(14.dp)) @@ -207,6 +237,7 @@ private fun Overlay(state: AppState) { "${formatClock(now.start)} – ${formatClock(now.stop)}", color = CastarrColors.muted, fontFamily = AppFont, + style = OverlayText, fontSize = 14.sp, ) } @@ -219,6 +250,7 @@ private fun Overlay(state: AppState) { "Danach: ${next.title} (${formatClock(next.start)})", color = CastarrColors.faint, fontFamily = AppFont, + style = OverlayText, fontSize = 14.sp, ) } @@ -267,6 +299,7 @@ private fun Overlay(state: AppState) { "▲ ▼ Sender wechseln", color = CastarrColors.faint, fontFamily = AppFont, + style = OverlayText, fontSize = 12.sp, ) } @@ -346,6 +379,7 @@ private fun PillButton( Text( label, fontFamily = AppFont, + style = OverlayText, fontSize = 14.sp, fontWeight = FontWeight.Medium, modifier = Modifier.padding(horizontal = 18.dp, vertical = 9.dp),