fix(android): Erkunden (Apple) overlay back no longer jumps to Home
The iTunes artist / album detail in the Erkunden tab are in-screen overlays on the NavHost "erkunden" destination, not real routes. Their BackHandler lost back priority to the NavHost, so one back press popped Erkunden → Home instead of dismissing the overlay (artist→search, album→artist). Handle the overlay's back at the app root via OnBackPressedCallback (the same proven mechanism as the NowPlaying overlay): ExploreScreen reports its current overlay close action up through onOverlayBackChange, and AppNavigation registers a root-level back callback for it. Also covers an album opened straight from search (no artist), which had no back handling at all. Removes the temporary nav-debug strip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
b07212fdce
commit
e50b4dc93c
2 files changed
+38
-20
No files matched your search
@@ -96,6 +96,10 @@ fun AppNavigation() {
|
|||||||
var showNotifications by remember { mutableStateOf(false) }
|
var showNotifications by remember { mutableStateOf(false) }
|
||||||
var selectedAbsItem by remember { mutableStateOf<AbsLibraryItem?>(null) }
|
var selectedAbsItem by remember { mutableStateOf<AbsLibraryItem?>(null) }
|
||||||
var showAbsPlayer by remember { mutableStateOf(false) }
|
var showAbsPlayer by remember { mutableStateOf(false) }
|
||||||
|
// Close action for the Erkunden (Apple) in-screen overlay (iTunes artist / album). Handled at the
|
||||||
|
// app root because a BackHandler inside the NavHost "erkunden" destination loses back priority to
|
||||||
|
// the NavHost, which pops Erkunden → Home instead of dismissing the overlay.
|
||||||
|
var exploreOverlayBack by remember { mutableStateOf<(() -> Unit)?>(null) }
|
||||||
|
|
||||||
val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
|
val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
|
||||||
DisposableEffect(showNowPlaying, backDispatcher) {
|
DisposableEffect(showNowPlaying, backDispatcher) {
|
||||||
@@ -122,6 +126,15 @@ fun AppNavigation() {
|
|||||||
backDispatcher.addCallback(cb)
|
backDispatcher.addCallback(cb)
|
||||||
onDispose { cb.remove() }
|
onDispose { cb.remove() }
|
||||||
}
|
}
|
||||||
|
DisposableEffect(exploreOverlayBack, backDispatcher) {
|
||||||
|
val action = exploreOverlayBack
|
||||||
|
if (action == null || backDispatcher == null) return@DisposableEffect onDispose {}
|
||||||
|
val cb = object : OnBackPressedCallback(true) {
|
||||||
|
override fun handleOnBackPressed() { action() }
|
||||||
|
}
|
||||||
|
backDispatcher.addCallback(cb)
|
||||||
|
onDispose { cb.remove() }
|
||||||
|
}
|
||||||
|
|
||||||
fun coverUrl(coverId: String?) = repo.coverArtUrl(coverId, 600)
|
fun coverUrl(coverId: String?) = repo.coverArtUrl(coverId, 600)
|
||||||
fun heroCoverUrl(coverId: String?) = repo.coverArtUrl(coverId, 1000)
|
fun heroCoverUrl(coverId: String?) = repo.coverArtUrl(coverId, 1000)
|
||||||
@@ -275,6 +288,7 @@ fun AppNavigation() {
|
|||||||
onAlbumClick = { album -> navController.navigate("album/${album.id}") },
|
onAlbumClick = { album -> navController.navigate("album/${album.id}") },
|
||||||
onArtistClick = { artist -> navController.navigate("artist/${artist.id}") },
|
onArtistClick = { artist -> navController.navigate("artist/${artist.id}") },
|
||||||
onShowContextMenu = ::showContextMenu,
|
onShowContextMenu = ::showContextMenu,
|
||||||
|
onOverlayBackChange = { exploreOverlayBack = it },
|
||||||
onOpenImporter = { navController.navigate("importer") },
|
onOpenImporter = { navController.navigate("importer") },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -395,21 +409,6 @@ fun AppNavigation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── TEMP NAV DEBUG — zeigt den Back-Stack; wird nach der Diagnose entfernt ──
|
|
||||||
val dbgBackStack by navController.currentBackStack.collectAsStateWithLifecycle()
|
|
||||||
Box(Modifier.fillMaxWidth().statusBarsPadding(), contentAlignment = androidx.compose.ui.Alignment.TopCenter) {
|
|
||||||
Text(
|
|
||||||
"🧭 " + dbgBackStack.mapNotNull { it.destination.route?.substringBefore("/") }
|
|
||||||
.filter { it != "null" }.joinToString(" › "),
|
|
||||||
color = Color(0xFFFFEB3B),
|
|
||||||
fontSize = 9.sp,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
modifier = Modifier
|
|
||||||
.background(Color(0xCC000000))
|
|
||||||
.padding(horizontal = 6.dp, vertical = 2.dp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NowPlaying overlay
|
// NowPlaying overlay
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = showNowPlaying,
|
visible = showNowPlaying,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.novasonic.app.ui.screen
|
package com.novasonic.app.ui.screen
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
@@ -50,6 +49,7 @@ fun ExploreScreen(
|
|||||||
onAlbumClick: (com.novasonic.app.api.model.Album) -> Unit,
|
onAlbumClick: (com.novasonic.app.api.model.Album) -> Unit,
|
||||||
onArtistClick: (com.novasonic.app.api.model.Artist) -> Unit,
|
onArtistClick: (com.novasonic.app.api.model.Artist) -> Unit,
|
||||||
onShowContextMenu: ((com.novasonic.app.api.model.Song) -> Unit)? = null,
|
onShowContextMenu: ((com.novasonic.app.api.model.Song) -> Unit)? = null,
|
||||||
|
onOverlayBackChange: ((() -> Unit)?) -> Unit = {},
|
||||||
onOpenImporter: () -> Unit = {},
|
onOpenImporter: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val vm: ExploreViewModel = viewModel()
|
val vm: ExploreViewModel = viewModel()
|
||||||
@@ -57,10 +57,29 @@ fun ExploreScreen(
|
|||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
// BackHandlers for state-based navigation (must be unconditional)
|
// Overlay back is handled at the app root (see AppNavigation.exploreOverlayBack): a BackHandler
|
||||||
BackHandler(enabled = state.artistDetail != null && state.partialAlbum != null) { vm.dismissPartialAlbum() }
|
// inside this NavHost destination loses back priority to the NavHost, which pops Erkunden → Home.
|
||||||
BackHandler(enabled = state.artistDetail != null && state.albumTracks != null && state.partialAlbum == null) { vm.dismissAlbum() }
|
// Report the current overlay's close action up; clear it when this screen leaves composition
|
||||||
BackHandler(enabled = state.artistDetail != null && state.albumTracks == null && state.partialAlbum == null) { vm.closeArtistDetail() }
|
// (e.g. drilling into a real album route) so that screen's own back works normally.
|
||||||
|
val overlayKind = when {
|
||||||
|
state.artistDetail != null && state.partialAlbum != null -> 4 // artist → partial album
|
||||||
|
state.artistDetail != null && state.albumTracks != null -> 3 // artist → iTunes album
|
||||||
|
state.artistDetail != null -> 2 // iTunes artist
|
||||||
|
state.albumTracks != null -> 1 // album straight from search
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
DisposableEffect(overlayKind) {
|
||||||
|
onOverlayBackChange(
|
||||||
|
when (overlayKind) {
|
||||||
|
4 -> vm::dismissPartialAlbum
|
||||||
|
3 -> vm::dismissAlbum
|
||||||
|
2 -> vm::closeArtistDetail
|
||||||
|
1 -> vm::dismissAlbum
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
onDispose { onOverlayBackChange(null) }
|
||||||
|
}
|
||||||
|
|
||||||
// Download sheet
|
// Download sheet
|
||||||
state.downloadSheetItem?.let { item ->
|
state.downloadSheetItem?.let { item ->
|
||||||
|
|||||||
Reference in new issue
Block a user