
(?)
(?)
(i dont have apple's devices) Some time in the future WASM/JS and maybe WASI.
What?
Router style navigation library with Decompose used as a base with some features on top, like view model store, overlays, custom extensions like animations, etc.
Why?
There was existing multiplatform tooling, but it was kinda raw for my taste, so I started learning and experimenting by making DSLs based on it and this is the result.
... What was the thought process?
Uhm...
Here's what it has and can do
- Convenient type-safe router-style navigation
- Custom animation system (inspired by Decompose)
- Properly store view models, with configuration change handling, view model scope cancellation and allat
- Convenient view model instance creation
- Display destinations in overlays
- Pass the backstack entry's component context using CompositionLocalProvider
- Pass the type (contained/overlay) of the displayed content also using CompositionLocalProvider
- Store navigation controller instances like view models
- Automatically create navigation controller instances upon the creation of nav hosts that are retrievable by just calling navController, again, kind of like view models
Examples/Getting Started
In your version catalog add the "com.github.nxoim.decomposite:decomposite" artifact. In your toml file that would be:
decomposite = { module = "com.github.nxoim.decomposite:decomposite", version.ref = "version" }
First you have to set up the app by creating a root of the app. This root sets up stores for view models and nav controllers, overlay stuff, and provides the root component context.
On Android:
class YourActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val navigationRootData = NavigationRootData(defaultComponentContext())
setContent {
NavigationRootProvider(navigationRootData) { YourContent() }
}
}
}
Check out the android sample if you want predictive gesture animations application-wide and on older androids.
On everything else:
val navigationRootData = NavigationRootData()
NavigationRootProvider(navigationRootData) { YourContent() }
Navigation host creation:
val yourNavController = navController<YourDestinations>(startingDestination = YourDestinations.Star)
Scaffold(
bottomBar = {
GlobalSampleNavBar(onBack = { yourNavController.navigateBack() })
}
) { scaffoldPadding ->
NavHost(
yourNavController,
Modifier.padding(scaffoldPadding),
animations = {
when (currentChild) {
RootDestinations.Star -> fade() + scale()
else -> cleanSlideAndFade()
}
}
) {
when (it) {
RootDestinations.Star -> StarNavHost()
RootDestinations.Heart -> HeartNavHost()
}
}
}
Navigation controller usage:
yourNavController.navigate(YourDestinations.Heart)
yourNavController.navigateBack()
View model creation and usage:
@Composable
fun {
vm = viewModel() { SomeViewModel(someArgument = ) }
vm = getExistingViewModel<SomeViewModel>()
}
(someArgument: String) : ViewModel() {
{
viewModelScope.coroutineContext.cancelChildren()
}
}
Back gestures on other platforms:
Or you can apply a modifier to the content you want to handle the back gestures, like:
ExampleComposable(Modifier.backGestureProvider(LocalBackDispatcher.current))