Restrict shell route and Back handling to the current entry

This commit is contained in:
justinzeus 2026-11-06 12:03:20 +01:00
parent afff383b75
commit 22850632ec
3 changed files with 18 additions and 5 deletions

View file

@ -105,9 +105,17 @@ class FirstSignInNavigationTest {
assertEquals(6, session.state!!.view.library!!.source.size)
assertFalse(session.state!!.person.hasAnime)
rule.onNodeWithText("Shows").performClick()
rule.waitUntil(10_000) {
Shadows.shadowOf(Looper.getMainLooper()).idle()
session.state!!.view.library?.source?.size == 29
try {
rule.waitUntil(10_000) {
Shadows.shadowOf(Looper.getMainLooper()).idle()
session.state!!.view.library?.source?.size == 29
}
} catch (timeout: ComposeTimeoutException) {
val shell = session.state!!
throw AssertionError("Active=${navigation.backStack.last()}, shell=${shell.route}, " +
"movies=${shell.rememberedView("movies").library?.source?.size}, " +
"shows=${shell.rememberedView("shows").library?.source?.size}/" +
"${shell.rememberedView("shows").library?.status}", timeout)
}
rule.onNodeWithTag("library-grid").assertIsDisplayed()
rule.onAllNodesWithText("Mindel Shows title 0")[0].assertIsDisplayed()

View file

@ -285,11 +285,14 @@ fun WolfskinApp(
is Destination.MediaItem -> if (destination.type == org.jellyfin.sdk.model.api.BaseItemKind.PERSON) personRoute(destination.itemId.toString()) else titleRoute(destination.itemId.toString())
else -> "pushed"
}
LaunchedEffect(destination, state) { if (!destination.fullScreen) state.enterDestination(route) }
val isCurrent = navigationManager.backStack.lastOrNull() == destination
LaunchedEffect(destination, state, isCurrent) {
if (isCurrent && !destination.fullScreen) state.enterDestination(route)
}
if (destination.fullScreen) {
DestinationContent(destination, preferences, viewModel::clearBackdrop, Modifier.fillMaxSize())
} else {
BackHandler { state.key(org.justinvisser.wolfskin.design.ShellKey.Back) }
BackHandler(enabled = isCurrent) { state.key(org.justinvisser.wolfskin.design.ShellKey.Back) }
val upstream = resolveUpstreamDestination(destination, WolfskinScreenPreference.enabled, viewModel.libraryDestinations)
if (upstream == null && (route.startsWith("title/") || route.startsWith("person/"))) {
val jellyfinIdentity = destination is Destination.MediaItem || android.net.Uri.decode(route.substringAfter('/')).toUUIDOrNull() != null

View file

@ -485,6 +485,8 @@ Cached `NavDisplay` entries read the current shell and Discover composition loca
not the temporary launch shell captured when the entry was first created. Otherwise
the screen can retain skeleton people, disconnected tab actions and an open picker
even after the real session is ready.
Only the current navigation entry may set the shared route or handle Back;
outgoing entries can remain composed during a transition.
Artwork uses a fresh bounded Wolfskin loader, not the upstream loader's
authenticated fetcher. The app's network interceptor removes Authorization from