Skip to content

Instantly share code, notes, and snippets.

class ScopedBackPressHandler(
// nullable, because root level doesn’t have one
var backStack: BackStack<*>? = null
) {
// remainder the same
}
class Entry<T>(val element: T) {
val children: MutableMap<Any, BackStack<*>> = mutableMapOf()
}
A [back stack of 1 element]
└── B [back stack of 1 element]
└── C [back stack of 1 element]
└── D [back stack of 1 element]
A [back stack of 2 elements]
└── X [...]
└── Y [...]
└── Z [...]
A [back stack of 1 element]
└── B [back stack of 2 elements]
└── C [back stack of 4 elements]
└── D [back stack of 1 element]
class MainActivity : AppCompatActivity() {
private val rootHandler = ScopedBackPressHandler()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
RootBackHandler(rootHandler) {
Root.Content(LoggedOut)
}
@Composable
fun RootBackHandler(rootHandler: ScopedBackPressHandler, children: @Composable() () -> Unit) {
val downstream = +memo { ScopedBackPressHandler() }
val handleBackPressHere: () -> Boolean = { downstream.handle() }
rootHandler.handlers.add(handleBackPressHere)
+onDispose { rootHandler.handlers.remove(handleBackPressHere) }
backPressHandler.Provider(value = downstream) {
children()
}
@Composable
fun Content() {
BackHandler(Routing.AlbumList as Routing) { backStack ->
when (val currentRouting = backStack.last()) {
// all Content() on the right hand side are @Composable
is Routing.AlbumList -> AlbumList.Content()
is Routing.PhotosOfAlbum -> PhotosOfAlbum.Content(currentRouting.album)
is Routing.FullScreenPhoto -> FullScreenPhoto.Content(currentRouting..photo)
}
val handleBackPressHere: () -> Boolean = { downstream.handle() || backStack.pop() }
@Composable
fun <T> BackHandler(routing: T, children: @Composable() (BackStack<T>) -> Unit) {
// grab the parent handler, wherever it's up the tree
val upstream = +ambient(backPressHandler)
// to keep track of children down the tree
val downstream = +memo { ScopedBackPressHandler() }
// let's have a default back stack on this level
val backStack = BackStack(routing)
// our lambda for handling back press: asking all children,
val handleBackPressHere: () -> Boolean = { downstream.handle() || backStack.pop() }