0

I have a dialog written as @Composable. Inside there is a scrollable Column object with 2 TextFields and Buttons (for Login). When user enters wrong information an error text appears at the top. When the TextFields have the focus, the android keyboard shows up. With the errorText, maybe the dialog is to big to show everything when keyboard is open and start to scroll (what is like expected). But when the keyboard is closed, I would expect the the dialog measured it heights again to expand the height and show the hole content without scrolling. So I assume toggling the state if keyboard does not recompose the UI.

Is there a way to recompose the dialog as result of toggling the keyboard?

here the code of the dialog:

@Composable
fun Dialog() {
    val theme by currentTheme.collectAsMutableState()
    val error by rememberSaveable { mError }
    var emailError by rememberSaveable { mutableStateOf(context.getString(R.string.empty_error_text)) }
    var passwordError by rememberSaveable { mutableStateOf(context.getString(R.string.empty_error_text)) }
    var email = ""
    var password = ""

    Dialog(
        onDismissRequest = { onDismissRequest.invoke() },
        DialogProperties(dismissOnClickOutside = false)
    ) {
        Surface(
            modifier = Modifier
                .fillMaxWidth()
                .wrapContentHeight(),
            shape = RoundedCornerShape(size = 10.dp)
        ) {
            Column(modifier = Modifier.padding(16.dp)) {
                Row(
                    modifier = Modifier.fillMaxWidth()
                ) {
                    Image(
                        modifier = verticalGradientModifier(theme).size(25.dp),
                        painter = painterResource(id = R.mipmap.icons8_login_125px),
                        contentDescription = stringResource(R.string.log_in_online)
                    )
                    Text(
                        modifier = horizontalGradientModifier(theme)
                            .align(CenterVertically)
                            .padding(start = 5.dp),
                        text = stringResource(R.string.log_in_online),
                        fontSize = 16.sp,
                        fontWeight = FontWeight.Bold
                    )
                }
                Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
                    if (error.isNotEmpty()) {
                        Box(
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(5.dp)
                                .border(1.dp, Color.Red, RoundedCornerShape(10))
                        ) {
                            Text(
                                modifier = Modifier.padding(5.dp),
                                text = error,
                                color = Color.Red
                            )
                        }
                    }
                    InputView(
                        title = stringResource(R.string.email_label),
                        description = stringResource(R.string.login_email_description),
                        icon = R.mipmap.icons8_mail_125px,
                        error = emailError,
                        important = true
                    ) {
                        email = it
                        emailError = if (it.isNotEmpty()) {
                            ""
                        } else {
                            context.getString(R.string.empty_error_text)
                        }
                    }
                    InputView(
                        title = stringResource(R.string.label_password),
                        description = stringResource(R.string.login_password_description),
                        icon = R.mipmap.icons8_password_125px,
                        error = passwordError,
                        inputType = KeyboardType.Password,
                        important = true
                    ) {
                        password = it
                        passwordError = if (it.isNotEmpty()) {
                            ""
                        } else {
                            context.getString(R.string.empty_error_text)
                        }
                    }
                    Row(
                        modifier = Modifier
                            .align(CenterHorizontally)
                            .padding(10.dp)
                    ) {
                        TextButton(
                            modifier = Modifier
                                .padding(5.dp)
                                .border(
                                    width = 1.dp,
                                    brush = horizontalGradientBrush(theme),
                                    shape = RoundedCornerShape(percent = 10)
                                ),
                            enabled = passwordError.isEmpty() && emailError.isEmpty(),
                            onClick = {
                                Repository.execute {
                                    Repository.login(email, password) { success, _ ->
                                        if (success) {
                                            onDismissRequest.invoke()
                                        } else {
                                            //show error banner
                                            mError.value = "Ether email or password was wrong."
                                        }
                                    }
                                }
                            }) {
                            Image(
                                modifier = verticalGradientModifier(theme).size(25.dp),
                                painter = painterResource(id = R.mipmap.icons8_login_125px),
                                contentDescription = stringResource(R.string.title_login)
                            )
                            Text(
                                modifier = horizontalGradientModifier(theme).padding(start = 5.dp),
                                text = stringResource(R.string.title_login)
                            )
                        }
                        Text(
                            modifier = horizontalGradientModifier(theme)
                                .padding(5.dp)
                                .align(CenterVertically),
                            text = "or"
                        )
                        TextButton(
                            modifier = Modifier
                                .padding(5.dp)
                                .border(
                                    width = 1.dp,
                                    brush = horizontalGradientBrush(theme),
                                    shape = RoundedCornerShape(percent = 10)
                                ),
                            onClick = {
                                //open Sign-In dialog
                            }) {
                            Image(
                                modifier = verticalGradientModifier(theme).size(25.dp),
                                painter = painterResource(id = R.mipmap.icons8_create_125px),
                                contentDescription = stringResource(R.string.sign_in)
                            )
                            Text(
                                modifier = horizontalGradientModifier(theme).padding(start = 5.dp),
                                text = stringResource(R.string.sign_in)
                            )
                        }
                    }
                }
            }
        }
    }
}
Sebi
  • 133
  • 1
  • 9

1 Answers1

0

You can use WindowInsets.isImeVisible to listen for keyboard status and make changes accordingly.

Sample code

@OptIn(ExperimentalLayoutApi::class)
@Composable
fun KeyboardListenerDemo() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .statusBarsPadding(),
    ) {
        Text(
            text = "Keyboard Visible : ${WindowInsets.isImeVisible}",
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp),
        )
        OutlinedTextField(
            value = "",
            onValueChange = {},
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp)
        )
    }
}

Note: For this to return correct values you should set

WindowCompat.setDecorFitsSystemWindows(window, false)

I have set this in Activity before setContent{}

Soure: https://stackoverflow.com/a/73358604/9636037
Refer to this answer for more advanced use cases like tracking keyboard opening and closing.

Abhimanyu
  • 11,351
  • 7
  • 51
  • 121
  • Okay with this I know when keyboard is shown or hide but I don't know what do to with this information to "recompose" the UI without hiding the keyboard after recompose the whole dialog. – Sebi Jun 15 '23 at 08:33
  • Use this in the state of the dialog attributes. For example, if you need to change the height, use this to give two conditional heights. – Abhimanyu Jun 15 '23 at 12:30