summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson90@gmail.com>2023-10-17 11:49:21 +0200
committerDavid Göransson <david.goransson90@gmail.com>2023-10-23 15:26:39 +0200
commitf0e3d0e0a88fb20e2c36a68700e39770badbfeba (patch)
tree4e8558b11d0ac933b2d29d8e04d49d3732ec2b00 /android
parentbb76fbc01bc40d467139b058d61df9cd5a314baa (diff)
downloadmullvadvpn-f0e3d0e0a88fb20e2c36a68700e39770badbfeba.tar.xz
mullvadvpn-f0e3d0e0a88fb20e2c36a68700e39770badbfeba.zip
Fix DPad navigation and align dialog styles
Diffstat (limited to 'android')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CustomPortDialog.kt3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt101
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/MtuDialog.kt95
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/RedeemVoucherDialog.kt52
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomPortTextField.kt1
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/CustomTextField.kt152
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/DnsTextField.kt12
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/GroupedTextField.kt13
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/textfield/MtuTextField.kt2
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 a5d886de2e..69c5a95ba1 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 4312b239af..0c83bfba10 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 82773f079d..5877964ec8 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 a7a7273555..1f86eedc64 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 e1478e1987..72d8b95093 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 619b5ee4ed..5a490af717 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 bbd9755d2b..d7aec9e417 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 d9fcecc597..5bc0a8ff86 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 4e6e4fc63c..8df93d7b86 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,