Fix Events crash: bind FocusRequester before TopNav down to hub rail.
This commit is contained in:
parent
1f072b7d09
commit
244a8c97ed
2 changed files with 32 additions and 8 deletions
|
|
@ -20,8 +20,8 @@ android {
|
||||||
applicationId = "nl.vonas.mediacluster.tv"
|
applicationId = "nl.vonas.mediacluster.tv"
|
||||||
minSdk = 24
|
minSdk = 24
|
||||||
targetSdk = 36
|
targetSdk = 36
|
||||||
versionCode = 144
|
versionCode = 145
|
||||||
versionName = "0.14.81"
|
versionName = "0.14.82"
|
||||||
buildConfigField("String", "DEFAULT_API_BASE", "\"https://master.vonas.nl\"")
|
buildConfigField("String", "DEFAULT_API_BASE", "\"https://master.vonas.nl\"")
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters += listOf("arm64-v8a", "armeabi-v7a")
|
abiFilters += listOf("arm64-v8a", "armeabi-v7a")
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ fun EventsScreen(
|
||||||
var providerFilter by remember { mutableStateOf<String?>(null) }
|
var providerFilter by remember { mutableStateOf<String?>(null) }
|
||||||
var nowMs by remember { mutableLongStateOf(System.currentTimeMillis()) }
|
var nowMs by remember { mutableLongStateOf(System.currentTimeMillis()) }
|
||||||
var filterBarFocusReady by remember { mutableStateOf(false) }
|
var filterBarFocusReady by remember { mutableStateOf(false) }
|
||||||
|
var hubRailFocusReady by remember { mutableStateOf(false) }
|
||||||
/** Owner-id van first-rail FocusRequester — voorkomt dispose-race live↔upcoming. */
|
/** Owner-id van first-rail FocusRequester — voorkomt dispose-race live↔upcoming. */
|
||||||
var railFocusOwner by remember { mutableStateOf<String?>(null) }
|
var railFocusOwner by remember { mutableStateOf<String?>(null) }
|
||||||
val railFocusReady = railFocusOwner != null
|
val railFocusReady = railFocusOwner != null
|
||||||
|
|
@ -141,6 +142,7 @@ fun EventsScreen(
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
val firstRailFocus = remember { FocusRequester() }
|
val firstRailFocus = remember { FocusRequester() }
|
||||||
val restoreCardFocus = remember { FocusRequester() }
|
val restoreCardFocus = remember { FocusRequester() }
|
||||||
|
val hubRailFocus = remember { FocusRequester() }
|
||||||
|
|
||||||
suspend fun refresh() {
|
suspend fun refresh() {
|
||||||
runCatching { api.listScheduleEvents() }
|
runCatching { api.listScheduleEvents() }
|
||||||
|
|
@ -253,7 +255,7 @@ fun EventsScreen(
|
||||||
val filterBarFocus = remember { FocusRequester() }
|
val filterBarFocus = remember { FocusRequester() }
|
||||||
val firstRailUpTarget = when {
|
val firstRailUpTarget = when {
|
||||||
showFilterBar && filterBarFocusReady -> filterBarFocus
|
showFilterBar && filterBarFocusReady -> filterBarFocus
|
||||||
hasHubRail -> contentFocusRequester
|
hasHubRail && hubRailFocusReady -> hubRailFocus
|
||||||
else -> navFocusRequester
|
else -> navFocusRequester
|
||||||
}
|
}
|
||||||
val filterFocusDown: FocusRequester? = when {
|
val filterFocusDown: FocusRequester? = when {
|
||||||
|
|
@ -342,19 +344,24 @@ fun EventsScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
val entryReady = when {
|
val entryReady = when {
|
||||||
hasHubRail -> true
|
hasHubRail -> hubRailFocusReady
|
||||||
showFilterBar -> filterBarFocusReady
|
showFilterBar -> filterBarFocusReady
|
||||||
else -> railFocusReady
|
else -> railFocusReady
|
||||||
}
|
}
|
||||||
val needContentSink = when {
|
val needContentSink = when {
|
||||||
loading && events.isEmpty() -> true
|
loading && events.isEmpty() -> true
|
||||||
error != null && events.isEmpty() -> true
|
error != null && events.isEmpty() -> true
|
||||||
hasHubRail -> false
|
// contentFocusRequester mag nooit "los" staan (TopNav.down → crash)
|
||||||
|
hasHubRail -> !hubRailFocusReady
|
||||||
showFilterBar -> !filterBarFocusReady
|
showFilterBar -> !filterBarFocusReady
|
||||||
!hasRails -> true
|
!hasRails -> true
|
||||||
else -> !railFocusReady
|
else -> !railFocusReady
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(hasHubRail) {
|
||||||
|
if (!hasHubRail) hubRailFocusReady = false
|
||||||
|
}
|
||||||
|
|
||||||
// Detail → back: card restore; fallback = chips of eerste rail.
|
// Detail → back: card restore; fallback = chips of eerste rail.
|
||||||
LaunchedEffect(
|
LaunchedEffect(
|
||||||
pendingFocusRestore,
|
pendingFocusRestore,
|
||||||
|
|
@ -374,7 +381,7 @@ fun EventsScreen(
|
||||||
if (restoredSuccessfully) return
|
if (restoredSuccessfully) return
|
||||||
val entryOk = awaitReady({
|
val entryOk = awaitReady({
|
||||||
when {
|
when {
|
||||||
hasHubRail -> true
|
hasHubRail -> hubRailFocusReady
|
||||||
showFilterBar -> filterBarFocusReady
|
showFilterBar -> filterBarFocusReady
|
||||||
else -> railFocusReady
|
else -> railFocusReady
|
||||||
}
|
}
|
||||||
|
|
@ -499,12 +506,17 @@ fun EventsScreen(
|
||||||
) {
|
) {
|
||||||
if (hasHubRail) {
|
if (hasHubRail) {
|
||||||
item(key = "hub_rail") {
|
item(key = "hub_rail") {
|
||||||
|
// Zolang TopNav-sink contentFocusRequester vasthoudt → hubRailFocus op tile.
|
||||||
|
// Zodra ready → contentFocusRequester op eerste tile.
|
||||||
|
val hubEntryFocus =
|
||||||
|
if (hubRailFocusReady) contentFocusRequester else hubRailFocus
|
||||||
EventsHubRail(
|
EventsHubRail(
|
||||||
hubs = hubs,
|
hubs = hubs,
|
||||||
focusRequester = contentFocusRequester,
|
focusRequester = hubEntryFocus,
|
||||||
focusUp = navFocusRequester,
|
focusUp = navFocusRequester,
|
||||||
onOpenF1 = onOpenF1Hub,
|
onOpenF1 = onOpenF1Hub,
|
||||||
onOpenViaplay = onOpenViaplayHub,
|
onOpenViaplay = onOpenViaplayHub,
|
||||||
|
onFocusReady = { hubRailFocusReady = it },
|
||||||
onFocus = onContentFocused,
|
onFocus = onContentFocused,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -523,7 +535,11 @@ fun EventsScreen(
|
||||||
liveCount = live.size,
|
liveCount = live.size,
|
||||||
totalCount = filtered.size,
|
totalCount = filtered.size,
|
||||||
firstFocusRequester = if (hasHubRail) filterBarFocus else contentFocusRequester,
|
firstFocusRequester = if (hasHubRail) filterBarFocus else contentFocusRequester,
|
||||||
focusUp = if (hasHubRail) contentFocusRequester else navFocusRequester,
|
focusUp = when {
|
||||||
|
hasHubRail && hubRailFocusReady -> contentFocusRequester
|
||||||
|
hasHubRail -> null
|
||||||
|
else -> navFocusRequester
|
||||||
|
},
|
||||||
focusDown = filterFocusDown,
|
focusDown = filterFocusDown,
|
||||||
onFocusReady = { filterBarFocusReady = it },
|
onFocusReady = { filterBarFocusReady = it },
|
||||||
onFocus = onContentFocused,
|
onFocus = onContentFocused,
|
||||||
|
|
@ -1108,6 +1124,7 @@ private fun EventsHubRail(
|
||||||
focusUp: FocusRequester?,
|
focusUp: FocusRequester?,
|
||||||
onOpenF1: (() -> Unit)?,
|
onOpenF1: (() -> Unit)?,
|
||||||
onOpenViaplay: (() -> Unit)?,
|
onOpenViaplay: (() -> Unit)?,
|
||||||
|
onFocusReady: ((Boolean) -> Unit)? = null,
|
||||||
onFocus: () -> Unit,
|
onFocus: () -> Unit,
|
||||||
) {
|
) {
|
||||||
LazyRow(
|
LazyRow(
|
||||||
|
|
@ -1140,6 +1157,7 @@ private fun EventsHubRail(
|
||||||
accent = accent,
|
accent = accent,
|
||||||
focusRequester = if (index == 0) focusRequester else null,
|
focusRequester = if (index == 0) focusRequester else null,
|
||||||
focusUp = focusUp,
|
focusUp = focusUp,
|
||||||
|
onFocusReady = if (index == 0) onFocusReady else null,
|
||||||
onOpen = onOpen,
|
onOpen = onOpen,
|
||||||
onFocus = onFocus,
|
onFocus = onFocus,
|
||||||
)
|
)
|
||||||
|
|
@ -1156,9 +1174,15 @@ private fun HubRailTile(
|
||||||
accent: Color,
|
accent: Color,
|
||||||
focusRequester: FocusRequester?,
|
focusRequester: FocusRequester?,
|
||||||
focusUp: FocusRequester?,
|
focusUp: FocusRequester?,
|
||||||
|
onFocusReady: ((Boolean) -> Unit)? = null,
|
||||||
onOpen: () -> Unit,
|
onOpen: () -> Unit,
|
||||||
onFocus: () -> Unit,
|
onFocus: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
// Ready = eerste tile is in composition (niet gekoppeld aan welk FocusRequester-object)
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
onFocusReady?.invoke(true)
|
||||||
|
onDispose { onFocusReady?.invoke(false) }
|
||||||
|
}
|
||||||
var focused by remember { mutableStateOf(false) }
|
var focused by remember { mutableStateOf(false) }
|
||||||
Surface(
|
Surface(
|
||||||
onClick = onOpen,
|
onClick = onOpen,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue