From bed34f3e2dca9f2a6262c278405d584d62c934eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20G=C3=B6ransson?= Date: Tue, 17 Oct 2023 11:49:21 +0200 Subject: [PATCH] Fix DPad navigation and align dialog styles --- .../compose/dialog/CustomPortDialog.kt | 3 +- .../mullvadvpn/compose/dialog/DnsDialog.kt | 101 +++++------- .../mullvadvpn/compose/dialog/MtuDialog.kt | 95 ++++------- .../compose/dialog/RedeemVoucherDialog.kt | 52 +++--- .../compose/textfield/CustomPortTextField.kt | 1 - .../compose/textfield/CustomTextField.kt | 152 ++++-------------- .../compose/textfield/DnsTextField.kt | 12 +- .../compose/textfield/GroupedTextField.kt | 13 +- .../compose/textfield/MtuTextField.kt | 2 - 9 files changed, 129 insertions(+), 302 deletions(-) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomPortDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomPortDialog.kt index a5d886de2e7b..69c5a95ba1c9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomPortDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomPortDialog.kt @@ -2,6 +2,7 @@ package net.mullvad.mullvadvpn.compose.dialog import androidx.compose.foundation.layout.Column 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.material3.AlertDialog @@ -99,7 +100,7 @@ fun CustomPortDialog( port.value.isNotEmpty() && allowedPortRanges.isPortInValidRanges(port.value.toIntOrNull() ?: 0), maxCharLength = 5, - modifier = Modifier.testTag(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG) + modifier = Modifier.testTag(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG).fillMaxWidth() ) Spacer(modifier = Modifier.height(Dimens.smallPadding)) Text( diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt index 4312b239af85..0c83bfba10b9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt @@ -1,25 +1,18 @@ package net.mullvad.mullvadvpn.compose.dialog -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.textfield.DnsTextField @@ -94,57 +87,31 @@ fun DnsDialog( onRemove: () -> Unit, onDismiss: () -> Unit ) { - val mediumPadding = Dimens.mediumPadding - val dialogPadding = 20.dp - val midPadding = 10.dp - val smallPadding = 5.dp - - val textFieldFocusRequester = FocusRequester() - - Dialog( - // Fix for https://issuetracker.google.com/issues/221643630 - properties = DialogProperties(usePlatformDefaultWidth = false), - onDismissRequest = onDismiss, - content = { - Column( - Modifier - // Related to the fix for https://issuetracker.google.com/issues/221643630 - .fillMaxWidth(0.8f) - .background( - color = MaterialTheme.colorScheme.background, - shape = MaterialTheme.shapes.extraLarge - ) - .padding(dialogPadding) - ) { - Text( - text = - if (stagedDns is StagedDns.NewDns) { - stringResource(R.string.add_dns_server_dialog_title) - } else { - stringResource(R.string.update_dns_server_dialog_title) - }, - color = Color.White, - style = - MaterialTheme.typography.headlineSmall.copy(fontWeight = FontWeight.Normal) + AlertDialog( + title = { + Text( + text = + if (stagedDns is StagedDns.NewDns) { + stringResource(R.string.add_dns_server_dialog_title) + } else { + stringResource(R.string.update_dns_server_dialog_title) + }, + color = Color.White, + style = MaterialTheme.typography.headlineSmall.copy(fontWeight = FontWeight.Normal) + ) + }, + text = { + Column { + DnsTextField( + value = stagedDns.item.address, + isValidValue = stagedDns.isValid(), + onValueChanged = { newMtuValue -> onIpAddressChanged(newMtuValue) }, + onSubmit = { onAttemptToSave() }, + isEnabled = true, + placeholderText = stringResource(R.string.custom_dns_hint), + modifier = Modifier.fillMaxWidth() ) - Box( - Modifier.wrapContentSize().clickable { textFieldFocusRequester.requestFocus() } - ) { - DnsTextField( - value = stagedDns.item.address, - isValidValue = stagedDns.isValid(), - onValueChanged = { newMtuValue -> onIpAddressChanged(newMtuValue) }, - onFocusChanges = {}, - onSubmit = { onAttemptToSave() }, - isEnabled = true, - placeholderText = stringResource(R.string.custom_dns_hint), - modifier = - Modifier.padding(top = midPadding) - .focusRequester(textFieldFocusRequester) - ) - } - val errorMessage = when { stagedDns.validationResult is @@ -164,12 +131,15 @@ fun DnsDialog( text = errorMessage, style = MaterialTheme.typography.bodySmall, color = MullvadRed, - modifier = Modifier.padding(top = smallPadding) + modifier = Modifier.padding(top = Dimens.smallPadding) ) } - + } + }, + confirmButton = { + Column(verticalArrangement = Arrangement.spacedBy(Dimens.mediumPadding)) { PrimaryButton( - modifier = Modifier.padding(top = mediumPadding), + modifier = Modifier.fillMaxWidth(), onClick = onAttemptToSave, isEnabled = stagedDns.isValid(), text = stringResource(id = R.string.submit_button), @@ -177,18 +147,21 @@ fun DnsDialog( if (stagedDns is StagedDns.EditDns) { PrimaryButton( - modifier = Modifier.padding(top = mediumPadding), + modifier = Modifier.fillMaxWidth(), onClick = onRemove, text = stringResource(id = R.string.remove_button) ) } PrimaryButton( - modifier = Modifier.padding(top = mediumPadding), + modifier = Modifier.fillMaxWidth(), onClick = onDismiss, text = stringResource(id = R.string.cancel) ) } - } + }, + onDismissRequest = onDismiss, + containerColor = MaterialTheme.colorScheme.background, + titleContentColor = MaterialTheme.colorScheme.onBackground, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/MtuDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/MtuDialog.kt index 82773f079df3..5877964ec8cc 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/MtuDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/MtuDialog.kt @@ -1,25 +1,17 @@ package net.mullvad.mullvadvpn.compose.dialog -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.textfield.MtuTextField @@ -45,59 +37,37 @@ fun MtuDialog( onRestoreDefaultValue: () -> Unit, onDismiss: () -> Unit, ) { - val dialogPadding = 20.dp - val midPadding = 10.dp - val smallPadding = 5.dp - val mtu = remember { mutableStateOf(mtuInitial?.toString() ?: "") } - val textFieldFocusRequester = FocusRequester() val isValidMtu = mtu.value.toIntOrNull()?.isValidMtu() == true - Dialog( - // Fix for https://issuetracker.google.com/issues/221643630 - properties = DialogProperties(usePlatformDefaultWidth = false), - onDismissRequest = { onDismiss() }, - content = { - Column( - Modifier - // Related to the fix for https://issuetracker.google.com/issues/221643630 - .fillMaxWidth(0.8f) - .background( - color = MaterialTheme.colorScheme.background, - shape = MaterialTheme.shapes.extraLarge - ) - .padding(dialogPadding) - ) { - Text( - text = stringResource(id = R.string.wireguard_mtu), - color = MaterialTheme.colorScheme.onBackground, - style = MaterialTheme.typography.headlineSmall + AlertDialog( + onDismissRequest = onDismiss, + title = { + Text( + text = stringResource(id = R.string.wireguard_mtu), + color = MaterialTheme.colorScheme.onBackground, + style = MaterialTheme.typography.headlineSmall + ) + }, + text = { + Column { + MtuTextField( + value = mtu.value, + onValueChanged = { newMtuValue -> mtu.value = newMtuValue }, + onSubmit = { newMtuValue -> + val mtuInt = newMtuValue.toIntOrNull() + if (mtuInt?.isValidMtu() == true) { + onSave(mtuInt) + } + }, + isEnabled = true, + placeholderText = stringResource(R.string.enter_value_placeholder), + maxCharLength = 4, + isValidValue = isValidMtu, + modifier = Modifier.fillMaxWidth() ) - Box( - Modifier.wrapContentSize().clickable { textFieldFocusRequester.requestFocus() } - ) { - MtuTextField( - value = mtu.value, - onValueChanged = { newMtuValue -> mtu.value = newMtuValue }, - onFocusChange = {}, - onSubmit = { newMtuValue -> - val mtuInt = newMtuValue.toIntOrNull() - if (mtuInt?.isValidMtu() == true) { - onSave(mtuInt) - } - }, - isEnabled = true, - placeholderText = stringResource(R.string.enter_value_placeholder), - maxCharLength = 4, - isValidValue = isValidMtu, - modifier = - Modifier.padding(top = midPadding) - .focusRequester(textFieldFocusRequester) - ) - } - Text( text = stringResource( @@ -107,11 +77,14 @@ fun MtuDialog( ), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onBackground.copy(alpha = AlphaDescription), - modifier = Modifier.padding(top = smallPadding) + modifier = Modifier.padding(top = Dimens.smallPadding) ) - + } + }, + confirmButton = { + Column { PrimaryButton( - modifier = Modifier.padding(top = Dimens.mediumPadding).fillMaxWidth(), + modifier = Modifier.fillMaxWidth(), isEnabled = isValidMtu, text = stringResource(R.string.submit_button), onClick = { @@ -134,6 +107,8 @@ fun MtuDialog( onClick = onDismiss ) } - } + }, + containerColor = MaterialTheme.colorScheme.background, + titleContentColor = MaterialTheme.colorScheme.onBackground, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt index a7a7273555d9..1f86eedc644b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt @@ -2,8 +2,6 @@ package net.mullvad.mullvadvpn.compose.dialog import android.content.res.Configuration import androidx.compose.foundation.Image -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -11,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.material3.AlertDialog import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme @@ -19,9 +16,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource @@ -34,12 +28,12 @@ import net.mullvad.mullvadvpn.compose.button.VariantButton import net.mullvad.mullvadvpn.compose.state.VoucherDialogState import net.mullvad.mullvadvpn.compose.state.VoucherDialogUiState import net.mullvad.mullvadvpn.compose.textfield.GroupedTextField +import net.mullvad.mullvadvpn.compose.util.MAX_VOUCHER_LENGTH import net.mullvad.mullvadvpn.compose.util.vouchersVisualTransformation import net.mullvad.mullvadvpn.constant.VOUCHER_LENGTH import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.lib.theme.color.AlphaDescription -import net.mullvad.mullvadvpn.lib.theme.color.AlphaDisabled import org.joda.time.DateTimeConstants @Preview(device = Devices.TV_720p) @@ -216,32 +210,24 @@ private fun EnterVoucherBody( onVoucherInputChange: (String) -> Unit = {}, onRedeem: (voucherCode: String) -> Unit ) { - val textFieldFocusRequester = FocusRequester() - Box(Modifier.wrapContentSize().clickable { textFieldFocusRequester.requestFocus() }) { - GroupedTextField( - value = uiState.voucherInput, - onSubmit = { input -> - if (uiState.voucherInput.length == VOUCHER_LENGTH) { - onRedeem(input) - } - }, - onValueChanged = { input -> onVoucherInputChange(input.uppercase()) }, - isValidValue = uiState.voucherInput.isNotEmpty(), - keyboardType = KeyboardType.Password, - placeholderText = stringResource(id = R.string.voucher_hint), - placeHolderColor = - MaterialTheme.colorScheme.onPrimary - .copy(alpha = AlphaDisabled) - .compositeOver(MaterialTheme.colorScheme.primary), - visualTransformation = vouchersVisualTransformation(), - maxCharLength = VOUCHER_LENGTH, - onFocusChange = {}, - isDigitsOnlyAllowed = false, - isEnabled = true, - modifier = Modifier.focusRequester(textFieldFocusRequester), - validateRegex = "^[A-Za-z0-9]*$".toRegex() - ) - } + GroupedTextField( + value = uiState.voucherInput, + onSubmit = { input -> + if (uiState.voucherInput.length == VOUCHER_LENGTH) { + onRedeem(input) + } + }, + onValueChanged = { input -> onVoucherInputChange(input.uppercase()) }, + isValidValue = + uiState.voucherInput.isEmpty() || uiState.voucherInput.length == MAX_VOUCHER_LENGTH, + keyboardType = KeyboardType.Password, + placeholderText = stringResource(id = R.string.voucher_hint), + visualTransformation = vouchersVisualTransformation(), + maxCharLength = VOUCHER_LENGTH, + isDigitsOnlyAllowed = false, + isEnabled = true, + validateRegex = "^[A-Za-z0-9]*$".toRegex() + ) Spacer(modifier = Modifier.height(Dimens.smallPadding)) Row( verticalAlignment = Alignment.CenterVertically, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomPortTextField.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomPortTextField.kt index e1478e198716..72d8b950935f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomPortTextField.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomPortTextField.kt @@ -21,7 +21,6 @@ fun CustomPortTextField( modifier = modifier, placeholderText = stringResource(id = R.string.custom_port_dialog_placeholder), onValueChanged = onValueChanged, - onFocusChange = {}, onSubmit = onSubmit, isDigitsOnlyAllowed = true, isEnabled = true, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomTextField.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomTextField.kt index 619b5ee4ed05..5a490af717ab 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomTextField.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomTextField.kt @@ -1,172 +1,82 @@ package net.mullvad.mullvadvpn.compose.textfield import android.text.TextUtils -import android.view.KeyEvent -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.TextField import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.focus.FocusDirection -import androidx.compose.ui.focus.onFocusChanged -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.input.key.onKeyEvent -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.text.TextStyle +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.text.input.VisualTransformation -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.lib.theme.color.MullvadBlue -import net.mullvad.mullvadvpn.lib.theme.color.MullvadWhite10 +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch private const val EMPTY_STRING = "" private const val NEWLINE_STRING = "\n" @Composable -@OptIn(ExperimentalComposeUiApi::class) fun CustomTextField( value: String, keyboardType: KeyboardType, modifier: Modifier = Modifier, onValueChanged: (String) -> Unit, - onFocusChange: (Boolean) -> Unit, onSubmit: (String) -> Unit, isEnabled: Boolean = true, - placeholderText: String = "", - placeHolderColor: Color = MullvadBlue, + placeholderText: String?, maxCharLength: Int = Int.MAX_VALUE, isValidValue: Boolean, isDigitsOnlyAllowed: Boolean, - defaultTextColor: Color = Color.White, - textAlign: TextAlign = TextAlign.Start, visualTransformation: VisualTransformation = VisualTransformation.None ) { - val fontSize = dimensionResource(id = R.dimen.text_medium_plus).value.sp - val shape = RoundedCornerShape(4.dp) - val textFieldHeight = 44.dp - val focusManager = LocalFocusManager.current - val keyboardController = LocalSoftwareKeyboardController.current + val scope = rememberCoroutineScope() - var isFocused by remember { mutableStateOf(false) } + // Pass initial text range ensure cursor position is correct when entering a TextField with a + // preexisting value + val textRange = remember { mutableStateOf(TextRange(value.length)) } - val textColor = - when { - isValidValue.not() -> Color.Red - isFocused -> MullvadBlue - else -> defaultTextColor - } - - val placeholderTextColor = - if (isFocused) { - placeHolderColor - } else { - Color.White - } - - val backgroundColor = - if (isFocused) { - Color.White - } else { - MullvadWhite10 - } - - fun triggerSubmit() { - keyboardController?.hide() - focusManager.moveFocus(FocusDirection.Previous) - onSubmit(value) - } - - BasicTextField( - value = value, + TextField( + value = TextFieldValue(value, textRange.value), onValueChange = { input -> - val isValidInput = if (isDigitsOnlyAllowed) TextUtils.isDigitsOnly(input) else true - if (input.length <= maxCharLength && isValidInput) { + val isValidInput = if (isDigitsOnlyAllowed) TextUtils.isDigitsOnly(input.text) else true + if (input.text.length <= maxCharLength && isValidInput) { // Remove any newline chars added by enter key clicks - onValueChanged(input.replace(NEWLINE_STRING, EMPTY_STRING)) + textRange.value = input.selection + onValueChanged(input.text.replace(NEWLINE_STRING, EMPTY_STRING)) } }, - textStyle = TextStyle(color = textColor, fontSize = fontSize, textAlign = textAlign), enabled = isEnabled, singleLine = true, - maxLines = 1, + placeholder = placeholderText?.let { { Text(text = it) } }, keyboardOptions = KeyboardOptions( keyboardType = keyboardType, imeAction = ImeAction.Done, autoCorrect = false, ), - keyboardActions = KeyboardActions(onDone = { triggerSubmit() }), - decorationBox = { decorationBox -> - Box(modifier = Modifier.padding(PaddingValues(12.dp, 10.dp)).fillMaxWidth()) { - if (value.isBlank()) { - Text( - text = placeholderText, - color = placeholderTextColor, - style = TextStyle(fontSize = fontSize, textAlign = textAlign), - fontSize = fontSize, - textAlign = textAlign, - modifier = Modifier.fillMaxWidth() - ) - } - decorationBox() - } - }, - cursorBrush = SolidColor(MullvadBlue), - visualTransformation = visualTransformation, - modifier = - modifier - .background(backgroundColor) - .clip(shape) - .onFocusChanged { focusState -> - isFocused = focusState.isFocused - onFocusChange(focusState.isFocused) - } - .height(textFieldHeight) - .onKeyEvent { keyEvent -> - return@onKeyEvent when (keyEvent.nativeKeyEvent.keyCode) { - KeyEvent.KEYCODE_ENTER -> { - triggerSubmit() - true - } - KeyEvent.KEYCODE_ESCAPE -> { - focusManager.clearFocus(force = true) - keyboardController?.hide() - true - } - KeyEvent.KEYCODE_DPAD_DOWN -> { - focusManager.moveFocus(FocusDirection.Down) - true - } - KeyEvent.KEYCODE_DPAD_UP -> { - focusManager.moveFocus(FocusDirection.Up) - true - } - else -> { - false - } + keyboardActions = + KeyboardActions( + onDone = { + scope.launch { + // https://issuetracker.google.com/issues/305518328 + delay(100) + onSubmit(value) } } + ), + visualTransformation = visualTransformation, + colors = mullvadDarkTextFieldColors(), + isError = !isValidValue, + modifier = modifier.clip(MaterialTheme.shapes.small).fillMaxWidth() ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/DnsTextField.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/DnsTextField.kt index bbd9755d2b94..d7aec9e417c7 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/DnsTextField.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/DnsTextField.kt @@ -3,31 +3,27 @@ package net.mullvad.mullvadvpn.compose.textfield import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.text.style.TextAlign @Composable fun DnsTextField( value: String, - isValidValue: Boolean, modifier: Modifier = Modifier, onValueChanged: (String) -> Unit = {}, - onFocusChanges: (Boolean) -> Unit = {}, onSubmit: (String) -> Unit = {}, - placeholderText: String = "", - isEnabled: Boolean = true + placeholderText: String?, + isEnabled: Boolean = true, + isValidValue: Boolean = true ) { CustomTextField( value = value, keyboardType = KeyboardType.Text, modifier = modifier, onValueChanged = onValueChanged, - onFocusChange = onFocusChanges, onSubmit = onSubmit, isEnabled = isEnabled, placeholderText = placeholderText, maxCharLength = Int.MAX_VALUE, - isValidValue = isValidValue, isDigitsOnlyAllowed = false, - textAlign = TextAlign.Start + isValidValue = isValidValue ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/GroupedTextField.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/GroupedTextField.kt index d9fcecc597f3..5bc0a8ff867b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/GroupedTextField.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/GroupedTextField.kt @@ -1,12 +1,9 @@ package net.mullvad.mullvadvpn.compose.textfield -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.VisualTransformation -import androidx.compose.ui.text.style.TextAlign @Composable fun GroupedTextField( @@ -14,34 +11,26 @@ fun GroupedTextField( keyboardType: KeyboardType, modifier: Modifier = Modifier, onValueChanged: (String) -> Unit, - onFocusChange: (Boolean) -> Unit, onSubmit: (String) -> Unit, isEnabled: Boolean = true, visualTransformation: VisualTransformation, placeholderText: String = "", - placeHolderColor: Color = MaterialTheme.colorScheme.primary, maxCharLength: Int = Int.MAX_VALUE, isValidValue: Boolean, isDigitsOnlyAllowed: Boolean, validateRegex: Regex, - defaultTextColor: Color = MaterialTheme.colorScheme.onPrimary, - textAlign: TextAlign = TextAlign.Start ) { CustomTextField( value = value, keyboardType = keyboardType, onValueChanged = { if (validateRegex.matches(it)) onValueChanged(it) }, - onFocusChange = onFocusChange, onSubmit = onSubmit, - isValidValue = isValidValue, isDigitsOnlyAllowed = isDigitsOnlyAllowed, modifier = modifier, isEnabled = isEnabled, visualTransformation = visualTransformation, placeholderText = placeholderText, - placeHolderColor = placeHolderColor, maxCharLength = maxCharLength, - defaultTextColor = defaultTextColor, - textAlign = textAlign + isValidValue = isValidValue, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/MtuTextField.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/MtuTextField.kt index 4e6e4fc63c28..8df93d7b86a4 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/MtuTextField.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/MtuTextField.kt @@ -10,7 +10,6 @@ fun MtuTextField( isValidValue: Boolean, modifier: Modifier = Modifier, onValueChanged: (String) -> Unit = {}, - onFocusChange: (Boolean) -> Unit = {}, onSubmit: (String) -> Unit = {}, isEnabled: Boolean = true, placeholderText: String = "", @@ -21,7 +20,6 @@ fun MtuTextField( keyboardType = KeyboardType.Number, modifier = modifier, onValueChanged = onValueChanged, - onFocusChange = onFocusChange, onSubmit = onSubmit, isEnabled = isEnabled, placeholderText = placeholderText,