From 01a154d425ebd37e53801785c13cce3e8e371f3f Mon Sep 17 00:00:00 2001 From: "omer.habib" Date: Sat, 29 Jun 2024 03:20:31 +0500 Subject: [PATCH] fix: Added error Text for editable fields on SignIn Screen - Add error text in case of empty fields on sign in Screen fix: LEARNER-10032 --- .../restore/RestorePasswordFragment.kt | 24 +++++++---- .../presentation/signin/compose/SignInView.kt | 42 ++++++++++++++++--- .../openedx/auth/presentation/ui/AuthUI.kt | 32 ++++++++++---- auth/src/main/res/values/strings.xml | 3 ++ 4 files changed, 81 insertions(+), 20 deletions(-) diff --git a/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordFragment.kt b/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordFragment.kt index 41fe23230..fa459d756 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordFragment.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/restore/RestorePasswordFragment.kt @@ -128,9 +128,8 @@ private fun RestorePasswordScreen( ) { val scaffoldState = rememberScaffoldState() val scrollState = rememberScrollState() - var email by rememberSaveable { - mutableStateOf("") - } + var email by rememberSaveable { mutableStateOf("") } + var isEmailError by rememberSaveable { mutableStateOf(false) } val keyboardController = LocalSoftwareKeyboardController.current Scaffold( @@ -271,13 +270,20 @@ private fun RestorePasswordScreen( description = stringResource(id = authR.string.auth_example_email), onValueChanged = { email = it + isEmailError = email.isEmpty() }, imeAction = ImeAction.Done, keyboardActions = { keyboardController?.hide() - it.clearFocus() - onRestoreButtonClick(email) - } + if (email.isNotEmpty()) { + it.clearFocus() + onRestoreButtonClick(email) + } else { + isEmailError = email.isEmpty() + } + }, + isError = isEmailError, + errorMessages = stringResource(id = authR.string.auth_error_empty_email) ) Spacer(Modifier.height(50.dp)) if (uiState == RestorePasswordUIState.Loading) { @@ -296,7 +302,11 @@ private fun RestorePasswordScreen( text = stringResource(id = authR.string.auth_reset_password), onClick = { keyboardController?.hide() - onRestoreButtonClick(email) + if (email.isNotEmpty()) { + onRestoreButtonClick(email) + } else { + isEmailError = email.isEmpty() + } } ) } diff --git a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt index fc7fb5ae6..bce426ff4 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signin/compose/SignInView.kt @@ -222,6 +222,9 @@ private fun AuthForm( var login by rememberSaveable { mutableStateOf("") } var password by rememberSaveable { mutableStateOf("") } val keyboardController = LocalSoftwareKeyboardController.current + var isEmailError by rememberSaveable { mutableStateOf(false) } + var isPasswordError by rememberSaveable { mutableStateOf(false) } + Column(horizontalAlignment = Alignment.CenterHorizontally) { LoginTextField( @@ -231,7 +234,11 @@ private fun AuthForm( description = stringResource(id = R.string.auth_enter_email_username), onValueChanged = { login = it - }) + isEmailError = login.isEmpty() + }, + isError = isEmailError, + errorMessages = stringResource(id = R.string.auth_error_empty_username_email) + ) Spacer(modifier = Modifier.height(18.dp)) PasswordTextField( @@ -239,11 +246,18 @@ private fun AuthForm( .fillMaxWidth(), onValueChanged = { password = it + isPasswordError = password.isEmpty() }, onPressDone = { keyboardController?.hide() - onEvent(AuthEvent.SignIn(login = login, password = password)) - } + if (password.isNotEmpty()) { + onEvent(AuthEvent.SignIn(login = login, password = password)) + } else { + isEmailError = login.isEmpty() + isPasswordError = password.isEmpty() + } + }, + isError = isPasswordError, ) Row( @@ -286,7 +300,12 @@ private fun AuthForm( backgroundColor = MaterialTheme.appColors.secondaryButtonBackground, onClick = { keyboardController?.hide() - onEvent(AuthEvent.SignIn(login = login, password = password)) + if (login.isNotEmpty() && password.isNotEmpty()) { + onEvent(AuthEvent.SignIn(login = login, password = password)) + } else { + isEmailError = login.isEmpty() + isPasswordError = password.isEmpty() + } } ) } @@ -308,6 +327,7 @@ private fun AuthForm( @Composable private fun PasswordTextField( modifier: Modifier = Modifier, + isError: Boolean, onValueChanged: (String) -> Unit, onPressDone: () -> Unit, ) { @@ -366,9 +386,21 @@ private fun PasswordTextField( focusManager.clearFocus() onPressDone() }, + isError = isError, textStyle = MaterialTheme.appTypography.bodyMedium, - singleLine = true + singleLine = true, ) + if (isError) { + Text( + modifier = Modifier + .testTag("txt_password_error") + .fillMaxWidth() + .padding(top = 4.dp), + text = stringResource(id = R.string.auth_error_empty_password), + style = MaterialTheme.appTypography.bodySmall, + color = MaterialTheme.appColors.error, + ) + } } @Preview(uiMode = UI_MODE_NIGHT_NO) diff --git a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt index 16d75492b..9f75a2478 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/ui/AuthUI.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions @@ -69,14 +70,15 @@ fun RequiredFields( showErrorMap: MutableMap, selectableNamesMap: MutableMap, onFieldUpdated: (String, String) -> Unit, - onSelectClick: (String, RegistrationField, List) -> Unit + onSelectClick: (String, RegistrationField, List) -> Unit, ) { fields.forEach { field -> when (field.type) { RegistrationFieldType.TEXT, RegistrationFieldType.EMAIL, RegistrationFieldType.CONFIRM_EMAIL, - RegistrationFieldType.PASSWORD -> { + RegistrationFieldType.PASSWORD, + -> { InputRegistrationField( modifier = Modifier.fillMaxWidth(), isErrorShown = showErrorMap[field.name] ?: true, @@ -232,9 +234,11 @@ fun LoginTextField( modifier: Modifier = Modifier, title: String, description: String, + isError: Boolean = false, + errorMessages: String = "", onValueChanged: (String) -> Unit, imeAction: ImeAction = ImeAction.Next, - keyboardActions: (FocusManager) -> Unit = { it.moveFocus(FocusDirection.Down) } + keyboardActions: (FocusManager) -> Unit = { it.moveFocus(FocusDirection.Down) }, ) { var loginTextFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf( @@ -281,8 +285,20 @@ fun LoginTextField( }, textStyle = MaterialTheme.appTypography.bodyMedium, singleLine = true, - modifier = modifier.testTag("tf_email") + modifier = modifier.testTag("tf_email"), + isError = isError ) + if (isError) { + Text( + modifier = Modifier + .testTag("txt_email_error") + .fillMaxWidth() + .padding(top = 4.dp), + text = errorMessages, + style = MaterialTheme.appTypography.bodySmall, + color = MaterialTheme.appColors.error, + ) + } } @Composable @@ -290,7 +306,7 @@ fun InputRegistrationField( modifier: Modifier, isErrorShown: Boolean, registrationField: RegistrationField, - onValueChanged: (String, String, Boolean) -> Unit + onValueChanged: (String, String, Boolean) -> Unit, ) { var inputRegistrationFieldValue by rememberSaveable { mutableStateOf(registrationField.placeholder) @@ -401,7 +417,7 @@ fun SelectableRegisterField( registrationField: RegistrationField, isErrorShown: Boolean, initialValue: String, - onClick: (String, List) -> Unit + onClick: (String, List) -> Unit, ) { val helperTextColor = if (registrationField.errorInstructions.isEmpty()) { MaterialTheme.appColors.textSecondary @@ -489,7 +505,7 @@ fun SelectableRegisterField( fun ExpandableText( modifier: Modifier = Modifier, isExpanded: Boolean, - onClick: (Boolean) -> Unit + onClick: (Boolean) -> Unit, ) { val transitionState = remember { MutableTransitionState(isExpanded).apply { @@ -537,7 +553,7 @@ fun ExpandableText( @Composable internal fun PasswordVisibilityIcon( isPasswordVisible: Boolean, - onClick: () -> Unit + onClick: () -> Unit, ) { val (image, description) = if (isPasswordVisible) { Icons.Filled.VisibilityOff to stringResource(R.string.auth_accessibility_hide_password) diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 642185915..49a8fb68e 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -22,7 +22,10 @@ We have sent a password recover instructions to your email %s username@domain.com Enter email or username + Please enter your username or e-mail address and try again. + Please enter your e-mail address and try again. Enter password + Please enter your password and try again. Create an account to start learning today! Complete your registration Sign in with Google