Skip to content

Commit

Permalink
Ensure Navigation Material properly handles back for nested nav
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Jeremy Woods committed Dec 20, 2023
1 parent d1e3475 commit c280281
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -212,6 +213,10 @@ class BottomSheetNavigator(
LaunchedEffect(retainedEntry) {
sheetState.show()
}

BackHandler {
state.popWithTransition(popUpTo = retainedEntry!!, saveState = false)
}
}

SheetContentHost(
Expand Down

0 comments on commit c280281

Please sign in to comment.