Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
844ea928ef | ||
|
|
95f8793938 |
@@ -12,8 +12,8 @@ android {
|
|||||||
applicationId = "dev.castarr.tv"
|
applicationId = "dev.castarr.tv"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 19
|
versionCode = 21
|
||||||
versionName = "0.8.3"
|
versionName = "0.8.5"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release signing from environment (see ~/.keys/castarr-release.env on the
|
// Release signing from environment (see ~/.keys/castarr-release.env on the
|
||||||
|
|||||||
@@ -337,24 +337,18 @@ private fun ChannelRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Channel logo in a small tile; initials while loading or without a logo. */
|
/** Bare channel logo (they ship transparent); initials as fallback. */
|
||||||
@Composable
|
@Composable
|
||||||
private fun LogoTile(channel: Channel) {
|
private fun LogoTile(channel: Channel) {
|
||||||
val initials = channel.name.split(" ").filter { it.isNotBlank() }
|
val initials = channel.name.split(" ").filter { it.isNotBlank() }
|
||||||
.take(2).map { it.first() }.joinToString("").uppercase()
|
.take(2).map { it.first() }.joinToString("").uppercase()
|
||||||
Box(
|
Box(Modifier.size(width = 52.dp, height = 40.dp), contentAlignment = Alignment.Center) {
|
||||||
Modifier
|
|
||||||
.size(38.dp)
|
|
||||||
.clip(RoundedCornerShape(8.dp))
|
|
||||||
.background(CastarrColors.surfaceFocused),
|
|
||||||
contentAlignment = Alignment.Center,
|
|
||||||
) {
|
|
||||||
if (channel.logo.isNotEmpty()) {
|
if (channel.logo.isNotEmpty()) {
|
||||||
SubcomposeAsyncImage(
|
SubcomposeAsyncImage(
|
||||||
model = channel.logo,
|
model = channel.logo,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
contentScale = ContentScale.Fit,
|
contentScale = ContentScale.Fit,
|
||||||
modifier = Modifier.fillMaxSize().padding(5.dp),
|
modifier = Modifier.fillMaxSize(),
|
||||||
loading = { LogoInitials(initials) },
|
loading = { LogoInitials(initials) },
|
||||||
error = { LogoInitials(initials) },
|
error = { LogoInitials(initials) },
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import androidx.compose.ui.focus.FocusRequester
|
|||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Path
|
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.Key
|
||||||
import androidx.compose.ui.input.key.KeyEventType
|
import androidx.compose.ui.input.key.KeyEventType
|
||||||
import androidx.compose.ui.input.key.key
|
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.input.key.type
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
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.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 =
|
private fun formatClock(millis: Long): String =
|
||||||
SimpleDateFormat("HH:mm", Locale.GERMANY).format(Date(millis))
|
SimpleDateFormat("HH:mm", Locale.GERMANY).format(Date(millis))
|
||||||
|
|
||||||
@@ -146,7 +154,8 @@ private fun Overlay(state: AppState) {
|
|||||||
.padding(top = 22.dp, end = 30.dp),
|
.padding(top = 22.dp, end = 30.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
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))
|
Spacer(Modifier.width(8.dp))
|
||||||
Box(
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
@@ -178,18 +187,38 @@ private fun Overlay(state: AppState) {
|
|||||||
statusWord,
|
statusWord,
|
||||||
color = CastarrColors.muted,
|
color = CastarrColors.muted,
|
||||||
fontFamily = AppFont,
|
fontFamily = AppFont,
|
||||||
|
style = OverlayText,
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.height(4.dp))
|
Spacer(Modifier.height(4.dp))
|
||||||
}
|
}
|
||||||
Text(
|
Row(verticalAlignment = Alignment.Bottom) {
|
||||||
state.currentChannel?.name.orEmpty(),
|
// Channel number inline before the name (matches the list
|
||||||
color = CastarrColors.fg,
|
// and the number-pad zapping).
|
||||||
fontFamily = AppFont,
|
val number = state.currentChannel?.let { current ->
|
||||||
fontSize = 30.sp,
|
state.activeChannels().indexOfFirst { it.url == current.url } + 1
|
||||||
fontWeight = FontWeight.Medium,
|
} ?: 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 info = state.currentChannel?.let { state.nowNext(it) }
|
||||||
val now = info?.now?.takeUnless { isEpgPlaceholder(it.title) }
|
val now = info?.now?.takeUnless { isEpgPlaceholder(it.title) }
|
||||||
@@ -200,6 +229,7 @@ private fun Overlay(state: AppState) {
|
|||||||
now.title,
|
now.title,
|
||||||
color = CastarrColors.fg,
|
color = CastarrColors.fg,
|
||||||
fontFamily = AppFont,
|
fontFamily = AppFont,
|
||||||
|
style = OverlayText,
|
||||||
fontSize = 18.sp,
|
fontSize = 18.sp,
|
||||||
)
|
)
|
||||||
Spacer(Modifier.width(14.dp))
|
Spacer(Modifier.width(14.dp))
|
||||||
@@ -207,6 +237,7 @@ private fun Overlay(state: AppState) {
|
|||||||
"${formatClock(now.start)} – ${formatClock(now.stop)}",
|
"${formatClock(now.start)} – ${formatClock(now.stop)}",
|
||||||
color = CastarrColors.muted,
|
color = CastarrColors.muted,
|
||||||
fontFamily = AppFont,
|
fontFamily = AppFont,
|
||||||
|
style = OverlayText,
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -219,6 +250,7 @@ private fun Overlay(state: AppState) {
|
|||||||
"Danach: ${next.title} (${formatClock(next.start)})",
|
"Danach: ${next.title} (${formatClock(next.start)})",
|
||||||
color = CastarrColors.faint,
|
color = CastarrColors.faint,
|
||||||
fontFamily = AppFont,
|
fontFamily = AppFont,
|
||||||
|
style = OverlayText,
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -267,6 +299,7 @@ private fun Overlay(state: AppState) {
|
|||||||
"▲ ▼ Sender wechseln",
|
"▲ ▼ Sender wechseln",
|
||||||
color = CastarrColors.faint,
|
color = CastarrColors.faint,
|
||||||
fontFamily = AppFont,
|
fontFamily = AppFont,
|
||||||
|
style = OverlayText,
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -346,6 +379,7 @@ private fun PillButton(
|
|||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
fontFamily = AppFont,
|
fontFamily = AppFont,
|
||||||
|
style = OverlayText,
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Medium,
|
||||||
modifier = Modifier.padding(horizontal = 18.dp, vertical = 9.dp),
|
modifier = Modifier.padding(horizontal = 18.dp, vertical = 9.dp),
|
||||||
|
|||||||
Reference in New Issue
Block a user