-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to open a ModalBottomSheet with the previous route behind #72
Comments
Is there a reason why this needs to be a route? Can you show how you are currently handling this (with androidx-navigation-compose) IMO, modals (like dialogs or modal bottom sheets) typically do not need to be routes as they are not part of the navigation graph. But, I can be convinced otherwise if there's a valid use case for it to be considered as a route |
Hello @xxfast We have here some BottomSheet and dialogs that are part of the flow and treat them today as part of the navigation as they could be open from different places, we could just open it as a normal dialog, but the idea was to treat some of these these BottomSheet as self-contained and give them the same attention we give to screens With NavigationCompose this is doable today as we can create a BottomSheet as part of the routes As we can have some BottomSheet dialogs as complex as we need or as simple as we need, and let the navigation be there, if in the future this needs to be a screen instead of a dialog, we can just go there and change the implementation, as the navigation is already being made as route navigation, this way the navigation route is abstracted from the implementation detail of what each route is, as one route should not care about the details of another |
Here a simple example setContent {
MyApplicationTheme {
// A surface container using the 'background' color from the theme
val bottomSheetNavigator = rememberBottomSheetNavigator()
val navHost = rememberNavController(bottomSheetNavigator)
val sheetState = bottomSheetNavigator.navigatorSheetState
val current = LocalContext.current
ModalBottomSheetLayout(
bottomSheetNavigator = bottomSheetNavigator
) {
NavHost(
navController = navHost,
startDestination = "home",
) {
composable("home") {
Home { dest ->
navHost.navigate(dest)
}
}
composable("greetins/{id}") {
GreetingComposable(text = it.arguments?.getString("id").orEmpty())
}
bottomSheet(route = "sheet") {
OnDismissAction(sheetState) {
Toast.makeText(current, "sheet", Toast.LENGTH_LONG).show()
}
Text("This is a cool bottom sheet!")
}
bottomSheet(route = "sheet2") {
OnDismissAction(sheetState) {
Toast.makeText(current, "sheet2", Toast.LENGTH_LONG).show()
}
Text("This is the other sheet")
}
}
}
}
} |
Hi, @GabriellCosta Thank you for the detailed explanation of your use case. Is this from accompanist's navigation-material? The equivalent API from decompose to support this use case would be child slots, which requires some breaking API changes to accommodate on the router API side. I think this is a good use case that warrants such a breaking API change - so I'm definitely up for it. Just a few more questions for me to fully wrap my head around the requirement In my production app, we have a modal bottom sheet that looks like this pscore.mp4The way this is currently implemented looks something like this @Composable
fun TasksRootScreen() {
val router: Router<TasksRootScreens> = rememberRouter(TasksRootScreens::class) { listOf(TasksRootScreens.Home) }
RoutedContent(router = router) { screen ->
when (screen) {
is Home -> TasksHomeScreen(..)
is IncidentDetails -> IncidentDetailsScreen()
}
}
} the filter bottom sheet is implemented within @Composable
fun TasksHomeScreen() {
val sheetState: ModalBottomSheetState =
rememberModalBottomSheetState(Hidden, skipHalfExpanded = true)
ModalBottomSheetLayout(
sheetState = sheetState,
sheetContent = {
TasksFilterScreen(
onClosed = { coroutineScope.launch { sheetState.hide() } },
)
},
) { .. }
} If I understand this correctly, in your case you want this bottom sheet to exist outside of the main screen? Something like fun TasksRootScreen() {
val router: Router<TasksRootScreens> = rememberRouter(TasksRootScreens::class) { listOf(TasksRootScreens.Home) }
RoutedContent(router = router) { screen ->
when (screen) {
is Home -> TasksHomeScreen(..)
is FIlter -> TasksHomeFilterScreen(..)
is IncidentDetails -> IncidentDetailsScreen()
}
}
} |
Hello @xxfast, sorry for the delay Yes, something like that would be great As I understand our RoutedContent would need to support |
I would place those bottoms sheets as a nested navigation, e.g. inside the Home screen. Placing everything at the top level doesn't look scalable, e.g. there could be 100s of bottom sheets in an app. Perhaps, Decompose-Router could add a separate API for this kind of navigation, i.e. Slot or Overlay where the hosting Composable is still visible. I think this could be done even without breaking the existing API. |
Hi @GabriellCosta. With latest Here's how you would use router for slots @Serialisable object ShowBottomSheet
@Composable
fun SlotScreen() {
val router: Router<ShowBottomSheet> = rememberRouter(ShowBottomSheet::class, initialConfiguration = { null })
// An example button to open the bottom sheet
Button(
onClick = { router.activate(ShowBottomSheet) },
) {
Text("Show Bottom Sheet")
}
RoutedContent(router) { screen ->
ModalBottomSheet(
onDismissRequest = { router.dismiss() },
) {
// sheet content
}
}
} As @arkivanov pointed out, you will need to handle these as nested navigation modals and you won't be able to handle everything at the top level. Let me know if this can address your usecase |
@GabriellCosta If you want to handle everything at the root level - here's how I would handle your case mentioned here, and I don't think you'd need a slot for that @Serialisable sealed class Screen {
data object Home
data class Greetings(val id: String)
data object Sheet
}
val router: Router<Screen> = rememberRouter(initialStack = { listOf(Home) }
RoutedContent(router = router) { screen ->
when(screen){
Home -> HomeScreen(onGreeting = { id -> router.push(Greetings(id)) })
is Greetings -> GreetingScreen(screen.id)
Sheet -> SheetScreen(onDismiss = { router.pop() })
}
}
@Composable
fun SheetScreen(onDismiss: () -> Unit) {
ModalBottomSheet(
onDismissRequest = onDismiss,
) {
// sheet content
}
} I believe the sheet should be rendered over the previous screen. Let me know if this works |
Hello @xxfast thanks for letting me know, I will try it here and add a feedback, thanks : D |
Feel free to comment on this issue with any feedback. Going to close this issue for now |
I would like to start a
ModalBottomSheet
(android) as part of my navigation routes (some action would trigger and start a specific ModalBottomSheet) and that one would be treated as a route to be used, similar to what I would do in Compose NavigationWhat I did was start the route normally and that works, the problem is that the screen behind the BottomSheet is blank, as my previous screen is in the stack
How Can I present a ModalBottomSheet as an overlay over other screens?
obs: I was not able to put the
Question
label in this issueThe text was updated successfully, but these errors were encountered: