Hi I found bug in wear-compose material 1.3.1's di...
# compose-wear
b
Hi I found bug in wear-compose material 1.3.1's dialog. When I change
showDialog
to false but onDismissRequest not triggered in 1.3.1. wear-compose 1.3.1 dialog is in the code block below.
Copy code
if (showDialog || transition.currentState == DialogVisibility.Display) {
        Dialog(
            onDismissRequest = onDismissRequest,
            properties = properties,
        ) {
          
            ...

            LaunchedEffect(showDialog) {
                if (showDialog) {
                    // a) Fade out previous screen contents b) Scale down dialog contents from 125%
                    transitionState.targetState = DialogVisibility.Display
                    pendingOnDismissCall = true
                } else {
                    // a) Fade out dialog contents b) Scale up dialog contents.
                    transitionState.targetState = DialogVisibility.Hide
                }
            }

            LaunchedEffect(transitionState.currentState) {
                if (pendingOnDismissCall &&
                    transitionState.currentState == DialogVisibility.Hide &&
                    transitionState.isIdle
                ) {
                    // After the outro animation, leave the dialog & reset alpha/scale transitions.
                    onDismissRequest()
                    pendingOnDismissCall = false
                }
            }
And when
showDialog
go to false then first LaunchedEffect is triggered.
Copy code
LaunchedEffect(showDialog) {
                if (showDialog) {
                    // a) Fade out previous screen contents b) Scale down dialog contents from 125%
                    transitionState.targetState = DialogVisibility.Display
                    pendingOnDismissCall = true
                } else {
                    // a) Fade out dialog contents b) Scale up dialog contents.
                    transitionState.targetState = DialogVisibility.Hide
                }
            }
This LaunchedEffect make
transitionState.TargetState = DialogVisibility.Hide
Because of targetState change to hide, currentState also change to Hide and this have to trigger second LaunchedEffect for run
onDismissRequest
Copy code
LaunchedEffect(transitionState.currentState) {
                if (pendingOnDismissCall &&
                    transitionState.currentState == DialogVisibility.Hide &&
                    transitionState.isIdle
                ) {
                    // After the outro animation, leave the dialog & reset alpha/scale transitions.
                    onDismissRequest()
                    pendingOnDismissCall = false
                }
            }
However, Dialog Composable's visible condition is
if (showDialog || transition.currentState == DialogVisibility.Display)
. So based on the if condition the dialog will be hidden. The second LaunchedEffect is contained in this hidden Dialog, so it will never be triggered. As a result, when
showDialog
change to false, never triggered
onDismissRequest
I thinks second LaunchedEffect about transitionState.currentState need to move outside of if condition.
s
Hi - thanks for reaching out with this. Please will you share your code for how you are calling the wear compose dialog (I think all the snippets above are from the wear compose dialog implementation)? In our tests , the dialog is working well, for example as follows:
Copy code
var showDialog by remember { mutableStateOf(false) }
    val scrollState = rememberScalingLazyListState()
    LaunchScreen(onClick = { showDialog = true }) // display button to set showDialog=true
    Dialog(
        showDialog = showDialog,
        onDismissRequest = { showDialog = false },
        scrollState = scrollState,
    ) {
      // Alert content goes here
    }
Note that we set showDialog = false in the onDismissRequest, and the Dialog calls onDismissRequest in response to a swipe to dismiss. In the Alert content, you would typically set showDialog = false in response to a button click too.
b
@stevebower Thank you for the reply. I am also using the method in the example you mentioned. In this flow, it works without problem as you mentioned. However, the issue mentioned above occurs when using dialog in the following block. I write a simple example of how the issue can be reproduced.
Copy code
// In NavHost
Composable(route = "OnlyDialogScreen"){
  OnlyDialogComposable(navController = navController)
}

// TestDialog
@Composable
fun OnlyDialogComposable(
    navController: NavController,
) {
    var showDialog by remember { mutableStateOf(true) }
    androidx.wear.compose.material.dialog.Dialog(showDialog = showDialog, onDismissRequest = {
        navController.popBackStack() // pop OnlyDialogComposable
    }) {
    Button(
        onClick = { showDialog = false }
    ) {
        Text(text = "Button1")
    }

    Button(
        onClick = { showDialog = false }
    ) {
        Text(text = "Button2")
    }
    }
}
In your example, onDIsmissRequest is triggered by SwipeDismiss or the backbutton and showDialog becomes false. However, In my example dialog appears on independent screen. The default showDialog is true, and when the user clicks the button, showDialog is change to false. In the old version of the wear-compose material, when showDialog becomes false, alpha and scale states changed by outro animation, and this state change triggers LaunchedEffect and LaunchedEffect trigger onDismissRequest. So I can trigger onDIsmissRequest by changing showDialog to false. However, in the latest library, as mentioned earlier, onDismissRequest does not triggered even if showDialog becomes false, so this logic cannot be established. To follow the example's instructions, I probably need to change the behavior likes code block below.
Copy code
@Composable
fun OnlyDialogComposable(
    navController: NavController,
) {
    var showDialog by remember { mutableStateOf(true) }
    androidx.wear.compose.material.dialog.Dialog(showDialog = showDialog, onDismissRequest = {
        showDialog = false
    }) {

    }
    Button(
        onClick = { navControler.popBackstack() // pop OnlyDialogComposable }
    ) {
        Text(text = "Button1")
    }

    Button(
        onClick = { navControler.popBackstack() }
    ) {
        Text(text = "Button2")
    }
}
However, if I look at the description of ShowDialog in the 1.3.1 library, it is still written as below.
Copy code
showDialog - Controls whether to display the Dialog. Set to true initially to trigger an 'intro' animation and display the Dialog. Subsequently, setting to false triggers an 'outro' animation, then Dialog calls onDismissRequest and hides itself.
According to this explanation, if showDialog change to false, outro animation should be triggered, and then onDismissRequest should be called.
m
Hi @barat. Resurrecting this thread. Sorry for such a late reply. Did it work for you before? Can you share with us a version when it worked to help triage this issue?
s
We experimented with calling onDismissRequest when showDialog was set to false, but there was a side-effect in some usages where it was called multiple times. We have instead updated the documentation to match the actual behavior, both in the Material and Material3 libraries. Thanks for bringing it to our attention that the documentation was incorrect.