11package app.k9mail.feature.account.server.settings.ui.common
22
3- import androidx.biometric.BiometricPrompt
3+ import androidx.annotation.StringRes
44import androidx.compose.foundation.layout.PaddingValues
55import androidx.compose.foundation.layout.fillMaxWidth
66import androidx.compose.runtime.Composable
@@ -11,62 +11,71 @@ import androidx.compose.runtime.remember
1111import androidx.compose.runtime.setValue
1212import androidx.compose.ui.Modifier
1313import androidx.compose.ui.res.stringResource
14- import androidx.fragment.app.FragmentActivity
1514import app.k9mail.core.ui.compose.designsystem.molecule.input.InputLayout
16- import app.k9mail.core.ui.compose.designsystem.molecule.input.PasswordInput
1715import app.k9mail.core.ui.compose.designsystem.molecule.input.inputContentPadding
1816import app.k9mail.feature.account.server.settings.R
1917import kotlinx.coroutines.delay
18+ import net.thunderbird.feature.account.server.settings.ui.common.AuthenticationError
19+ import net.thunderbird.feature.account.server.settings.ui.common.Authenticator
20+ import net.thunderbird.feature.account.server.settings.ui.common.rememberBiometricAuthenticator
2021import app.k9mail.core.ui.compose.designsystem.R as RDesign
2122
2223private const val SHOW_WARNING_DURATION = 5000L
2324
2425/* *
2526 * Variant of [PasswordInput] that only allows the password to be unmasked after the user has authenticated using
26- * [BiometricPrompt].
27- *
28- * Note: Due to limitations of [BiometricPrompt] this composable can only be used inside a [FragmentActivity].
27+ * [Authenticator] that defaults to [rememberBiometricAuthenticator].
2928 */
3029@Composable
31- fun BiometricPasswordInput (
30+ fun ProtectedPasswordInput (
3231 onPasswordChange : (String ) -> Unit ,
3332 modifier : Modifier = Modifier ,
3433 password : String = "",
3534 isRequired : Boolean = false,
3635 errorMessage : String? = null,
3736 contentPadding : PaddingValues = inputContentPadding(),
37+ authenticator : Authenticator = rememberBiometricAuthenticator(
38+ title = stringResource(R .string.account_server_settings_password_authentication_title),
39+ subtitle = stringResource(R .string.account_server_settings_password_authentication_subtitle),
40+ ),
3841) {
39- var biometricWarning by remember { mutableStateOf<String ?>(value = null ) }
42+ var authenticationError by remember { mutableStateOf<AuthenticationError ?>(value = null ) }
43+ val authenticationWarning = authenticationError?.let { stringResource(it.mapToStringRes()) }
4044
41- LaunchedEffect (key1 = biometricWarning ) {
42- if (biometricWarning != null ) {
45+ LaunchedEffect (key1 = authenticationError ) {
46+ if (authenticationError != null ) {
4347 delay(SHOW_WARNING_DURATION )
44- biometricWarning = null
48+ authenticationError = null
4549 }
4650 }
4751
4852 InputLayout (
4953 modifier = modifier,
5054 contentPadding = contentPadding,
5155 errorMessage = errorMessage,
52- warningMessage = biometricWarning ,
56+ warningMessage = authenticationWarning ,
5357 ) {
54- val title = stringResource(R .string.account_server_settings_password_authentication_title)
55- val subtitle = stringResource(R .string.account_server_settings_password_authentication_subtitle)
56- val needScreenLockMessage =
57- stringResource(R .string.account_server_settings_password_authentication_screen_lock_required)
58-
59- TextFieldOutlinedPasswordBiometric (
58+ ProtectedTextFieldOutlinedPassword (
6059 value = password,
6160 onValueChange = onPasswordChange,
62- authenticationTitle = title,
63- authenticationSubtitle = subtitle,
64- needScreenLockMessage = needScreenLockMessage,
65- onWarningChange = { biometricWarning = it?.toString() },
61+ onWarningChange = { authenticationError = it },
62+ authenticator = authenticator,
6663 label = stringResource(id = RDesign .string.designsystem_molecule_password_input_label),
6764 isRequired = isRequired,
6865 hasError = errorMessage != null ,
6966 modifier = Modifier .fillMaxWidth(),
7067 )
7168 }
7269}
70+
71+ @StringRes
72+ private fun AuthenticationError.mapToStringRes (): Int {
73+ return when (this ) {
74+ AuthenticationError .NotAvailable ->
75+ R .string.account_server_settings_password_authentication_screen_lock_required
76+ AuthenticationError .Failed ->
77+ R .string.account_server_settings_password_authentication_failed
78+ AuthenticationError .UnableToStart ->
79+ R .string.account_server_settings_password_authentication_unable_to_start
80+ }
81+ }
0 commit comments