fix(android): back focus lost after tabbing out — re-assert overlay back callbacks on resume
With NowPlaying (or an ABS player) open, backgrounding and resuming the app made the next back press pop the NavHost invisibly to Home before dismissing the overlay. Returning from the background re-registers the NavController's own OnBackPressedCallback on top of the dispatcher, stealing back-priority from the overlays. AppNavigation now bumps a resumeTick on Lifecycle.Event.ON_RESUME and keys every overlay DisposableEffect (NowPlaying, ABS player, ABS item, Erkunden overlay) on resumeTick + currentBackEntry, so each overlay re-adds its callback above the NavController after a resume or navigation. Needs on-device verification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
17bb527e1d
commit
e69fbaf75e
3 files changed
+21
-5
No files matched your search
@@ -23,6 +23,8 @@ import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.LifecycleEventEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.*
|
||||
import androidx.navigation.compose.*
|
||||
@@ -112,7 +114,15 @@ fun AppNavigation() {
|
||||
var exploreOverlayBack by remember { mutableStateOf<(() -> Unit)?>(null) }
|
||||
|
||||
val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
|
||||
DisposableEffect(showNowPlaying, backDispatcher) {
|
||||
val currentBackEntry by navController.currentBackStackEntryAsState()
|
||||
// Returning from the background re-registers the NavController's OWN back callback on top of the
|
||||
// dispatcher, which stole back-priority from the NowPlaying/ABS overlays: pressing back then popped
|
||||
// the NavHost (invisibly, all the way to Home) before dismissing the overlay. Bump this tick on
|
||||
// ON_RESUME (and re-key on navigation) so the overlay callbacks below re-add above it again.
|
||||
var resumeTick by remember { mutableIntStateOf(0) }
|
||||
LifecycleEventEffect(Lifecycle.Event.ON_RESUME) { resumeTick++ }
|
||||
|
||||
DisposableEffect(showNowPlaying, backDispatcher, currentBackEntry, resumeTick) {
|
||||
if (!showNowPlaying || backDispatcher == null) return@DisposableEffect onDispose {}
|
||||
val cb = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() { showNowPlaying = false }
|
||||
@@ -120,7 +130,7 @@ fun AppNavigation() {
|
||||
backDispatcher.addCallback(cb)
|
||||
onDispose { cb.remove() }
|
||||
}
|
||||
DisposableEffect(showAbsPlayer, backDispatcher) {
|
||||
DisposableEffect(showAbsPlayer, backDispatcher, currentBackEntry, resumeTick) {
|
||||
if (!showAbsPlayer || backDispatcher == null) return@DisposableEffect onDispose {}
|
||||
val cb = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() { showAbsPlayer = false }
|
||||
@@ -128,7 +138,7 @@ fun AppNavigation() {
|
||||
backDispatcher.addCallback(cb)
|
||||
onDispose { cb.remove() }
|
||||
}
|
||||
DisposableEffect(selectedAbsItem, backDispatcher) {
|
||||
DisposableEffect(selectedAbsItem, backDispatcher, currentBackEntry, resumeTick) {
|
||||
if (selectedAbsItem == null || backDispatcher == null) return@DisposableEffect onDispose {}
|
||||
val cb = object : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() { selectedAbsItem = null }
|
||||
@@ -148,7 +158,6 @@ fun AppNavigation() {
|
||||
|
||||
var homeRefreshKey by remember { mutableIntStateOf(0) }
|
||||
|
||||
val currentBackEntry by navController.currentBackStackEntryAsState()
|
||||
val currentRoute = currentBackEntry?.destination?.route
|
||||
val isTopLevel = TopLevel.entries.any { it.route == currentRoute }
|
||||
|
||||
@@ -156,7 +165,7 @@ fun AppNavigation() {
|
||||
// callback is re-added (bumped to the top of the OnBackPressedDispatcher) after every navigation
|
||||
// — otherwise, once the NavHost re-registers its own callback during an album drill-down or tab
|
||||
// switch, it could regain priority and pop Erkunden → Home on the next back ("sometimes" bug).
|
||||
DisposableEffect(exploreOverlayBack, backDispatcher, currentBackEntry) {
|
||||
DisposableEffect(exploreOverlayBack, backDispatcher, currentBackEntry, resumeTick) {
|
||||
val action = exploreOverlayBack
|
||||
if (action == null || backDispatcher == null) return@DisposableEffect onDispose {}
|
||||
val cb = object : OnBackPressedCallback(true) {
|
||||
|
||||
Reference in new issue
Block a user