Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to SecureTextField #1191

Open
wants to merge 2 commits into
base: main-ose
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Card
Expand All @@ -22,10 +22,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
Expand All @@ -34,7 +31,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
Expand All @@ -49,11 +45,10 @@ fun EditTextInputDialog(
onValueEntered: (String) -> Unit = {},
onDismiss: () -> Unit = {},
) {
var textValue by remember {
mutableStateOf(TextFieldValue(
initialValue ?: "", selection = TextRange(initialValue?.length ?: 0)
))
}
val state = rememberTextFieldState(
initialText = initialValue ?: "",
initialSelection = TextRange(initialValue?.length ?: 0)
)

AlertDialog(
onDismissRequest = onDismiss,
Expand All @@ -67,27 +62,22 @@ fun EditTextInputDialog(
val focusRequester = remember { FocusRequester() }
if (passwordField)
PasswordTextField(
password = textValue.text,
password = state,
labelText = inputLabel,
onPasswordChange = { textValue = TextFieldValue(it) },
modifier = Modifier.focusRequester(focusRequester)
)
else
TextField(
label = { inputLabel?.let { Text(it) } },
value = textValue,
onValueChange = { textValue = it },
singleLine = true,
state = state,
keyboardOptions = KeyboardOptions(
keyboardType = keyboardType,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = {
onValueEntered(textValue.text)
onDismiss()
}
),
onKeyboardAction = {
onValueEntered(state.text.toString())
onDismiss()
},
modifier = Modifier.focusRequester(focusRequester)
)
LaunchedEffect(Unit) {
Expand All @@ -97,10 +87,10 @@ fun EditTextInputDialog(
confirmButton = {
Button(
onClick = {
onValueEntered(textValue.text)
onValueEntered(state.text.toString())
onDismiss()
},
enabled = textValue.text != initialValue
enabled = state.text != initialValue
) {
Text(stringResource(android.R.string.ok))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@
package at.bitfire.davdroid.ui.composable

import androidx.compose.foundation.focusGroup
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.KeyboardActionHandler
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.TextObfuscationMode
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material.icons.filled.VisibilityOff
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedSecureTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
Expand All @@ -22,39 +25,32 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import at.bitfire.davdroid.R

@Composable
fun PasswordTextField(
password: String,
password: TextFieldState,
labelText: String?,
onPasswordChange: (String) -> Unit,
modifier: Modifier = Modifier,
leadingIcon: @Composable (() -> Unit)? = null,
keyboardOptions: KeyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
keyboardActions: KeyboardActions = KeyboardActions.Default,
onKeyboardAction: KeyboardActionHandler? = null,
enabled: Boolean = true,
readOnly: Boolean = false,
isError: Boolean = false
) {
var passwordVisible by remember { mutableStateOf(false) }

OutlinedTextField(
value = password,
onValueChange = onPasswordChange,
OutlinedSecureTextField(
state = password,
label = labelText?.let { { Text(it) } },
leadingIcon = leadingIcon,
isError = isError,
singleLine = true,
enabled = enabled,
readOnly = readOnly,
modifier = modifier.focusGroup(),
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
onKeyboardAction = onKeyboardAction,
textObfuscationMode = if (passwordVisible) TextObfuscationMode.Visible else TextObfuscationMode.RevealLastTyped,
trailingIcon = {
IconButton(
enabled = enabled,
Expand All @@ -73,46 +69,42 @@ fun PasswordTextField(
@Preview
fun PasswordTextField_Sample() {
PasswordTextField(
password = "",
password = rememberTextFieldState(""),
labelText = "labelText",
enabled = true,
isError = false,
onPasswordChange = {},
)
}

@Composable
@Preview
fun PasswordTextField_Sample_Filled() {
PasswordTextField(
password = "password",
password = rememberTextFieldState("password"),
labelText = "labelText",
enabled = true,
isError = false,
onPasswordChange = {},
)
}

@Composable
@Preview
fun PasswordTextField_Sample_Error() {
PasswordTextField(
password = "password",
password = rememberTextFieldState("password"),
labelText = "labelText",
enabled = true,
isError = true,
onPasswordChange = {},
)
}

@Composable
@Preview
fun PasswordTextField_Sample_Disabled() {
PasswordTextField(
password = "password",
password = rememberTextFieldState("password"),
labelText = "labelText",
enabled = false,
isError = false,
onPasswordChange = {},
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Folder
Expand Down Expand Up @@ -69,7 +71,6 @@ object AdvancedLogin : LoginType {
username = uiState.username,
onSetUsername = model::setUsername,
password = uiState.password,
onSetPassword = model::setPassword,
certAlias = uiState.certAlias,
onSetCertAlias = model::setCertAlias,
canContinue = uiState.canContinue,
Expand All @@ -88,8 +89,7 @@ fun AdvancedLoginScreen(
onSetUrl: (String) -> Unit = {},
username: String,
onSetUsername: (String) -> Unit = {},
password: String,
onSetPassword: (String) -> Unit = {},
password: TextFieldState,
certAlias: String,
onSetCertAlias: (String) -> Unit = {},
canContinue: Boolean,
Expand Down Expand Up @@ -158,7 +158,6 @@ fun AdvancedLoginScreen(

PasswordTextField(
password = password,
onPasswordChange = onSetPassword,
labelText = stringResource(R.string.login_password_optional),
leadingIcon = {
Icon(Icons.Default.Password, null)
Expand Down Expand Up @@ -199,7 +198,7 @@ fun AdvancedLoginScreen_Preview_Empty() {
snackbarHostState = SnackbarHostState(),
url = "",
username = "",
password = "",
password = rememberTextFieldState(""),
certAlias = "",
canContinue = false
)
Expand All @@ -212,7 +211,7 @@ fun AdvancedLoginScreen_Preview_AllFilled() {
snackbarHostState = SnackbarHostState(),
url = "dav.example.com",
username = "someuser",
password = "password",
password = rememberTextFieldState("password"),
certAlias = "someCert",
canContinue = true
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package at.bitfire.davdroid.ui.setup

import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
Expand All @@ -29,7 +30,7 @@ class AdvancedLoginModel @AssistedInject constructor(
data class UiState(
val url: String = "",
val username: String = "",
val password: String = "",
val password: TextFieldState = TextFieldState(),
val certAlias: String = ""
) {

Expand All @@ -46,7 +47,7 @@ class AdvancedLoginModel @AssistedInject constructor(
baseUri = uri,
credentials = Credentials(
username = username.trimToNull(),
password = password.trimToNull(),
password = password.text.toString().trimToNull(),
certificateAlias = certAlias.trimToNull()
)
)
Expand All @@ -60,7 +61,7 @@ class AdvancedLoginModel @AssistedInject constructor(
uiState = uiState.copy(
url = initialLoginInfo.baseUri?.toString()?.removePrefix("https://") ?: "",
username = initialLoginInfo.credentials?.username ?: "",
password = initialLoginInfo.credentials?.password ?: "",
password = TextFieldState(initialLoginInfo.credentials?.password ?: ""),
certAlias = initialLoginInfo.credentials?.certificateAlias ?: ""
)
}
Expand All @@ -73,10 +74,6 @@ class AdvancedLoginModel @AssistedInject constructor(
uiState = uiState.copy(username = username)
}

fun setPassword(password: String) {
uiState = uiState.copy(password = password)
}

fun setCertAlias(certAlias: String) {
uiState = uiState.copy(certAlias = certAlias)
}
Expand Down
14 changes: 5 additions & 9 deletions app/src/main/kotlin/at/bitfire/davdroid/ui/setup/EmailLogin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import android.net.Uri
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Email
import androidx.compose.material.icons.filled.Password
Expand Down Expand Up @@ -63,7 +64,6 @@ object EmailLogin : LoginType {
email = uiState.email,
onSetEmail = model::setEmail,
password = uiState.password,
onSetPassword = model::setPassword,
canContinue = uiState.canContinue,
onLogin = { onLogin(uiState.asLoginInfo()) }
)
Expand All @@ -76,8 +76,7 @@ object EmailLogin : LoginType {
fun EmailLoginScreen(
email: String,
onSetEmail: (String) -> Unit = {},
password: String,
onSetPassword: (String) -> Unit = {},
password: TextFieldState,
canContinue: Boolean,
onLogin: () -> Unit = {}
) {
Expand Down Expand Up @@ -131,7 +130,6 @@ fun EmailLoginScreen(

PasswordTextField(
password = password,
onPasswordChange = onSetPassword,
labelText = stringResource(R.string.login_password),
leadingIcon = {
Icon(Icons.Default.Password, null)
Expand All @@ -140,9 +138,7 @@ fun EmailLoginScreen(
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = { onLogin() }
),
onKeyboardAction = { onLogin() },
modifier = Modifier.fillMaxWidth()
)
}
Expand All @@ -155,7 +151,7 @@ fun EmailLoginScreen(
fun EmailLoginScreen_Preview() {
EmailLoginScreen(
email = "[email protected]",
password = "",
password = rememberTextFieldState(""),
canContinue = false
)
}
Loading
Loading