SNM
SNM

Reputation: 6835

SnackBar does not show second time jetpack compose

I'm trying to understand why my SnackBar does not show second time, I'm propagating the snackbar message and error boolean values from my composables, I'm taking this data and emiting a single snackbar but it works first time and not second time with the same message even if I set the message to null.

When I go to my register screen I emit an error message if the e-mail is already present in the DB, then if I trigger again the same message, nothing happens and the snackbar does not appear, any ideas ?

MainActivity

setContent {
var snackBarMessage: String? by remember { mutableStateOf(null) }
            var isError by remember { mutableStateOf(false) }
            val snackbarHostState = remember { SnackbarHostState() }


            CryptoTheme {
                Scaffold(
                    scaffoldState = scaffoldState,
                    snackbarHost = {
                        SnackbarHost(hostState = snackbarHostState) { data ->
                            Snackbar(
                                snackbarData = data,
                                backgroundColor = if (!isError) GreenProfit else Color.Red,
                                contentColor = Color.White
                            )
                        }
                    },
                    bottomBar = { BottomBarNavigation(navController = navController) },
                    backgroundColor = Color.Black
                ) {
                    NavigationGraph(
                        modifier = Modifier.padding(bottom = it.calculateBottomPadding()),
                        navController = navController,
                        showSnackBarMessage = { message, showError ->
                            isError = showError
                            snackBarMessage = message
                        }
                    )

                    LaunchedEffect(key1 = snackBarMessage) {
                        if (snackBarMessage != null) {
                            snackbarHostState.showSnackbar(
                                message = snackBarMessage ?: ""
                            )
                            snackBarMessage = null
                        }
                    }
                }
            }
}

Inside NavigationGraph I have multiple composables that reuse this way of propagating the message and error to the scaffold to show the snackbar

NavigationGraph

NavigationGraph(showSnackBarMessage: (message: String, isError: Boolean)) {
Navhost(...) {
 composable(route) {
  RegisterComposable(showSnackBarMessage)
 }
}

and from the composable

RegisterComposable

RegisterComposable(showSnackBarMessage: (message: String, isError: Boolean)){ 
 when(uiState.signUpError) {
  showSnackBarMessage("E-mail already in use", true)
 }

Upvotes: 5

Views: 1384

Answers (2)

tahaak67
tahaak67

Reputation: 161

This is a bug in kotlinx-coroutines:1.8.0-RC you can simply fix it by upgrading to 1.8.0-RC2.

If you are using Compose multiplatform it is fixed in version 1.6.0-beta01 of the compose plugin or you can downgrade to 1.5.11 where the issue does not happen.

Upvotes: 0

fshdn19
fshdn19

Reputation: 410

Your snackbar is not shown because the message and isError are not changed. Compose will only get recomposed when its referenced values have changed.

Snackbar is a kind of one-time event. So you need to provide it as an effect

Recommend: combine your message and isError into a data model

data class SnackBarAction(
    val uid: Long = System.currentTimeMillis(),
    val text: String,
    val isError: Boolean,
)

On your compose layout

val (stateOfSnackBarAction, setSnackBarAction) = remember {
    mutableStateOf<SnackBarAction?>(null)
}
val scaffoldState = rememberScaffoldState()
val coroutineScope = rememberCoroutineScope()
Scaffold(scaffoldState = scaffoldState) {
    LaunchedEffect(key1 = stateOfSnackBarAction) {
        stateOfSnackBarAction ?: return@LaunchedEffect
        scaffoldState.snackbarHostState.showSnackbar(
            message = stateOfSnackBarAction.text,
            backgroundColor = if (stateOfSnackBarAction.isError)  Color.Red else GreenProfit,
        )
        ...
    }
    ...

To show snackbar

Button(
    onClick = {
        coroutineScope.launch {
            val current = System.currentTimeMillis()
            setSnackBarAction(SnackBarAction(
                uid = current,
                text = "Your message here",
                isError = true/false
            ))
        }
    }

Upvotes: 0

Related Questions