What's the best way to show a Snackbar on a multi-module, single activity, Compose only project?
This is how the project dependency graph looks like:
The only activity of the project is inside the app
module and it just sets the NavHost
as content.
Each feature
module provides a list of composable screens that will be shown on the NavHost
.
Each screen has its own Scaffold
, so it can easily show Snackbars from the each screen's ViewModel
.
There is a special feature
module, feature-debug
, that shows on a single screen, a list of composable provided by each feature
module, that are called debug sections. It is used to allow any feature
module to show automatically some settings inside the debug screen.
Each debug section has its own ViewModel
so it works exactly like a Screen. But it's missing a Scaffold, since it only takes a portion of the screen:
+-------------------------+
| Debug screen |
|-------------------------+
| |
| Feature A debug section |
| |
|------------------------ +
| |
| Feature B debug section |
| |
|------------------------ +
| |
| Feature C debug section |
| |
|------------------------ +
| |
| Feature D debug section |
| |
+------------------------ +
So I'm not sure how can I show a Snackbar on the Scaffold of the feature-debug
screen, from a composable that is declared inside another feature
module that has no visibility of the any class inside feature-debug
.
CompositionLocal
can be used to pass data through the composition tree implicitly.
The first thing to do is to declare a variable that must be visible by provider and consumers (in my case, I created it inside the core-ui
module):
val LocalSnackbarHostState = compositionLocalOf<SnackbarHostState> { error("No SnackbarHostState provided") }
Then the provider should wrap its children with a CompositionLocalProvider
:
val scaffoldState = rememberScaffoldState()
CompositionLocalProvider(
LocalSnackbarHostState provides scaffoldState.snackbarHostState
) {
Scaffold(
[...]
And finally the children can grab an instance of the SnackbarHostState
accessing the variable LocalSnackbarHostState
:
val snackbarHostState = LocalSnackbarHostState.current