diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/RegistrationScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/RegistrationScreen.kt index 0397637debd567e2987a3f37a0dbf2790fffcfba..02846c31c30ec5bdf9c1a37bdc3df12947dcfa0b 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/login/RegistrationScreen.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/login/RegistrationScreen.kt @@ -33,6 +33,7 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment.Companion.Center import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusDirection +import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.platform.LocalFocusManager @@ -64,10 +65,10 @@ fun RegistrationScreen( buttonEnabled = viewHolder.buttonEnabled.value ) { NicknameForm( - viewHolder.nickname.value, - viewHolder::setNickname, - viewHolder.nicknameTooLongError.value, - viewHolder::goToPassword + nickname = viewHolder.nickname.value, + setNickname = viewHolder::setNickname, + nicknameTooLongError = viewHolder.nicknameTooLongError.value, + onSubmit = viewHolder::goToPassword ) } INSERT_PASSWORD -> @@ -77,16 +78,26 @@ fun RegistrationScreen( buttonClick = viewHolder::signUp, buttonEnabled = viewHolder.buttonEnabled.value ) { + val initialFocusRequester = remember { FocusRequester() } + val focusManager = LocalFocusManager.current PasswordForm( - viewHolder.password.value, - viewHolder::setPassword, - viewHolder.passwordConfirmation.value, - viewHolder::setPasswordConfirmation, - viewHolder.passwordStrength.value, - viewHolder.passwordTooWeakError.value, - viewHolder.passwordMatchError.value, - viewHolder::signUp + focusManager = focusManager, + focusRequester = initialFocusRequester, + keyLabelPassword = "startup.field.password", + keyLabelPasswordConfirmation = "startup.field.password_confirmation", + password = viewHolder.password.value, + setPassword = viewHolder::setPassword, + passwordConfirmation = viewHolder.passwordConfirmation.value, + setPasswordConfirmation = viewHolder::setPasswordConfirmation, + passwordStrength = viewHolder.passwordStrength.value, + passwordTooWeakError = viewHolder.passwordTooWeakError.value, + passwordsDontMatchError = viewHolder.passwordMatchError.value, + onSubmit = viewHolder::signUp ) + + LaunchedEffect(Unit) { + initialFocusRequester.requestFocus() + } } CREATING -> LoadingView(i18n("startup.database.creating")) CREATED -> {} // case handled by BriarUi @@ -98,7 +109,7 @@ fun NicknameForm( nickname: String, setNickname: (String) -> Unit, nicknameTooLongError: Boolean, - onEnter: () -> Unit, + onSubmit: () -> Unit, ) { val initialFocusRequester = remember { FocusRequester() } @@ -111,7 +122,7 @@ fun NicknameForm( errorMessage = i18n("startup.error.name_too_long"), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), modifier = Modifier.fillMaxWidth().focusRequester(initialFocusRequester), - onEnter = onEnter + onEnter = onSubmit ) LaunchedEffect(Unit) { @@ -119,8 +130,17 @@ fun NicknameForm( } } +/** + * This is used here in the RegistrationScreen but also on [org.briarproject.briar.desktop.settings.ChangePasswordDialog]. + * + * You can pass an optional [focusRequester] if the first of both password fields should request focus using a modifier. + */ @Composable fun PasswordForm( + focusManager: FocusManager, + focusRequester: FocusRequester? = null, + keyLabelPassword: String, + keyLabelPasswordConfirmation: String, password: String, setPassword: (String) -> Unit, passwordConfirmation: String, @@ -128,11 +148,8 @@ fun PasswordForm( passwordStrength: Float, passwordTooWeakError: Boolean, passwordsDontMatchError: Boolean, - onEnter: () -> Unit, + onSubmit: () -> Unit, ) { - val initialFocusRequester = remember { FocusRequester() } - val focusManager = LocalFocusManager.current - Box( modifier = Modifier.fillMaxWidth().requiredHeight(24.dp), contentAlignment = Center @@ -143,29 +160,27 @@ fun PasswordForm( OutlinedPasswordTextField( value = password, onValueChange = setPassword, - label = { Text(i18n("startup.field.password")) }, + label = { Text(i18n(keyLabelPassword)) }, singleLine = true, isError = passwordTooWeakError, showErrorWhen = AFTER_FOCUS_LOST_ONCE, errorMessage = i18n("startup.error.password_too_weak"), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Next), - modifier = Modifier.fillMaxWidth().focusRequester(initialFocusRequester), + modifier = Modifier.fillMaxWidth().apply { + if (focusRequester != null) focusRequester(focusRequester) + }, onEnter = { focusManager.moveFocus(FocusDirection.Next) }, ) OutlinedPasswordTextField( value = passwordConfirmation, onValueChange = setPasswordConfirmation, - label = { Text(i18n("startup.field.password_confirmation")) }, + label = { Text(i18n(keyLabelPasswordConfirmation)) }, singleLine = true, isError = passwordsDontMatchError, showErrorWhen = AFTER_FIRST_FOCUSSED, errorMessage = i18n("startup.error.passwords_not_match"), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done), modifier = Modifier.fillMaxWidth(), - onEnter = onEnter, + onEnter = onSubmit, ) - - LaunchedEffect(Unit) { - initialFocusRequester.requestFocus() - } } diff --git a/src/main/kotlin/org/briarproject/briar/desktop/settings/ChangePasswordDialog.kt b/src/main/kotlin/org/briarproject/briar/desktop/settings/ChangePasswordDialog.kt index d9b6b5bba0489bd989453609c7fb523e7b5ac031..afe98b3c5d6af23945ab8e4f8115f3f3b4ef3ddb 100644 --- a/src/main/kotlin/org/briarproject/briar/desktop/settings/ChangePasswordDialog.kt +++ b/src/main/kotlin/org/briarproject/briar/desktop/settings/ChangePasswordDialog.kt @@ -18,11 +18,9 @@ package org.briarproject.briar.desktop.settings -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.AlertDialog @@ -38,7 +36,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusDirection import androidx.compose.ui.focus.FocusRequester @@ -46,10 +43,9 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.unit.dp import org.briarproject.bramble.api.crypto.DecryptionResult import org.briarproject.bramble.api.crypto.DecryptionResult.INVALID_PASSWORD -import org.briarproject.briar.desktop.login.StrengthMeter +import org.briarproject.briar.desktop.login.PasswordForm import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n import org.briarproject.briar.desktop.utils.PreviewUtils.preview import java.lang.Float.min @@ -162,17 +158,17 @@ fun ChangePasswordDialog( }, text = { PasswordForm( - oldPassword, - setOldPassword, - password, - setPassword, - passwordConfirmation, - setPasswordConfirmation, - passwordStrength, - passwordTooWeakError, - passwordsDontMatchError, - onSubmit, - submitError, + oldPassword = oldPassword, + setOldPassword = setOldPassword, + password = password, + setPassword = setPassword, + passwordConfirmation = passwordConfirmation, + setPasswordConfirmation = setPasswordConfirmation, + passwordStrength = passwordStrength, + passwordTooWeakError = passwordTooWeakError, + passwordsDontMatchError = passwordsDontMatchError, + onSubmit = onSubmit, + submitError = submitError, ) }, dismissButton = { @@ -205,7 +201,7 @@ fun PasswordForm( passwordTooWeakError: Boolean, passwordsDontMatchError: Boolean, onSubmit: () -> Unit, - onSubmitError: DecryptionResult?, + submitError: DecryptionResult?, ) { val initialFocusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current @@ -216,43 +212,25 @@ fun PasswordForm( onValueChange = setOldPassword, label = { Text(i18n("settings.security.password.current")) }, singleLine = true, - isError = onSubmitError == INVALID_PASSWORD, + isError = submitError == INVALID_PASSWORD, showErrorWhen = InitialFocusState.FROM_START, errorMessage = i18n("startup.error.password_wrong"), keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Next), modifier = Modifier.fillMaxWidth().focusRequester(initialFocusRequester), onEnter = { focusManager.moveFocus(FocusDirection.Next) }, ) - Box( - modifier = Modifier.fillMaxWidth().requiredHeight(24.dp), - contentAlignment = Alignment.Center - ) { - if (password.isNotEmpty()) - StrengthMeter(passwordStrength, Modifier.fillMaxWidth()) - } - OutlinedPasswordTextField( - value = password, - onValueChange = setPassword, - label = { Text(i18n("settings.security.password.choose")) }, - singleLine = true, - isError = passwordTooWeakError, - showErrorWhen = InitialFocusState.AFTER_FOCUS_LOST_ONCE, - errorMessage = i18n("startup.error.password_too_weak"), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Next), - modifier = Modifier.fillMaxWidth(), - onEnter = { focusManager.moveFocus(FocusDirection.Next) }, - ) - OutlinedPasswordTextField( - value = passwordConfirmation, - onValueChange = setPasswordConfirmation, - label = { Text(i18n("settings.security.password.confirm")) }, - singleLine = true, - isError = passwordsDontMatchError, - showErrorWhen = InitialFocusState.AFTER_FIRST_FOCUSSED, - errorMessage = i18n("startup.error.passwords_not_match"), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password, imeAction = ImeAction.Done), - modifier = Modifier.fillMaxWidth(), - onEnter = onSubmit, + PasswordForm( + focusManager = focusManager, + keyLabelPassword = "settings.security.password.choose", + keyLabelPasswordConfirmation = "settings.security.password.confirm", + password = password, + setPassword = setPassword, + passwordConfirmation = passwordConfirmation, + setPasswordConfirmation = setPasswordConfirmation, + passwordStrength = passwordStrength, + passwordTooWeakError = passwordTooWeakError, + passwordsDontMatchError = passwordsDontMatchError, + onSubmit = onSubmit, ) }