Tighten detail action buttons for readability on backdrops.
Use compact solid buttons and a quieter back control so labels stay clear over hero art. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
6c96b0ca01
commit
57280ef470
2 changed files with 96 additions and 15 deletions
|
|
@ -12,8 +12,8 @@ android {
|
|||
applicationId = "nl.vonas.mediacluster.tv"
|
||||
minSdk = 24
|
||||
targetSdk = 35
|
||||
versionCode = 16
|
||||
versionName = "0.7.9"
|
||||
versionCode = 17
|
||||
versionName = "0.8.0"
|
||||
buildConfigField("String", "DEFAULT_API_BASE", "\"https://master.vonas.nl\"")
|
||||
ndk {
|
||||
abiFilters += listOf("arm64-v8a", "armeabi-v7a")
|
||||
|
|
|
|||
|
|
@ -45,15 +45,16 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.tv.material3.Border
|
||||
import androidx.tv.material3.ClickableSurfaceDefaults
|
||||
import androidx.tv.material3.ExperimentalTvMaterial3Api
|
||||
import androidx.tv.material3.Glow
|
||||
import androidx.tv.material3.Surface
|
||||
import androidx.tv.material3.Text
|
||||
import coil.compose.AsyncImage
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import nl.vonas.mediacluster.tv.data.ApiClient
|
||||
import nl.vonas.mediacluster.tv.ui.components.McButton
|
||||
import nl.vonas.mediacluster.tv.ui.theme.McColors
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
|
@ -198,6 +199,86 @@ private fun MetaChips(parts: List<String>) {
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTvMaterial3Api::class)
|
||||
@Composable
|
||||
private fun DetailBackButton(onClick: () -> Unit) {
|
||||
Surface(
|
||||
onClick = onClick,
|
||||
shape = ClickableSurfaceDefaults.shape(shape = RoundedCornerShape(4.dp)),
|
||||
scale = ClickableSurfaceDefaults.scale(focusedScale = 1.05f),
|
||||
glow = ClickableSurfaceDefaults.glow(focusedGlow = Glow(elevationColor = Color.Transparent, elevation = 0.dp)),
|
||||
colors = ClickableSurfaceDefaults.colors(
|
||||
containerColor = Color.Transparent,
|
||||
focusedContainerColor = Color(0x33FFFFFF),
|
||||
contentColor = Color(0xFFCFCFCF),
|
||||
focusedContentColor = Color.White,
|
||||
),
|
||||
border = ClickableSurfaceDefaults.border(
|
||||
focusedBorder = Border(
|
||||
border = androidx.compose.foundation.BorderStroke(1.dp, Color.White),
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
),
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
"Terug",
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
|
||||
color = Color.Unspecified,
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Medium,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTvMaterial3Api::class)
|
||||
@Composable
|
||||
private fun DetailActionButton(
|
||||
label: String,
|
||||
primary: Boolean = false,
|
||||
focusRequester: FocusRequester? = null,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val bg = if (primary) Color.White else Color(0xE6181818)
|
||||
val bgFocus = if (primary) Color(0xFFE8E8E8) else Color.White
|
||||
val fg = if (primary) Color.Black else Color.White
|
||||
Surface(
|
||||
onClick = onClick,
|
||||
modifier = if (focusRequester != null) Modifier.focusRequester(focusRequester) else Modifier,
|
||||
shape = ClickableSurfaceDefaults.shape(shape = RoundedCornerShape(4.dp)),
|
||||
scale = ClickableSurfaceDefaults.scale(focusedScale = 1.05f),
|
||||
glow = ClickableSurfaceDefaults.glow(focusedGlow = Glow(elevationColor = Color.Transparent, elevation = 0.dp)),
|
||||
colors = ClickableSurfaceDefaults.colors(
|
||||
containerColor = bg,
|
||||
focusedContainerColor = bgFocus,
|
||||
contentColor = fg,
|
||||
focusedContentColor = Color.Black,
|
||||
),
|
||||
border = if (primary) {
|
||||
ClickableSurfaceDefaults.border()
|
||||
} else {
|
||||
ClickableSurfaceDefaults.border(
|
||||
border = Border(
|
||||
border = androidx.compose.foundation.BorderStroke(1.dp, Color(0x55FFFFFF)),
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
),
|
||||
focusedBorder = Border(
|
||||
border = androidx.compose.foundation.BorderStroke(1.dp, Color.White),
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
),
|
||||
)
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = label,
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
color = Color.Unspecified,
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalTvMaterial3Api::class)
|
||||
@Composable
|
||||
fun MovieDetailScreen(
|
||||
|
|
@ -286,7 +367,7 @@ fun MovieDetailScreen(
|
|||
.padding(start = 44.dp, end = 20.dp, top = 28.dp, bottom = 28.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
McButton("← Terug", onClick = onBack)
|
||||
DetailBackButton(onClick = onBack)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
DetailLogoOrTitle(logoUrl, title)
|
||||
MetaChips(metaParts)
|
||||
|
|
@ -320,18 +401,18 @@ fun MovieDetailScreen(
|
|||
}
|
||||
if (error != null) Text(error!!, color = McColors.Danger)
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
files.firstOrNull()?.let { (id, _) ->
|
||||
McButton("▶ Afspelen", primary = true, focusRequester = playFocus) {
|
||||
DetailActionButton("Afspelen", primary = true, focusRequester = playFocus) {
|
||||
onPlay(id, title, 0)
|
||||
}
|
||||
}
|
||||
if (!trailerKey.isNullOrBlank()) {
|
||||
McButton("Trailer") {
|
||||
DetailActionButton("Trailer") {
|
||||
openYoutubeTrailer(context, trailerKey!!)
|
||||
}
|
||||
}
|
||||
McButton("Als gekeken") {
|
||||
DetailActionButton("Als gekeken") {
|
||||
scope.launch {
|
||||
runCatching { api.markWatched(movieId = movieId) }
|
||||
onBack()
|
||||
|
|
@ -341,9 +422,9 @@ fun MovieDetailScreen(
|
|||
if (files.size > 1) {
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Text("Versies", color = Color.White, fontSize = 15.sp, fontWeight = FontWeight.SemiBold)
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
items(files) { (id, label) ->
|
||||
McButton(label.take(42), primary = id == files.first().first) {
|
||||
DetailActionButton(label.take(36), primary = id == files.first().first) {
|
||||
onPlay(id, title, 0)
|
||||
}
|
||||
}
|
||||
|
|
@ -458,7 +539,7 @@ fun SeriesDetailScreen(
|
|||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
item {
|
||||
McButton("← Terug", onClick = onBack)
|
||||
DetailBackButton(onClick = onBack)
|
||||
Spacer(Modifier.height(10.dp))
|
||||
DetailLogoOrTitle(logoUrl, title)
|
||||
MetaChips(metaParts)
|
||||
|
|
@ -475,14 +556,14 @@ fun SeriesDetailScreen(
|
|||
}
|
||||
if (error != null) Text(error!!, color = McColors.Danger)
|
||||
Spacer(Modifier.height(6.dp))
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
episodes.firstOrNull()?.let { ep ->
|
||||
McButton("▶ Afspelen", primary = true, focusRequester = firstEpFocus) {
|
||||
DetailActionButton("Afspelen", primary = true, focusRequester = firstEpFocus) {
|
||||
onPlay(ep.fileId, ep.id, "$title · S${ep.season}E${ep.number}")
|
||||
}
|
||||
}
|
||||
if (!trailerKey.isNullOrBlank()) {
|
||||
McButton("Trailer") { openYoutubeTrailer(context, trailerKey!!) }
|
||||
DetailActionButton("Trailer") { openYoutubeTrailer(context, trailerKey!!) }
|
||||
}
|
||||
}
|
||||
if (seasons.size > 1) {
|
||||
|
|
@ -492,7 +573,7 @@ fun SeriesDetailScreen(
|
|||
LazyRow(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
items(seasons) { s ->
|
||||
val n = s.optInt("seasonNumber")
|
||||
McButton(
|
||||
DetailActionButton(
|
||||
"Seizoen $n",
|
||||
primary = n == selectedSeason,
|
||||
) { selectedSeason = n }
|
||||
|
|
|
|||
Loading…
Reference in a new issue