Android Compose Registration UI Form Validation

This post is focused on how I created a form validation for user registration.

I will just be posting the Composable I created because this could just be implemented anywhere. There is no outside connection to it yet except for a couple of booleans to handle submission and failure on submission.

Code

build.gradle – add extended material icons to use Visibility icons

implementation(libs.androidx.material.icons.extended)

libs.versions.toml – for icons stated above

[versions]
....
materialIconsExtended = "1.7.6"
....

[libraries]
....
androidx-material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "materialIconsExtended" }
....

RegisterUI – main composable, I created a seperate file for it to keep things organized.

@Composable
fun RegisterUI(
    userRegisterFail: Boolean,
    isRegisterProcessing: Boolean,
) {
    var usernameValidator by remember { mutableStateOf(true) }
    var emailValidator by remember { mutableStateOf(true) }
    var passwordValidator by remember { mutableStateOf(true) }

    var passwordVisible by remember { mutableStateOf(false) }

    var username by remember { mutableStateOf("Winston") }
    var email by remember { mutableStateOf("winston@clowncollege.com") }
    var password by remember { mutableStateOf("Password01") }

    ElevatedCard(
        modifier = Modifier
            .fillMaxWidth()
            .padding(25.dp),
        colors = CardDefaults.elevatedCardColors(MaterialTheme.colorScheme.primaryContainer)
    ) {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(10.dp), horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Spacer(modifier = Modifier.padding(10.dp))
            Text(text = "Register", style = MaterialTheme.typography.titleMedium)
            Spacer(modifier = Modifier.padding(10.dp))
            TextField(value = username, onValueChange = {
                username = it
                if (username.isEmpty()) {
                    usernameValidator = false
                } else {
                    usernameValidator = true
                }
            }, placeholder = { Text(text = "Choose your user name") })
            if (!usernameValidator) {
                Text(
                    text = "Invalid Username",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.error
                )
            }
            Spacer(modifier = Modifier.padding(10.dp))
            TextField(value = email, onValueChange = {
                email = it
                if (email.isEmpty() || !android.util.Patterns.EMAIL_ADDRESS.matcher(email)
                        .matches()
                ) {
                    emailValidator = false
                } else {
                    emailValidator = true
                }
            }, placeholder = { Text(text = "Enter Your Email") })
            if (!emailValidator) {
                Text(
                    text = "Invalid Email",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.error
                )
            }
            Spacer(modifier = Modifier.padding(10.dp))
            TextField(value = password, onValueChange = {
                password = it
                if (password.isEmpty() || password.length < 8 || !password.contains("[0-9]".toRegex()) || !password.contains("[A-Z]".toRegex()) || password.contains("[{('\"~\\[|\\]^)}]".toRegex())) {
                    passwordValidator = false
                } else {
                    passwordValidator = true
                }
            }, placeholder = { Text(text = "Enter Your Password") },
                visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
                trailingIcon = {
                    IconButton(onClick = { passwordVisible = !passwordVisible }) {
                        Icon(
                            imageVector = if (passwordVisible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff,
                            contentDescription = if (passwordVisible) "Hide Password" else "Show Password"
                        )
                    }
                }
            )
            if (!passwordValidator) {
                Text(
                    text = "Invalid Password" +
                            "\n-Needs to be at least 8 characters long" +
                            "\n-At least 1 number" +
                            "\n-At least 1 capital letter" +
                            "\n-Must Not contain one of the following " +
                            "special characters:" +
                            "\n { ( ' \" ~ [ |  ] ^ ) }",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.error
                )
            }
            Spacer(modifier = Modifier.padding(10.dp))
            //check if form is processing info, change from button to loading circle
            if (!isRegisterProcessing) {
                var check = listOf(usernameValidator, emailValidator, passwordValidator)
                Button(
                    enabled = if (check.any { !it }) false else true,
                    onClick = {
                        //submit form
                    }) {
                    Text(text = "Register")
                }
            } else {
                CircularProgressIndicator()
            }

            if (userRegisterFail) {
                Spacer(modifier = Modifier.padding(10.dp))
                Text(
                    text = "Registration Error",
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.error
                )
            }
        }
    }
}

Hope this helps.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *