From 6736da9120b4d405a7a5d3fae95c83ea1009e220 Mon Sep 17 00:00:00 2001 From: Jonatan Rhodin Date: Fri, 8 Mar 2024 16:15:38 +0100 Subject: [PATCH] Fixed some issues with dialogs and improved input field code --- .../component/CustomListNameTextField.kt | 72 ++++++++++++++++++ .../compose/dialog/CreateCustomListDialog.kt | 70 ++++-------------- .../dialog/EditCustomListNameDialog.kt | 74 ++++--------------- 3 files changed, 103 insertions(+), 113 deletions(-) create mode 100644 android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CustomListNameTextField.kt diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CustomListNameTextField.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CustomListNameTextField.kt new file mode 100644 index 000000000000..675f6f8f14dc --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/CustomListNameTextField.kt @@ -0,0 +1,72 @@ +package net.mullvad.mullvadvpn.compose.component + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.focus.onFocusChanged +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.compose.textfield.CustomTextField +import net.mullvad.mullvadvpn.model.CustomListsError + +@Composable +fun CustomListNameTextField( + modifier: Modifier = Modifier, + name: String, + isValidName: Boolean, + error: CustomListsError?, + onValueChanged: (String) -> Unit, + onSubmit: (String) -> Unit +) { + val focusRequester = remember { FocusRequester() } + val keyboardController = LocalSoftwareKeyboardController.current + CustomTextField( + value = name, + onValueChanged = onValueChanged, + onSubmit = { + if (isValidName) { + onSubmit(it) + } + }, + // This can not be set to KeyboardType.Text because it will show the + // suggestions, this will cause an infinite loop on Android TV with Gboard + keyboardType = KeyboardType.Password, + placeholderText = null, + isValidValue = error == null, + isDigitsOnlyAllowed = false, + supportingText = + error?.let { + { + Text( + text = it.errorString(), + color = MaterialTheme.colorScheme.error, + style = MaterialTheme.typography.bodySmall + ) + } + }, + modifier = + modifier.focusRequester(focusRequester).onFocusChanged { focusState -> + if (focusState.hasFocus) { + keyboardController?.show() + } + } + ) + + LaunchedEffect(Unit) { focusRequester.requestFocus() } +} + +@Composable +private fun CustomListsError.errorString() = + stringResource( + when (this) { + CustomListsError.CustomListExists -> R.string.custom_list_error_list_exists + CustomListsError.OtherError -> R.string.error_occurred + } + ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CreateCustomListDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CreateCustomListDialog.kt index 49e0ff1914a7..afabe3139c9b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CreateCustomListDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/CreateCustomListDialog.kt @@ -1,6 +1,6 @@ package net.mullvad.mullvadvpn.compose.dialog -import androidx.compose.foundation.layout.Column +import android.util.Log import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -11,13 +11,8 @@ import androidx.compose.runtime.getValue 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.focus.onFocusChanged -import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.ramcosta.composedestinations.annotation.Destination @@ -27,10 +22,10 @@ import com.ramcosta.composedestinations.spec.DestinationStyle import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.communication.CustomListResult +import net.mullvad.mullvadvpn.compose.component.CustomListNameTextField import net.mullvad.mullvadvpn.compose.destinations.CustomListLocationsDestination import net.mullvad.mullvadvpn.compose.state.CreateCustomListUiState import net.mullvad.mullvadvpn.compose.test.CREATE_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG -import net.mullvad.mullvadvpn.compose.textfield.CustomTextField import net.mullvad.mullvadvpn.lib.theme.AppTheme import net.mullvad.mullvadvpn.model.CustomListsError import net.mullvad.mullvadvpn.viewmodel.CreateCustomListDialogSideEffect @@ -83,6 +78,7 @@ fun CreateCustomList( } } val state by vm.uiState.collectAsStateWithLifecycle() + Log.d("LOLZ", "CreateCustomList: $state") CreateCustomListDialog( state = state, createCustomList = vm::createCustomList, @@ -98,8 +94,7 @@ fun CreateCustomListDialog( onInputChanged: () -> Unit = {}, onDismiss: () -> Unit = {} ) { - val focusRequester = remember { FocusRequester() } - val keyboardController = LocalSoftwareKeyboardController.current + val name = remember { mutableStateOf("") } val isValidName by remember { derivedStateOf { name.value.isNotBlank() } } @@ -110,43 +105,17 @@ fun CreateCustomListDialog( ) }, text = { - Column { - CustomTextField( - value = name.value, - onValueChanged = { - name.value = it - onInputChanged() - }, - onSubmit = { - if (isValidName) { - createCustomList(it) - } - }, - keyboardType = KeyboardType.Text, - placeholderText = "", - isValidValue = state.error == null, - isDigitsOnlyAllowed = false, - supportingText = { - if (state.error != null) { - Text( - text = state.error.errorString(), - color = MaterialTheme.colorScheme.error, - style = MaterialTheme.typography.bodySmall - ) - } - }, - modifier = - Modifier.focusRequester(focusRequester) - .onFocusChanged { focusState -> - if (focusState.hasFocus) { - keyboardController?.show() - } - } - .testTag(CREATE_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG) - ) - } - - LaunchedEffect(Unit) { focusRequester.requestFocus() } + CustomListNameTextField( + name = name.value, + isValidName = isValidName, + error = state.error, + onSubmit = createCustomList, + onValueChanged = { + name.value = it + onInputChanged() + }, + modifier = Modifier.testTag(CREATE_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG) + ) }, containerColor = MaterialTheme.colorScheme.background, titleContentColor = MaterialTheme.colorScheme.onBackground, @@ -163,12 +132,3 @@ fun CreateCustomListDialog( } ) } - -@Composable -private fun CustomListsError.errorString() = - stringResource( - when (this) { - CustomListsError.CustomListExists -> R.string.custom_list_error_list_exists - CustomListsError.OtherError -> R.string.error_occurred - } - ) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/EditCustomListNameDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/EditCustomListNameDialog.kt index 4d7cece88407..14f3edea668b 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/EditCustomListNameDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/EditCustomListNameDialog.kt @@ -1,6 +1,5 @@ package net.mullvad.mullvadvpn.compose.dialog -import androidx.compose.foundation.layout.Column import androidx.compose.material3.AlertDialog import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -11,13 +10,8 @@ import androidx.compose.runtime.getValue 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.focus.onFocusChanged -import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.ramcosta.composedestinations.annotation.Destination @@ -26,11 +20,10 @@ import com.ramcosta.composedestinations.spec.DestinationStyle import net.mullvad.mullvadvpn.R import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.communication.CustomListResult +import net.mullvad.mullvadvpn.compose.component.CustomListNameTextField import net.mullvad.mullvadvpn.compose.state.UpdateCustomListUiState import net.mullvad.mullvadvpn.compose.test.EDIT_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG -import net.mullvad.mullvadvpn.compose.textfield.CustomTextField import net.mullvad.mullvadvpn.lib.theme.AppTheme -import net.mullvad.mullvadvpn.model.CustomListsError import net.mullvad.mullvadvpn.viewmodel.EditCustomListNameDialogSideEffect import net.mullvad.mullvadvpn.viewmodel.EditCustomListNameDialogViewModel import org.koin.androidx.compose.koinViewModel @@ -77,10 +70,9 @@ fun EditCustomListNameDialog( onInputChanged: () -> Unit = {}, onDismiss: () -> Unit = {} ) { - val focusRequester = remember { FocusRequester() } - val keyboardController = LocalSoftwareKeyboardController.current - val input = remember { mutableStateOf(state.name) } - val isValidName by remember { derivedStateOf { input.value.isNotBlank() } } + val name = remember { mutableStateOf(state.name) } + val isValidName by remember { derivedStateOf { name.value.isNotBlank() } } + AlertDialog( title = { Text( @@ -88,51 +80,17 @@ fun EditCustomListNameDialog( ) }, text = { - Column { - CustomTextField( - value = input.value, - onValueChanged = { - input.value = it - onInputChanged() - }, - onSubmit = { - if (isValidName) { - updateName(it) - } - }, - keyboardType = KeyboardType.Text, - placeholderText = "", - isValidValue = state.error == null, - isDigitsOnlyAllowed = false, - supportingText = { - if (state.error != null) { - Text( - text = - stringResource( - id = - if (state.error == CustomListsError.CustomListExists) { - R.string.custom_list_error_list_exists - } else { - R.string.error_occurred - } - ), - color = MaterialTheme.colorScheme.error, - style = MaterialTheme.typography.bodySmall - ) - } - }, - modifier = - Modifier.focusRequester(focusRequester) - .onFocusChanged { focusState -> - if (focusState.hasFocus) { - keyboardController?.show() - } - } - .testTag(EDIT_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG) - ) - } - - LaunchedEffect(Unit) { focusRequester.requestFocus() } + CustomListNameTextField( + name = name.value, + isValidName = isValidName, + error = state.error, + onSubmit = updateName, + onValueChanged = { + name.value = it + onInputChanged() + }, + modifier = Modifier.testTag(EDIT_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG) + ) }, containerColor = MaterialTheme.colorScheme.background, titleContentColor = MaterialTheme.colorScheme.onBackground, @@ -140,7 +98,7 @@ fun EditCustomListNameDialog( confirmButton = { PrimaryButton( text = stringResource(id = R.string.save), - onClick = { updateName(input.value) }, + onClick = { updateName(name.value) }, isEnabled = isValidName ) },