From a3105925bbf761454d878a743db2004a1fa0dd0c Mon Sep 17 00:00:00 2001 From: be-nj Date: Wed, 26 Aug 2026 03:07:12 +0200 Subject: [PATCH] Make a waiting update visible instead of hiding it in the settings The start-up check already ran, but its result only showed as a badge for whoever happened to open the settings. A chip in the top bar now says "Update " and leads straight there, and the check repeats every six hours because a TV keeps the same process alive for days. Co-Authored-By: Claude Fable 5 --- app/build.gradle.kts | 4 +-- .../main/java/dev/castarr/tv/MainActivity.kt | 10 +++++- .../main/java/dev/castarr/tv/ui/CastarrApp.kt | 31 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bf23e27..82e5bdb 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 = 28 - versionName = "0.10.2" + versionCode = 29 + versionName = "0.10.3" } // Release signing from environment (see ~/.keys/castarr-release.env on the diff --git a/app/src/main/java/dev/castarr/tv/MainActivity.kt b/app/src/main/java/dev/castarr/tv/MainActivity.kt index 2270cf2..f090a16 100644 --- a/app/src/main/java/dev/castarr/tv/MainActivity.kt +++ b/app/src/main/java/dev/castarr/tv/MainActivity.kt @@ -50,7 +50,14 @@ class MainActivity : ComponentActivity(), ControlServer.Listener { server.startServer() state.remoteAvailable = server.running setContent { CastarrApp(state) } - lifecycleScope.launch { UpdateChecker.check(state) } + lifecycleScope.launch { + // At start-up and then occasionally: a TV often keeps the same + // app process alive for days. + while (true) { + UpdateChecker.check(state) + delay(UPDATE_CHECK_INTERVAL_MS) + } + } } private fun onPlaybackChanged() { @@ -325,5 +332,6 @@ class MainActivity : ComponentActivity(), ControlServer.Listener { const val TICK_INTERVAL_MS = 2_000L const val SEEK_STEP_SECONDS = 10L const val DIGIT_COMMIT_MS = 1_800L + const val UPDATE_CHECK_INTERVAL_MS = 6 * 60 * 60 * 1000L } } diff --git a/app/src/main/java/dev/castarr/tv/ui/CastarrApp.kt b/app/src/main/java/dev/castarr/tv/ui/CastarrApp.kt index 1eb59a2..f4e069c 100644 --- a/app/src/main/java/dev/castarr/tv/ui/CastarrApp.kt +++ b/app/src/main/java/dev/castarr/tv/ui/CastarrApp.kt @@ -132,6 +132,10 @@ private fun TopBar(state: AppState) { } Spacer(Modifier.width(18.dp)) } + state.updateAvailable?.let { version -> + UpdateChip(version) { state.screen = AppState.Screen.SETTINGS } + Spacer(Modifier.width(10.dp)) + } GearButton { state.screen = if (state.screen == AppState.Screen.LIVE) AppState.Screen.SETTINGS else AppState.Screen.LIVE @@ -139,6 +143,33 @@ private fun TopBar(state: AppState) { } } +/** + * Shown in the top bar as soon as the start-up check finds a newer + * release — otherwise an update would only be noticed by someone who + * happens to open the settings. + */ +@Composable +private fun UpdateChip(version: String, onClick: () -> Unit) { + Surface( + onClick = onClick, + shape = ClickableSurfaceDefaults.shape(RoundedCornerShape(999.dp)), + colors = ClickableSurfaceDefaults.colors( + containerColor = CastarrColors.accentDim, + contentColor = CastarrColors.accent, + focusedContainerColor = CastarrColors.accent, + focusedContentColor = CastarrColors.onAccent, + ), + ) { + Text( + "Update $version", + fontFamily = AppFont, + fontSize = 13.sp, + fontWeight = FontWeight.Medium, + modifier = Modifier.padding(horizontal = 14.dp, vertical = 8.dp), + ) + } +} + /** Round settings button with a drawn gear (glyphs render as emoji). */ @Composable private fun GearButton(onClick: () -> Unit) {