I did something similar but instead of a multi-activity app, it was setup for a single activity app. Nevertheless, the concept is still the same for a multi-activity app.
For starters, I got rid of the snackbar that is provided by Compose. Like so many badly designed components from Google, I ditched it because it was tied to the scaffold. What the hell does a snackbar have to do with a scaffold? There are plenty of apps that don't use scaffolds but need snackbars. They would have been better off to created a general purpose snackbar that could be displayed from anywhere in your app and from any activity - if your app happens to use multiple activities.
So I wrote my own custom snackbar, which by the way is hardly even any code. To see this custom snackbar in action and how it is called from anywhere in the app, visit:
https://github.com/JohannBlake/Jetmagic
To test it in the demo, run the app and open the navigation drawer and click on any item. That will take you to a test screen. There is a button on the test screen that lets you return an item to the previous screen. Click on that and after selecting an item and pressing the Back button, you'll see the custom snackbar appear.
The one thing you can't avoid is a small amount of boilerplate code in each activity that is used to render the snackbar. Nothing in an activity is going to get composed if it isn't part of the UI hierarchy that makes up the activity. Here is the minimum boilerplate code I use and it is positioned below the scaffold:
Box {
Scaffold(
modifier = modifier,
drawerGesturesEnabled = drawerGesturesEnabled,
scaffoldState = scaffoldState,
drawerBackgroundColor = Color.Transparent,
drawerElevation = 0.dp,
drawerContent = {
NavDrawerHandler(scaffoldState = scaffoldState)
},
content = {
ScreenFactoryHandler()
}
)
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
CustomSnackbarHandler(modifier = modifier)
}
}
The custom snackbar is shown or hidden by observing the state of a variable that is located in my main viewmodel:
@Composable
fun CustomSnackbarHandler(modifier: Modifier = Modifier) {
val vmMain: MainViewModel = viewModel()
val visible = vmMain.onSnackbarVisible.observeAsState(false)
CustomSnackbar(
visible = visible.value,
snackbarInfo = vmMain.snackbarInfo,
modifier = modifier,
onTimeout = {
vmMain.hideSnackbar()
}) {
vmMain.onSnackbarActionButtonClick()
}
}
In your app, you just need to place the code that triggers the observable in some global object instead of some viewmodel. If you have a class that inherits from Application, you can place it there.
To show or hide the snackbar, I simply make the call from anywhere like this:
App.mainViewModel.displaySnackbar(SnackbarInfo(message = "You selected: $result"))
I use a SnackbarInfo class (that I wrote) to provide multiple parameters to the snackbar. I perfer doing it that way instead of passing a bunch of parameters to it.