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.
Leave a Reply