0

Despite all the examples here, even the hacky solutions using a delay, nothing seems to work.

The focus needs to happen on recomposition when an error flag is true validating a username or a password. These errors work and display correctly. what doesn't work is requesting focus which subsequently does not bring the element into the view.

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun RegistrationScreenExample(
    errorState: List<RegistrationErrorState> = listOf(RegistrationErrorState(false)),
    enableContinue: Boolean = LocalInspectionMode.current,
    onContinue: (String, String) -> Unit,
    usernameValidation: UsernameValidation,
    passwordValidation: PasswordValidation,
    previewUsername: String = if (LocalInspectionMode.current) "[email protected]" else "",
    previewPassword: String = if (LocalInspectionMode.current) "testPassword" else "",
) {
    val focusRequester = remember { FocusRequester() }
    val focusManager = LocalFocusManager.current
    val bringIntoViewRequester = remember { BringIntoViewRequester() }
    val coroutineScope = rememberCoroutineScope()

    val focusModifier = Modifier
        .focusable()
        .focusRequester(focusRequester)
        .onFocusEvent {
            if (it.isFocused) {
                coroutineScope.launch {
                    bringIntoViewRequester.bringIntoView()
                }
            }
        }

    var username by remember { mutableStateOf(previewUsername) }
    var password by remember { mutableStateOf(previewPassword) }
    var passwordConfirmation by remember { mutableStateOf(previewPassword) }

    val usernameError: RegistrationErrorState? = errorState.firstOrNull { it.errorField == RegistrationFieldEnum.USERNAME }
    val passwordError: RegistrationErrorState? = errorState.firstOrNull { it.errorField == RegistrationFieldEnum.PASSWORD }
    val passwordConfirmationError: RegistrationErrorState? = errorState.firstOrNull { it.errorField == RegistrationFieldEnum.PASSWORD_CONF }

    LaunchedEffect(Unit) {
        if (usernameError?.isError == true || passwordError?.isError == true) {
            // Doesnt matter how long, never works.
            delay(1000.toLong())
            focusRequester.requestFocus()
        }
    }

    LazyColumn(
        modifier = Modifier
            .fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {

        item {
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(horizontal = 32.dp),
            ) {

                val userModifier = if(usernameError?.isError == true) focusModifier else Modifier

                // Username
                Input(
                    modifier = userModifier,
                    label = "Username",
                    value = username,
                    isError = usernameError?.isError == true,
                    supportingText = usernameError?.errorMessage ?: "",
                    onValueChange = {
                        usernameValidation.username = it
                        username = it
                    }
                )

                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(vertical = 8.dp)
                ) {
                    RequirementIndicator(
                        visible = true,
                        requirementMet = usernameValidation.lengthValid,
                        requirementDescription = "Length 6-36"
                    )
                    RequirementIndicator(
                        visible = true,
                        requirementMet = usernameValidation.legalCharacters,
                        requirementDescription = "Special '.' and '@' allowed"
                    )
                }
                StandardSpacer()

                val passModifier = if(usernameError?.isError == true) focusModifier else Modifier

                // Password
                Input(
                    modifier = passModifier,
                    label = "Create Password",
                    value = password,
                    onValueChange = {
                        passwordValidation.password = it
                        password = it
                    },
                )
                Column(
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(vertical = 8.dp)
                ) {
                    RequirementIndicator(
                        visible = true,
                        requirementMet = passwordValidation.lengthValid,
                        requirementDescription = "Length 8-64"
                    )
                    RequirementIndicator(
                        visible = true,
                        requirementMet = passwordValidation.hasUppercase,
                        requirementDescription = "At least 1 Uppercase"
                    )
                    RequirementIndicator(
                        visible = true,
                        requirementMet = passwordValidation.hasLowercase,
                        requirementDescription = "At least 1 Lowercase"
                    )
                    RequirementIndicator(
                        visible = true,
                        requirementMet = passwordValidation.hasNumber,
                        requirementDescription = "At least 1 Number"
                    )
                    RequirementIndicator(
                        visible = true,
                        requirementMet = passwordValidation.hasSpecialCharacter,
                        requirementDescription = "At least 1 Special Character"
                    )
                }
                StandardSpacer()

                // Password Confirmation
                Input(
                    label = "Confirm Password",
                    value = passwordConfirmation,
                    isError = passwordConfirmationError?.isError == true,
                    onValueChange = {
                        passwordConfirmation = it
                    },
                    supportingText = if (passwordConfirmation.isNotEmpty()) passwordConfirmationError?.errorMessage
                        ?: "" else "",
                )
                StandardSpacer()

            }
        }

        item {
            OutlinedButton(
                modifier = Modifier
                    .fillMaxWidth(.4f)
                    .padding(bottom = 32.dp),
                enabled = enableContinue,
                onClick = {
                    // Clearing focus works just fine
                    focusManager.clearFocus()
                    onContinue(username, password)
                },
            ) {
                Text(text = "Continue")
            }
        }
    }
}

0