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 37309cadf..783a60a99 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 @@ -49,6 +49,7 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview @@ -58,6 +59,7 @@ import org.openedx.auth.R import org.openedx.auth.presentation.signin.AuthEvent import org.openedx.auth.presentation.signin.SignInUIState import org.openedx.auth.presentation.ui.LoginTextField +import org.openedx.auth.presentation.ui.PasswordVisibilityIcon import org.openedx.auth.presentation.ui.SocialAuthView import org.openedx.core.UIMessage import org.openedx.core.extension.TextConverter @@ -305,11 +307,11 @@ private fun PasswordTextField( onPressDone: () -> Unit, ) { var passwordTextFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf( - TextFieldValue("") - ) + mutableStateOf(TextFieldValue("")) } + var isPasswordVisible by remember { mutableStateOf(false) } val focusManager = LocalFocusManager.current + Text( modifier = Modifier .testTag("txt_password_label") @@ -318,7 +320,9 @@ private fun PasswordTextField( color = MaterialTheme.appColors.textPrimary, style = MaterialTheme.appTypography.labelLarge ) + Spacer(modifier = Modifier.height(8.dp)) + OutlinedTextField( modifier = modifier.testTag("tf_password"), value = passwordTextFieldValue, @@ -341,11 +345,18 @@ private fun PasswordTextField( style = MaterialTheme.appTypography.bodyMedium ) }, + trailingIcon = { + PasswordVisibilityIcon( + isPasswordVisible = isPasswordVisible, + onClick = { isPasswordVisible = !isPasswordVisible } + ) + }, keyboardOptions = KeyboardOptions.Default.copy( keyboardType = KeyboardType.Password, imeAction = ImeAction.Done ), - visualTransformation = PasswordVisualTransformation(), + visualTransformation = if (isPasswordVisible) VisualTransformation.None + else PasswordVisualTransformation(), keyboardActions = KeyboardActions { focusManager.clearFocus() onPressDone() diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt index 8fafe40ff..08bbce466 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/SignUpViewModel.kt @@ -226,9 +226,14 @@ class SignUpViewModel( interactor.loginSocial(socialAuth.accessToken, socialAuth.authType) }.onFailure { val fields = uiState.value.allFields.toMutableList() - .filter { field -> field.type != RegistrationFieldType.PASSWORD } - updateField(ApiConstants.NAME, socialAuth.name) - updateField(ApiConstants.EMAIL, socialAuth.email) + .filter { it.type != RegistrationFieldType.PASSWORD } + .map { field -> + when (field.name) { + ApiConstants.NAME -> field.copy(placeholder = socialAuth.name) + ApiConstants.EMAIL -> field.copy(placeholder = socialAuth.email) + else -> field + } + } setErrorInstructions(emptyMap()) _uiState.update { it.copy( diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt index 42fd894df..2872c579b 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SignUpView.kt @@ -53,6 +53,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.testTagsAsResourceId +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Devices @@ -317,10 +318,11 @@ internal fun SignUpView( Text( modifier = Modifier .fillMaxWidth() - .padding(top = 4.dp), + .padding(top = 8.dp), text = stringResource( id = R.string.auth_compete_registration ), + fontWeight = FontWeight.Bold, color = MaterialTheme.appColors.textPrimary, style = MaterialTheme.appTypography.titleSmall ) diff --git a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SocialSignedView.kt b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SocialSignedView.kt index 25a9434d1..b2dee1919 100644 --- a/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SocialSignedView.kt +++ b/auth/src/main/java/org/openedx/auth/presentation/signup/compose/SocialSignedView.kt @@ -3,11 +3,15 @@ package org.openedx.auth.presentation.signup.compose import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Devices @@ -26,21 +30,36 @@ internal fun SocialSignedView(authType: AuthType) { Column( modifier = Modifier .background( - color = MaterialTheme.appColors.secondary, + color = MaterialTheme.appColors.authSSOSuccessBackground, shape = MaterialTheme.appShapes.buttonShape ) .padding(20.dp) ) { - Text( - fontSize = 18.sp, - fontWeight = FontWeight.Bold, - text = stringResource( - id = R.string.auth_social_signed_title, - authType.methodName + Row { + Icon( + modifier = Modifier + .padding(end = 8.dp) + .size(20.dp), + painter = painterResource(id = coreR.drawable.ic_core_check), + tint = MaterialTheme.appColors.successBackground, + contentDescription = "" ) - ) + + Text( + fontSize = 18.sp, + fontWeight = FontWeight.Bold, + color = MaterialTheme.colors.primary, + text = stringResource( + id = R.string.auth_social_signed_title, + authType.methodName + ) + ) + } + Text( - modifier = Modifier.padding(top = 8.dp), + modifier = Modifier.padding(top = 8.dp, start = 28.dp), + fontSize = 14.sp, + fontWeight = FontWeight.Normal, text = stringResource( id = R.string.auth_social_signed_desc, stringResource(id = coreR.string.app_name) 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 90fb91ee1..16d75492b 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 @@ -16,6 +16,7 @@ import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.Icon +import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.OutlinedTextField import androidx.compose.material.Text @@ -23,6 +24,8 @@ import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material.icons.filled.ExpandMore +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -70,7 +73,10 @@ fun RequiredFields( ) { fields.forEach { field -> when (field.type) { - RegistrationFieldType.TEXT, RegistrationFieldType.EMAIL, RegistrationFieldType.CONFIRM_EMAIL, RegistrationFieldType.PASSWORD -> { + RegistrationFieldType.TEXT, + RegistrationFieldType.EMAIL, + RegistrationFieldType.CONFIRM_EMAIL, + RegistrationFieldType.PASSWORD -> { InputRegistrationField( modifier = Modifier.fillMaxWidth(), isErrorShown = showErrorMap[field.name] ?: true, @@ -289,11 +295,15 @@ fun InputRegistrationField( var inputRegistrationFieldValue by rememberSaveable { mutableStateOf(registrationField.placeholder) } + var isPasswordVisible by remember { mutableStateOf(false) } + val focusManager = LocalFocusManager.current - val visualTransformation = if (registrationField.type == RegistrationFieldType.PASSWORD) { - PasswordVisualTransformation() - } else { - VisualTransformation.None + val visualTransformation = remember(isPasswordVisible) { + if (registrationField.type == RegistrationFieldType.PASSWORD && !isPasswordVisible) { + PasswordVisualTransformation() + } else { + VisualTransformation.None + } } val keyboardType = when (registrationField.type) { RegistrationFieldType.CONFIRM_EMAIL, RegistrationFieldType.EMAIL -> KeyboardType.Email @@ -315,6 +325,18 @@ fun InputRegistrationField( } else { registrationField.instructions } + val trailingIcon: @Composable (() -> Unit)? = + if (registrationField.type == RegistrationFieldType.PASSWORD) { + { + PasswordVisibilityIcon( + isPasswordVisible = isPasswordVisible, + onClick = { isPasswordVisible = !isPasswordVisible } + ) + } + } else { + null + } + Column { Text( modifier = Modifier @@ -359,6 +381,7 @@ fun InputRegistrationField( keyboardActions = KeyboardActions { focusManager.moveFocus(FocusDirection.Down) }, + trailingIcon = trailingIcon, textStyle = MaterialTheme.appTypography.bodyMedium, singleLine = isSingleLine, modifier = modifier.testTag("tf_${registrationField.name.tagId()}") @@ -418,6 +441,7 @@ fun SelectableRegisterField( OutlinedTextField( readOnly = true, enabled = false, + singleLine = true, value = initialValue, colors = TextFieldDefaults.outlinedTextFieldColors( unfocusedBorderColor = MaterialTheme.appColors.textFieldBorder, @@ -510,6 +534,26 @@ fun ExpandableText( } } +@Composable +internal fun PasswordVisibilityIcon( + isPasswordVisible: Boolean, + onClick: () -> Unit +) { + val (image, description) = if (isPasswordVisible) { + Icons.Filled.VisibilityOff to stringResource(R.string.auth_accessibility_hide_password) + } else { + Icons.Filled.Visibility to stringResource(R.string.auth_accessibility_show_password) + } + + IconButton(onClick = onClick) { + Icon( + imageVector = image, + contentDescription = description, + tint = MaterialTheme.appColors.onSurface + ) + } +} + @Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable diff --git a/auth/src/main/res/values/strings.xml b/auth/src/main/res/values/strings.xml index 49b3e0bbd..642185915 100644 --- a/auth/src/main/res/values/strings.xml +++ b/auth/src/main/res/values/strings.xml @@ -39,4 +39,6 @@ By creating an account, you agree to the %1$s and %2$s and you acknowledge that %3$s and each Member process your personal data in accordance with the %4$s. By signing in to this app, you agree to the %1$s and %2$s and you acknowledge that %3$s and each Member process your personal data in accordance with the %4$s. %2$s]]> + Show password + Hide password diff --git a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt index 625c52b27..37783b820 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/AppColors.kt @@ -51,6 +51,7 @@ data class AppColors( val inactiveButtonText: Color, val successGreen: Color, + val successBackground: Color, val datesSectionBarPastDue: Color, val datesSectionBarToday: Color, @@ -58,6 +59,7 @@ data class AppColors( val datesSectionBarNextWeek: Color, val datesSectionBarUpcoming: Color, + val authSSOSuccessBackground: Color, val authGoogleButtonBackground: Color, val authFacebookButtonBackground: Color, val authMicrosoftButtonBackground: Color, diff --git a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt index 88c973105..8fe1eb8ff 100644 --- a/core/src/main/java/org/openedx/core/ui/theme/Theme.kt +++ b/core/src/main/java/org/openedx/core/ui/theme/Theme.kt @@ -69,6 +69,7 @@ private val DarkColorPalette = AppColors( inactiveButtonText = dark_primary_button_text, successGreen = dark_success_green, + successBackground = dark_success_background, datesSectionBarPastDue = dark_dates_section_bar_past_due, datesSectionBarToday = dark_dates_section_bar_today, @@ -76,6 +77,7 @@ private val DarkColorPalette = AppColors( datesSectionBarNextWeek = dark_dates_section_bar_next_week, datesSectionBarUpcoming = dark_dates_section_bar_upcoming, + authSSOSuccessBackground = dark_auth_sso_success_background, authGoogleButtonBackground = dark_auth_google_button_background, authFacebookButtonBackground = dark_auth_facebook_button_background, authMicrosoftButtonBackground = dark_auth_microsoft_button_background, @@ -156,6 +158,7 @@ private val LightColorPalette = AppColors( inactiveButtonText = light_primary_button_text, successGreen = light_success_green, + successBackground = light_success_background, datesSectionBarPastDue = light_dates_section_bar_past_due, datesSectionBarToday = light_dates_section_bar_today, @@ -163,6 +166,7 @@ private val LightColorPalette = AppColors( datesSectionBarNextWeek = light_dates_section_bar_next_week, datesSectionBarUpcoming = light_dates_section_bar_upcoming, + authSSOSuccessBackground = light_auth_sso_success_background, authGoogleButtonBackground = light_auth_google_button_background, authFacebookButtonBackground = light_auth_facebook_button_background, authMicrosoftButtonBackground = light_auth_microsoft_button_background, diff --git a/course/src/main/res/drawable/ic_course_check.xml b/core/src/main/res/drawable/ic_core_check.xml similarity index 100% rename from course/src/main/res/drawable/ic_course_check.xml rename to core/src/main/res/drawable/ic_core_check.xml diff --git a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt index 855d557d3..ffc0b64e2 100644 --- a/core/src/openedx/org/openedx/core/ui/theme/Colors.kt +++ b/core/src/openedx/org/openedx/core/ui/theme/Colors.kt @@ -52,11 +52,13 @@ val light_info = Color(0xFF42AAFF) val light_rate_stars = Color(0xFFFFC94D) val light_inactive_button_background = Color(0xFFCCD4E0) val light_success_green = Color(0xFF198571) +val light_success_background = Color(0xFF0D7D4D) val light_dates_section_bar_past_due = light_warning val light_dates_section_bar_today = light_info val light_dates_section_bar_this_week = light_text_primary_variant val light_dates_section_bar_next_week = light_text_field_border val light_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val light_auth_sso_success_background = light_secondary val light_auth_google_button_background = Color.White val light_auth_facebook_button_background = Color(0xFF0866FF) val light_auth_microsoft_button_background = Color(0xFA000000) @@ -124,11 +126,13 @@ val dark_onInfo = Color.White val dark_rate_stars = Color(0xFFFFC94D) val dark_inactive_button_background = Color(0xFFCCD4E0) val dark_success_green = Color(0xFF198571) +val dark_success_background = Color.White val dark_dates_section_bar_past_due = dark_warning val dark_dates_section_bar_today = dark_info val dark_dates_section_bar_this_week = dark_text_primary_variant val dark_dates_section_bar_next_week = dark_text_field_border val dark_dates_section_bar_upcoming = Color(0xFFCCD4E0) +val dark_auth_sso_success_background = dark_secondary val dark_auth_google_button_background = Color(0xFF19212F) val dark_auth_facebook_button_background = Color(0xFF0866FF) val dark_auth_microsoft_button_background = Color(0xFA000000) diff --git a/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt b/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt index 27da57afb..3a40728dd 100644 --- a/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt +++ b/course/src/main/java/org/openedx/course/presentation/ui/CourseUI.kt @@ -910,7 +910,7 @@ fun SubSectionUnitsList( modifier = Modifier .size(16.dp) .alpha(if (unit.isCompleted()) 1f else 0f), - painter = painterResource(id = R.drawable.ic_course_check), + painter = painterResource(id = coreR.drawable.ic_core_check), contentDescription = "done" ) Text(