Home > Back-end >  SimpleAlertDialog component in Jetpack Compose cannot be added to a DetailView due to context of @Co
SimpleAlertDialog component in Jetpack Compose cannot be added to a DetailView due to context of @Co

Time:08-17

I was developing an app where I'm using Jetpack Compose as UI developing tool, and I design some kind of custom AlertDialog, which is the following:

CustomAlertDialog.kt


@Composable
fun SimpleAlertDialog(
    hero: CharacterModel? = null,
    show: Boolean,
    onConfirm: () -> Unit,
    onDismiss: () -> Unit,
    textDescription: String,
    textTittle: String,
) {
    if(show){
        AlertDialog(
            onDismissRequest = onDismiss,
            confirmButton = {
                TextButton(onClick = onConfirm)
                { Text(text = "OK") }
            },
            dismissButton = {
                TextButton(onClick = onDismiss)
                { Text(text = "Cancel") }
            },
            title = { Text(text = textTittle) },
            text = { Text(text = textDescription) }
        )
    }
}

But when I try to use in a detailScreen, I get the following context Composable error:

@Composable invocations can only happen from the context of a @Composable function

the region of code where I try to instances the following, where I get the error:


@OptIn(ExperimentalFoundationApi::class)
@Composable
fun MyCharactersListRowView(
    viewmodel: MainViewModel,
    characterModel: CharacterModel,
    popBack: () -> Unit
) {
    val (characterSelected, setCharacterSelected) = remember { mutableStateOf<CharacterModel?>(null) } //HOOK FUNCTION
    val openDialog = remember { mutableStateOf(false) }

    Row(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = { setCharacterSelected(characterModel) })
            .padding(vertical = 8.dp, horizontal = 16.dp),
        verticalAlignment = Alignment.CenterVertically
    ){
        AsyncImage(
            model = characterModel.image,
            contentDescription = characterModel.name,
            contentScale = ContentScale.Fit,
            modifier = Modifier
                .size(60.dp)
                .clip(CircleShape)
                .combinedClickable(
                    onLongClick = {
                        if (characterSelected != null) {
                            SimpleAlertDialog(
                                hero = characterSelected,
                                show = true,
                                onConfirm = {
                                    viewmodel
                                        .deleteCharacter(characterSelected!!.id.toLong())
                                        .also {
                                            Log.d(
                                                "info",
                                                "rowAffected: ${viewmodel.rowAffected.value}"
                                            )
                                            if (viewmodel.rowAffected.value.toInt() != 0) {
                                                Toast
                                                    .makeText(
                                                        LocalContext.current!!,
                                                        "¡ ${characterSelected.name} bought sucessfully!",
                                                        Toast.LENGTH_LONG
                                                    )
                                                    .show()
                                                    .also {
                                                        openDialog.value = false
                                                    }
                                            } else {
                                                Toast
                                                    .makeText(
                                                        LocalContext.current!!,
                                                        viewmodel.loadError.value,
                                                        Toast.LENGTH_LONG
                                                    )
                                                    .show()
                                                    .also {
                                                        openDialog.value = false
                                                    }
                                            }
                                        }
                                },
                                onDismiss = { openDialog.value = false },
                                textTittle = "Remove character",
                                textDescription = "Would you like to remove ${characterSelected.name} from your characters?"
                            )
                        } else {

                        }
                    },
                    onClick = {
                        //TODO {Do something}
                    }
                )
        )

...

...

So I know is a quite beginner error, but I've not been able to get into a working solution, due to take thanks in advance is you know how implement it.

CodePudding user response:

You can't call a Dialog from a lambda that doesn't have @Composable annotation. You can check this answer out for differences between Composable and non-Composable functions.

fun Modifier.combinedClickable(
    enabled: Boolean = true,
    onClickLabel: String? = null,
    role: Role? = null,
    onLongClickLabel: String? = null,
    onLongClick: (() -> Unit)? = null,
    onDoubleClick: (() -> Unit)? = null,
    onClick: () -> Unit
) 

These lambdas are not @Composable

Common way for showing dialog in Jetpack Compose is

var showDialog by remember {mutableStateOf(false)}

if(characterSelected && showDialog) {
  SimpleAlertDialog(onDismiss={showDialog = false})
}

and change showDialog to true inside long click

onLongClick = {
  showDialog = true
}

Show custom alert dialog in Jetpack Compose

  • Related