NullPointerException
NullPointerException

Reputation: 37733

Display multiple dialog types with different text in Compose

Which whould be the best approach to display, for example, 2 types of dialogs on a screen and also parametrize the message to each dialog? For now I have a remember mutable state DialogType enum variable which represents if a dialog must be displayed or not, so if the state is MessageDialog or ConfirmationDialog will display one of those. But... what if I need to parametrize the message (or more variables like for example a image, but for this case it will be simplyfied to message) to one of these dialogs? Should I use another remember state variable with the string? If so, then I'm using two different remember state variables. Is that correct?

For sure there are complex ways to achieve this, creating special data classes, wrapping them, passing composable content as parameters to the dialog, etc... but I'm trying to avoid these kind of complex and overprogrammed developments and trying to find a simple and easy way to achieve this.

This is the sample code I did:

var dialogState by remember { mutableStateOf(DialogStateType.HIDDEN) }
var dialogMessage by remember { mutableStateOf("") }

In the buttons i change the state of these variables like this:

onClick = {
    dialogMessage = "sample message text"
    dialogState = DialogStateType.MESSAGE
}) {

onClick = {
    dialogMessage = "sample confirmation dialog text"
    dialogState = DialogStateType.CONFIRMATION
}) {

And in the main composable I display them using this:

when (dialogState) {
    DialogStateType.MESSAGE -> {
        MessageDialog(dialogMessage) {
            dialogState = DialogStateType.HIDDEN
        }
    }

    DialogStateType.CONFIRMATION -> {
        ConfirmationDialog(dialogMessage,
            {
                CoroutineScope(Dispatchers.Default).launch {
                    //DO HARD JOB
                }
            },
            { dialogState = DialogStateType.HIDDEN },
            { dialogState = DialogStateType.HIDDEN })
    }
    DialogStateType.HIDDEN -> {}
}

This approach works and it's simple, but seems to be not too much escalable, Is this the recommended way of doing this? or is there a simpler and easier way?

Upvotes: 2

Views: 1092

Answers (1)

bylazy
bylazy

Reputation: 1305

Kotlin's default arguments and ?.let {...} can help

Some class representing state:

data class DialogState(val caption: String? = "Dialog",
                       val text: String? = null,
                       val imageResId: String? = null,
                       val confirmButtonText: String = "OK",
                       val cancelButtonText: String? = null,
                       val onConfirm: () -> Unit = {},
                       val onCancel: () -> Unit = {})

Generic dialog composabe like:

@Composable
fun GenericDialog(dialogState: DialogState, onDismiss: () -> Unit) {
    Dialog(onDismissRequest = onDismiss) {
        Surface {
            Column(
                modifier = Modifier.padding(10.dp),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                dialogState.caption?.let {
                    Text(text = dialogState.caption,
                        style = TextStyle(fontWeight = FontWeight.ExtraBold))
                    Spacer(modifier = Modifier.size(10.dp))
                }
                dialogState.imageResId?.let{
                    //show image
                    Spacer(modifier = Modifier.size(10.dp))
                }
                dialogState.text?.let {
                    Text(text = dialogState.text)
                    Spacer(modifier = Modifier.size(10.dp))
                }
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                    horizontalArrangement = Arrangement.SpaceBetween
                ) {
                    Button(onClick = dialogState.onConfirm) {
                        Text(text = dialogState.confirmButtonText)
                    }
                    dialogState.cancelButtonText?.let {
                        Spacer(modifier = Modifier.size(10.dp))
                        Button(onClick = dialogState.onCancel) {
                            Text(text = dialogState.cancelButtonText)
                        }
                    }
                }
            }
        }
    }
}

And then:

var showDialog by remember { mutableStateOf(false) }
var dialogState = remember { DialogState() }
//...
if (showDialog) GenericDialog(dialogState = dialogState) { showDialog = false }
//...
Button(onClick = {
            dialogState = DialogState(caption = "Caption",
                text = "Text text text text text text text text text text text", 
                onConfirm = {showDialog = false})
            showDialog = true
        }) {
            Text(text = "Caption, text, one button")
        }
// or
Button(onClick = {
            dialogState = DialogState(caption = null,
                text = "Text text text text text text text text text text text",
                cancelButtonText = "Cancel",
                onConfirm = {showDialog = false},
                onCancel = {showDialog = false})
            showDialog = true
        }) {
            Text(text = "Text, two buttons")
        }

Upvotes: 1

Related Questions