From c2802818656fffd625ea277eeb9fd06bad7e2480 Mon Sep 17 00:00:00 2001 From: Jeremy Woods Date: Wed, 20 Dec 2023 19:40:53 +0000 Subject: [PATCH] Ensure Navigation Material properly handles back for nested nav If there is a nested NavGraph under the current bottomSheet destination and you do a back press, instead of the bottomSheet which is the topmost destination being popped, the nested NavHost underneath will be popped instead. This is caused by bottomSheet not properly intercepting back presses. This change added a BackHandler to ensure that bottomsheets correctly respect the system back hierarchy for back events. Fixes: #1726 --- .../BottomSheetNavigatorTest.kt | 65 +++++++++++++++++++ .../material/BottomSheetNavigator.kt | 5 ++ 2 files changed, 70 insertions(+) diff --git a/navigation-material/src/androidTest/java/com/google/accompanist/navigation.material/BottomSheetNavigatorTest.kt b/navigation-material/src/androidTest/java/com/google/accompanist/navigation.material/BottomSheetNavigatorTest.kt index 915d4f392..7bad7972a 100644 --- a/navigation-material/src/androidTest/java/com/google/accompanist/navigation.material/BottomSheetNavigatorTest.kt +++ b/navigation-material/src/androidTest/java/com/google/accompanist/navigation.material/BottomSheetNavigatorTest.kt @@ -779,6 +779,71 @@ internal class BottomSheetNavigatorTest { .isEqualTo(firstSheetDestination) } + @Test + fun testBackPressWithNestedGraphBehind() { + lateinit var navigator: BottomSheetNavigator + lateinit var navController: NavHostController + lateinit var nestedNavController: NavHostController + lateinit var backDispatcher: OnBackPressedDispatcher + val homeDestination = "home" + val firstSheetDestination = "sheet1" + val firstNestedDestination = "nested1" + val secondNestedDestination = "nested2" + + composeTestRule.setContent { + backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher!! + navigator = rememberBottomSheetNavigator() + navController = rememberNavController(navigator) + ModalBottomSheetLayout(navigator) { + NavHost(navController, homeDestination) { + composable(homeDestination) { + nestedNavController = rememberNavController() + NavHost(nestedNavController, "nested1") { + composable(firstNestedDestination) { } + composable(secondNestedDestination) { } + } + } + bottomSheet(firstSheetDestination) { + Text("SheetDestination") + } + } + } + } + + assertThat(navController.currentBackStackEntry?.destination?.route) + .isEqualTo(homeDestination) + + composeTestRule.runOnUiThread { + nestedNavController.navigate(secondNestedDestination) + } + composeTestRule.waitForIdle() + + assertThat(navController.currentBackStackEntry?.destination?.route) + .isEqualTo(homeDestination) + assertThat(nestedNavController.currentBackStackEntry?.destination?.route) + .isEqualTo(secondNestedDestination) + + composeTestRule.runOnUiThread { + navController.navigate(firstSheetDestination) + } + composeTestRule.waitForIdle() + + assertThat(navigator.sheetState.currentValue) + .isAnyOf(ModalBottomSheetValue.HalfExpanded, ModalBottomSheetValue.Expanded) + + composeTestRule.runOnUiThread { + backDispatcher.onBackPressed() + } + composeTestRule.waitForIdle() + + assertThat(navController.currentBackStackEntry?.destination?.route) + .isEqualTo(homeDestination) + assertThat(nestedNavController.currentBackStackEntry?.destination?.route) + .isEqualTo(secondNestedDestination) + + assertThat(navigator.sheetState.currentValue).isEqualTo(ModalBottomSheetValue.Hidden) + } + private fun BottomSheetNavigator.createFakeDestination() = BottomSheetNavigator.Destination(this) { Text("Fake Sheet Content") diff --git a/navigation-material/src/main/java/com/google/accompanist/navigation/material/BottomSheetNavigator.kt b/navigation-material/src/main/java/com/google/accompanist/navigation/material/BottomSheetNavigator.kt index 932fc07c5..d514747d9 100644 --- a/navigation-material/src/main/java/com/google/accompanist/navigation/material/BottomSheetNavigator.kt +++ b/navigation-material/src/main/java/com/google/accompanist/navigation/material/BottomSheetNavigator.kt @@ -17,6 +17,7 @@ package com.google.accompanist.navigation.material import android.annotation.SuppressLint +import androidx.activity.compose.BackHandler import androidx.compose.animation.core.AnimationSpec import androidx.compose.foundation.layout.ColumnScope import androidx.compose.material.ExperimentalMaterialApi @@ -212,6 +213,10 @@ class BottomSheetNavigator( LaunchedEffect(retainedEntry) { sheetState.show() } + + BackHandler { + state.popWithTransition(popUpTo = retainedEntry!!, saveState = false) + } } SheetContentHost(