From 45fd1b963e441013bafa78652736c5fba7af7b1e Mon Sep 17 00:00:00 2001 From: Jeena Date: Fri, 16 Oct 2026 13:03:28 +0000 Subject: [PATCH] channels: never open the screen without a selection (#32) Coming back from a channel page hands that channel's card the focus, but the handle only wins when the card is still in the rows. A channel that was renamed, unsubscribed, or simply never carried in the rows left every row asking for no focus at all, so opening Channels from the drawer put the remote nowhere: "when I click on Channels, none is selected, it should behave like video cards" (#32 review). The fallback row is now chosen by whether the handle exists anywhere in the rows, and a row whose wanted card never became focusable takes its first card instead of staying unselected. --- .../jeena/jtubetv/ui/screens/ChannelsScreen.kt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/jeena/jtubetv/ui/screens/ChannelsScreen.kt b/app/src/main/java/net/jeena/jtubetv/ui/screens/ChannelsScreen.kt index 57d4fa3..4207968 100644 --- a/app/src/main/java/net/jeena/jtubetv/ui/screens/ChannelsScreen.kt +++ b/app/src/main/java/net/jeena/jtubetv/ui/screens/ChannelsScreen.kt @@ -358,6 +358,14 @@ fun ChannelsScreen( // as stats stream in the rows re-sort, and re-focusing their first card // would steal focus mid-navigation (user: "up jumps to the first row"). val focusHandedOut = remember { mutableStateOf(false) } + // The channel we came back from only wins the focus while it is still + // in the rows. When it isn't (renamed, unsubscribed, or the rows simply + // never carried it) every row used to ask for no focus at all — "when I + // click on Channels, none is selected" (#32 review). Fall back to the + // first row in that case, like the video cards do. + val focusRowExists = focusHandle != null && viewModel.userRows.any { + group -> group.channels.any { it.name + "@" + it.host == focusHandle } + } LazyColumn(Modifier.fillMaxSize()) { viewModel.userRows.forEach { group -> item(key = "hdr-" + group.ownerName) { @@ -379,7 +387,7 @@ fun ChannelsScreen( onOpenDrawer, drawerPulse = drawerPulse, focused = !focusHandedOut.value && ( - if (focusHandle != null) isTargetRow + if (focusRowExists) isTargetRow else group == viewModel.userRows.firstOrNull() ), focusIndex = if (isTargetRow) target else 0, @@ -479,6 +487,11 @@ private fun ChannelRow( return@LaunchedEffect } } + // The wanted card never became focusable (its row scrolled past it, + // or the handle went stale): take the first card instead, so the + // screen is never left with nothing selected (#32 review). + val first = focusRequesters[0] + if (first != null && runCatching { first.requestFocus() }.isSuccess) onFocused() } } }