From 93d96d7bb187130c0a6fd8210e2466af8c3f4b01 Mon Sep 17 00:00:00 2001 From: Jos Vooges | STH Date: Wed, 16 Sep 2026 01:10:37 +0200 Subject: [PATCH] Fix TV controls nav after scrub; bump Play release to TV 0.14.49 and mobile 1.0.22. --- apps/android-tv/app-mobile/build.gradle.kts | 4 +- apps/android-tv/app/build.gradle.kts | 4 +- .../vonas/mediacluster/tv/ui/PlayerScreen.kt | 65 +++++++++++++------ 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/apps/android-tv/app-mobile/build.gradle.kts b/apps/android-tv/app-mobile/build.gradle.kts index c236a10..442c17b 100644 --- a/apps/android-tv/app-mobile/build.gradle.kts +++ b/apps/android-tv/app-mobile/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "nl.vonas.mediacluster" minSdk = 24 targetSdk = 36 - versionCode = 22 - versionName = "1.0.21" + versionCode = 23 + versionName = "1.0.22" buildConfigField("String", "DEFAULT_API_BASE", "\"https://master.vonas.nl\"") ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") diff --git a/apps/android-tv/app/build.gradle.kts b/apps/android-tv/app/build.gradle.kts index 043b4a3..0917e67 100644 --- a/apps/android-tv/app/build.gradle.kts +++ b/apps/android-tv/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "nl.vonas.mediacluster.tv" minSdk = 24 targetSdk = 36 - versionCode = 110 - versionName = "0.14.47" + versionCode = 112 + versionName = "0.14.49" buildConfigField("String", "DEFAULT_API_BASE", "\"https://master.vonas.nl\"") ndk { abiFilters += listOf("arm64-v8a", "armeabi-v7a") diff --git a/apps/android-tv/app/src/main/java/nl/vonas/mediacluster/tv/ui/PlayerScreen.kt b/apps/android-tv/app/src/main/java/nl/vonas/mediacluster/tv/ui/PlayerScreen.kt index 59a3a1d..6e09b96 100644 --- a/apps/android-tv/app/src/main/java/nl/vonas/mediacluster/tv/ui/PlayerScreen.kt +++ b/apps/android-tv/app/src/main/java/nl/vonas/mediacluster/tv/ui/PlayerScreen.kt @@ -422,10 +422,14 @@ fun PlayerScreen( } LaunchedEffect(controls, menu, controlsNavMode) { - delay(40) + delay(60) if (menu != null) return@LaunchedEffect when { - controls && controlsNavMode -> runCatching { controlsFocus.requestFocus() } + controls && controlsNavMode -> { + // Even wachten tot knoppen gecomposeerd zijn. + delay(40) + runCatching { controlsFocus.requestFocus() } + } else -> runCatching { catcherFocus.requestFocus() } } } @@ -475,13 +479,15 @@ fun PlayerScreen( true } Key.DirectionLeft -> { - // Altijd scrubben (ook mét controls zichtbaar) — nooit door knoppen navigeren. if (menu != null) return@onPreviewKeyEvent false + // In knoppenmodus: laat focus tussen knoppen bewegen. + if (controls && controlsNavMode) return@onPreviewKeyEvent false scrubBy(-10_000) true } Key.DirectionRight -> { if (menu != null) return@onPreviewKeyEvent false + if (controls && controlsNavMode) return@onPreviewKeyEvent false scrubBy(10_000) true } @@ -501,12 +507,20 @@ fun PlayerScreen( } Key.DirectionUp, Key.Menu -> { if (menu != null) return@onPreviewKeyEvent false - if (controls && controlsNavMode) { - controlsNavMode = false - true - } else { - showControls(navMode = false) - true + when { + controls && controlsNavMode -> { + // Terug naar scrub-modus; ←/→ seeken weer. + controlsNavMode = false + true + } + controls -> { + hideControls() + true + } + else -> { + showControls(navMode = false) + true + } } } else -> false @@ -683,13 +697,16 @@ fun PlayerScreen( } Row( - Modifier - .fillMaxWidth() - .focusRequester(controlsFocus), + Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically, ) { - NetflixIconButton(if (playing) "❚❚" else "▶", primary = true) { togglePlay() } + NetflixIconButton( + label = if (playing) "❚❚" else "▶", + primary = true, + focusRequester = controlsFocus, + onClick = { togglePlay() }, + ) NetflixIconButton("−10") { scrubBy(-10_000) } @@ -709,13 +726,15 @@ fun PlayerScreen( showControls(navMode = true) } } - if (!controlsNavMode && scrubHint == null) { - Text( - "← → spoelen · ↓ knoppen · OK pauze", - color = Color(0x88FFFFFF), - fontSize = 12.sp, - ) - } + Text( + if (controlsNavMode) { + "← → knoppen · ↑ terug naar spoelen · OK kiezen" + } else { + "← → spoelen · ↓ knoppen (audio/ondertitel) · OK pauze" + }, + color = Color(0x88FFFFFF), + fontSize = 12.sp, + ) } } } @@ -877,10 +896,16 @@ private fun langLabel(code: String): String { private fun NetflixIconButton( label: String, primary: Boolean = false, + focusRequester: FocusRequester? = null, onClick: () -> Unit, ) { Surface( onClick = onClick, + modifier = if (focusRequester != null) { + Modifier.focusRequester(focusRequester) + } else { + Modifier + }, shape = ClickableSurfaceDefaults.shape(shape = CircleShape), scale = ClickableSurfaceDefaults.scale(focusedScale = 1.12f), border = ClickableSurfaceDefaults.border(