From d7394d0b9fbe435b2973b4522d962c30243a8119 Mon Sep 17 00:00:00 2001 From: Jonatan Rhodin Date: Thu, 22 Aug 2024 15:04:48 +0200 Subject: [PATCH] Add input dialog base dialog --- .../compose/dialog/CreateCustomListDialog.kt | 28 ++--- .../mullvadvpn/compose/dialog/DnsDialog.kt | 110 +++++------------- .../dialog/EditCustomListNameDialog.kt | 27 ++--- .../mullvadvpn/compose/dialog/InputDialog.kt | 106 +++++++++++++++++ .../mullvadvpn/compose/dialog/MtuDialog.kt | 101 +++++----------- .../dialog/WireguardCustomPortDialog.kt | 88 +++++--------- 6 files changed, 215 insertions(+), 245 deletions(-) create mode 100644 android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InputDialog.kt 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 0334b0b14dd5..a7656573b149 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,8 +1,5 @@ package net.mullvad.mullvadvpn.compose.dialog -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf @@ -22,7 +19,6 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.spec.DestinationStyle import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.state.CreateCustomListUiState import net.mullvad.mullvadvpn.compose.test.CREATE_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG @@ -101,13 +97,14 @@ fun CreateCustomListDialog( onInputChanged: () -> Unit = {}, onDismiss: () -> Unit = {}, ) { - val name = remember { mutableStateOf("") } val isValidName by remember { derivedStateOf { name.value.isNotBlank() } } - AlertDialog( - title = { Text(text = stringResource(id = R.string.create_new_list)) }, - text = { + InputDialog( + title = stringResource(id = R.string.create_new_list), + confirmButtonText = stringResource(id = R.string.create), + confirmButtonEnabled = isValidName, + input = { CustomListNameTextField( name = name.value, isValidName = isValidName, @@ -120,19 +117,8 @@ fun CreateCustomListDialog( modifier = Modifier.testTag(CREATE_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG), ) }, - containerColor = MaterialTheme.colorScheme.surface, - titleContentColor = MaterialTheme.colorScheme.onSurface, - onDismissRequest = onDismiss, - confirmButton = { - PrimaryButton( - text = stringResource(id = R.string.create), - onClick = { createCustomList(name.value) }, - isEnabled = isValidName, - ) - }, - dismissButton = { - PrimaryButton(text = stringResource(id = R.string.cancel), onClick = onDismiss) - }, + onBack = onDismiss, + onConfirm = { createCustomList(name.value) }, ) } 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 7561747e5306..dd08a71c3af3 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,12 +1,7 @@ package net.mullvad.mullvadvpn.compose.dialog -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.material3.AlertDialog import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier @@ -19,13 +14,10 @@ import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.spec.DestinationStyle import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.compose.button.NegativeButton -import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.communication.DnsDialogResult import net.mullvad.mullvadvpn.compose.textfield.DnsTextField import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.lib.theme.AppTheme -import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.viewmodel.DnsDialogSideEffect import net.mullvad.mullvadvpn.viewmodel.DnsDialogViewModel import net.mullvad.mullvadvpn.viewmodel.DnsDialogViewState @@ -85,79 +77,41 @@ fun DnsDialog( onRemoveDnsClick: (Int) -> Unit, onDismiss: () -> Unit, ) { - AlertDialog( - title = { - Text( - text = - if (state.isNewEntry) { - stringResource(R.string.add_dns_server_dialog_title) - } else { - stringResource(R.string.update_dns_server_dialog_title) - }, - color = MaterialTheme.colorScheme.onSurface, + InputDialog( + title = + if (state.isNewEntry) { + stringResource(R.string.add_dns_server_dialog_title) + } else { + stringResource(R.string.update_dns_server_dialog_title) + }, + input = { + DnsTextField( + value = state.input, + isValidValue = state.isValid(), + onValueChanged = { newDnsValue -> onDnsInputChange(newDnsValue) }, + onSubmit = onSaveDnsClick, + isEnabled = true, + placeholderText = stringResource(R.string.custom_dns_hint), + modifier = Modifier.fillMaxWidth(), ) }, - text = { - Column { - DnsTextField( - value = state.input, - isValidValue = state.isValid(), - onValueChanged = { newDnsValue -> onDnsInputChange(newDnsValue) }, - onSubmit = onSaveDnsClick, - isEnabled = true, - placeholderText = stringResource(R.string.custom_dns_hint), - modifier = Modifier.fillMaxWidth(), - ) - - val errorMessage = - when { - state.validationError is ValidationError.DuplicateAddress -> { - stringResource(R.string.duplicate_address_warning) - } - state.isLocal && !state.isAllowLanEnabled -> { - stringResource(id = R.string.confirm_local_dns) - } - else -> { - null - } - } - - if (errorMessage != null) { - Text( - text = errorMessage, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.error, - modifier = Modifier.padding(top = Dimens.smallPadding), - ) + message = + when { + state.validationError is ValidationError.DuplicateAddress -> { + stringResource(R.string.duplicate_address_warning) } - } - }, - confirmButton = { - Column(verticalArrangement = Arrangement.spacedBy(Dimens.buttonSpacing)) { - PrimaryButton( - modifier = Modifier.fillMaxWidth(), - onClick = onSaveDnsClick, - isEnabled = state.isValid(), - text = stringResource(id = R.string.submit_button), - ) - - if (state.index != null) { - NegativeButton( - modifier = Modifier.fillMaxWidth(), - onClick = { onRemoveDnsClick(state.index) }, - text = stringResource(id = R.string.remove_button), - ) + state.isLocal && !state.isAllowLanEnabled -> { + stringResource(id = R.string.confirm_local_dns) } - - PrimaryButton( - modifier = Modifier.fillMaxWidth(), - onClick = onDismiss, - text = stringResource(id = R.string.cancel), - ) - } - }, - onDismissRequest = onDismiss, - containerColor = MaterialTheme.colorScheme.surface, - titleContentColor = MaterialTheme.colorScheme.onSurface, + else -> { + null + } + }, + onResetButtonText = stringResource(id = R.string.remove_button), + confirmButtonEnabled = state.isValid(), + messageTextColor = MaterialTheme.colorScheme.error, + onReset = state.index?.let { { onRemoveDnsClick(state.index) } }, + onBack = onDismiss, + onConfirm = onSaveDnsClick, ) } 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 dcece689f437..57205175e5c4 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,8 +1,5 @@ package net.mullvad.mullvadvpn.compose.dialog -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier @@ -16,7 +13,6 @@ import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.spec.DestinationStyle import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.communication.CustomListActionResultData import net.mullvad.mullvadvpn.compose.state.EditCustomListNameUiState import net.mullvad.mullvadvpn.compose.test.EDIT_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG @@ -77,9 +73,11 @@ fun EditCustomListNameDialog( onInputChanged: (String) -> Unit = {}, onDismiss: () -> Unit = {}, ) { - AlertDialog( - title = { Text(text = stringResource(id = R.string.update_list_name)) }, - text = { + InputDialog( + title = stringResource(id = R.string.update_list_name), + confirmButtonText = stringResource(id = R.string.save), + confirmButtonEnabled = state.isValidName, + input = { CustomListNameTextField( name = state.name, isValidName = state.isValidName, @@ -89,19 +87,8 @@ fun EditCustomListNameDialog( modifier = Modifier.testTag(EDIT_CUSTOM_LIST_DIALOG_INPUT_TEST_TAG), ) }, - containerColor = MaterialTheme.colorScheme.surface, - titleContentColor = MaterialTheme.colorScheme.onSurface, - onDismissRequest = onDismiss, - confirmButton = { - PrimaryButton( - text = stringResource(id = R.string.save), - onClick = { updateName(state.name) }, - isEnabled = state.isValidName, - ) - }, - dismissButton = { - PrimaryButton(text = stringResource(id = R.string.cancel), onClick = onDismiss) - }, + onBack = onDismiss, + onConfirm = { updateName(state.name) }, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InputDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InputDialog.kt new file mode 100644 index 000000000000..8919ad69dbc0 --- /dev/null +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/InputDialog.kt @@ -0,0 +1,106 @@ +package net.mullvad.mullvadvpn.compose.dialog + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +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.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.tooling.preview.Preview +import net.mullvad.mullvadvpn.R +import net.mullvad.mullvadvpn.compose.button.NegativeButton +import net.mullvad.mullvadvpn.compose.button.PrimaryButton +import net.mullvad.mullvadvpn.compose.textfield.CustomTextField +import net.mullvad.mullvadvpn.lib.theme.AppTheme +import net.mullvad.mullvadvpn.lib.theme.Dimens + +@Preview +@Composable +private fun PreviewInputDialog() { + AppTheme { + InputDialog( + title = "Input here", + message = "Lorem ipsum", + input = { + CustomTextField( + value = "input", + keyboardType = KeyboardType.Text, + onValueChanged = {}, + onSubmit = {}, + placeholderText = "Placeholder", + isValidValue = true, + isDigitsOnlyAllowed = false, + ) + }, + onReset = {}, + onBack = {}, + onConfirm = {}, + ) + } +} + +@Composable +fun InputDialog( + title: String, + message: String? = null, + input: @Composable ColumnScope.() -> Unit, + confirmButtonEnabled: Boolean = true, + confirmButtonText: String = stringResource(R.string.submit_button), + onResetButtonText: String = stringResource(R.string.reset_to_default_button), + messageTextColor: Color = MaterialTheme.colorScheme.onSurfaceVariant, + onBack: () -> Unit, + onConfirm: () -> Unit, + onReset: (() -> Unit)? = null, +) { + AlertDialog( + onDismissRequest = onBack, + title = { Text(text = title, color = MaterialTheme.colorScheme.onSurface) }, + text = { + Column { + input() + + message?.let { + Text( + text = message, + style = MaterialTheme.typography.bodySmall, + color = messageTextColor, + modifier = Modifier.padding(top = Dimens.smallPadding), + ) + } + } + }, + confirmButton = { + Column(verticalArrangement = Arrangement.spacedBy(Dimens.buttonSpacing)) { + PrimaryButton( + modifier = Modifier.fillMaxWidth(), + isEnabled = confirmButtonEnabled, + text = confirmButtonText, + onClick = onConfirm, + ) + + if (onReset != null) { + NegativeButton( + modifier = Modifier.fillMaxWidth(), + text = onResetButtonText, + onClick = onReset, + ) + } + + PrimaryButton( + modifier = Modifier.fillMaxWidth(), + text = stringResource(R.string.cancel), + onClick = onBack, + ) + } + }, + containerColor = MaterialTheme.colorScheme.surface, + titleContentColor = MaterialTheme.colorScheme.onSurface, + ) +} 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 bbf05d550df5..97427fe9da2d 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,12 +1,6 @@ package net.mullvad.mullvadvpn.compose.dialog -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.material3.AlertDialog -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier @@ -16,19 +10,15 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph -import com.ramcosta.composedestinations.result.EmptyResultBackNavigator import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.spec.DestinationStyle import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.compose.button.NegativeButton -import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.textfield.MtuTextField import net.mullvad.mullvadvpn.compose.util.CollectSideEffectWithLifecycle import net.mullvad.mullvadvpn.constant.MTU_MAX_VALUE import net.mullvad.mullvadvpn.constant.MTU_MIN_VALUE import net.mullvad.mullvadvpn.lib.model.Mtu import net.mullvad.mullvadvpn.lib.theme.AppTheme -import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.viewmodel.MtuDialogSideEffect import net.mullvad.mullvadvpn.viewmodel.MtuDialogUiState import net.mullvad.mullvadvpn.viewmodel.MtuDialogViewModel @@ -37,7 +27,16 @@ import org.koin.androidx.compose.koinViewModel @Preview @Composable private fun PreviewMtuDialog() { - AppTheme { Mtu(EmptyResultBackNavigator()) } + AppTheme { + MtuDialog( + state = + MtuDialogUiState(mtuInput = "1300", isValidInput = true, showResetToDefault = true), + onInputChanged = {}, + onSaveMtu = {}, + onResetMtu = {}, + onDismiss = {}, + ) + } } data class MtuNavArgs(val initialMtu: Mtu? = null) @@ -71,65 +70,29 @@ fun MtuDialog( onResetMtu: () -> Unit, onDismiss: () -> Unit, ) { - AlertDialog( - onDismissRequest = onDismiss, - title = { - Text( - text = stringResource(id = R.string.wireguard_mtu), - color = MaterialTheme.colorScheme.onSurface, + InputDialog( + title = stringResource(id = R.string.wireguard_mtu), + message = stringResource(id = R.string.wireguard_mtu_footer, MTU_MIN_VALUE, MTU_MAX_VALUE), + input = { + MtuTextField( + value = state.mtuInput, + onValueChanged = onInputChanged, + onSubmit = onSaveMtu, + isEnabled = true, + placeholderText = stringResource(R.string.enter_value_placeholder), + maxCharLength = 4, + isValidValue = state.isValidInput, + modifier = Modifier.fillMaxWidth(), ) }, - text = { - Column { - MtuTextField( - value = state.mtuInput, - onValueChanged = onInputChanged, - onSubmit = onSaveMtu, - isEnabled = true, - placeholderText = stringResource(R.string.enter_value_placeholder), - maxCharLength = 4, - isValidValue = state.isValidInput, - modifier = Modifier.fillMaxWidth(), - ) - - Text( - text = - stringResource( - id = R.string.wireguard_mtu_footer, - MTU_MIN_VALUE, - MTU_MAX_VALUE, - ), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(top = Dimens.smallPadding), - ) - } - }, - confirmButton = { - Column(verticalArrangement = Arrangement.spacedBy(Dimens.buttonSpacing)) { - PrimaryButton( - modifier = Modifier.fillMaxWidth(), - isEnabled = state.isValidInput, - text = stringResource(R.string.submit_button), - onClick = { onSaveMtu(state.mtuInput) }, - ) - - if (state.showResetToDefault) { - NegativeButton( - modifier = Modifier.fillMaxWidth(), - text = stringResource(R.string.reset_to_default_button), - onClick = onResetMtu, - ) - } - - PrimaryButton( - modifier = Modifier.fillMaxWidth(), - text = stringResource(R.string.cancel), - onClick = onDismiss, - ) - } - }, - containerColor = MaterialTheme.colorScheme.surface, - titleContentColor = MaterialTheme.colorScheme.onSurface, + confirmButtonEnabled = state.isValidInput, + onReset = + if (state.showResetToDefault) { + onResetMtu + } else { + null + }, + onBack = onDismiss, + onConfirm = { onSaveMtu(state.mtuInput) }, ) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/WireguardCustomPortDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/WireguardCustomPortDialog.kt index 6f775358d911..63f17c780b46 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/WireguardCustomPortDialog.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/WireguardCustomPortDialog.kt @@ -1,14 +1,7 @@ package net.mullvad.mullvadvpn.compose.dialog import android.os.Parcelable -import androidx.compose.foundation.layout.Arrangement -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.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 @@ -23,14 +16,11 @@ import com.ramcosta.composedestinations.result.ResultBackNavigator import com.ramcosta.composedestinations.spec.DestinationStyle import kotlinx.parcelize.Parcelize import net.mullvad.mullvadvpn.R -import net.mullvad.mullvadvpn.compose.button.NegativeButton -import net.mullvad.mullvadvpn.compose.button.PrimaryButton import net.mullvad.mullvadvpn.compose.test.CUSTOM_PORT_DIALOG_INPUT_TEST_TAG import net.mullvad.mullvadvpn.compose.textfield.CustomPortTextField import net.mullvad.mullvadvpn.lib.model.Port import net.mullvad.mullvadvpn.lib.model.PortRange import net.mullvad.mullvadvpn.lib.theme.AppTheme -import net.mullvad.mullvadvpn.lib.theme.Dimens import net.mullvad.mullvadvpn.util.asString import net.mullvad.mullvadvpn.util.inAnyOf @@ -76,56 +66,40 @@ fun WireguardCustomPortDialog( onDismiss: () -> Unit, ) { val port = remember { mutableStateOf(initialPort?.value?.toString() ?: "") } - val isValidPort = port.value.toPortOrNull()?.inAnyOf(allowedPortRanges) ?: false - AlertDialog( - title = { Text(text = stringResource(id = R.string.custom_port_dialog_title)) }, - confirmButton = { - Column(verticalArrangement = Arrangement.spacedBy(Dimens.buttonSpacing)) { - PrimaryButton( - text = stringResource(id = R.string.custom_port_dialog_submit), - onClick = { onSave(port.value.toPortOrNull()) }, - isEnabled = isValidPort, - ) - if (initialPort != null) { - NegativeButton( - text = stringResource(R.string.custom_port_dialog_remove), - onClick = { onSave(null) }, - ) - } - PrimaryButton(text = stringResource(id = R.string.cancel), onClick = onDismiss) - } - }, - text = { - Column { - CustomPortTextField( - value = port.value, - onSubmit = { input -> - if (isValidPort) { - onSave(input.toPortOrNull()) - } - }, - onValueChanged = { input -> port.value = input }, - isValidValue = isValidPort, - maxCharLength = 5, - modifier = Modifier.testTag(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG).fillMaxWidth(), - ) - Spacer(modifier = Modifier.height(Dimens.smallPadding)) - Text( - text = - stringResource( - id = R.string.custom_port_dialog_valid_ranges, - allowedPortRanges.asString(), - ), - color = MaterialTheme.colorScheme.onSurfaceVariant, - style = MaterialTheme.typography.bodySmall, - ) - } + InputDialog( + title = stringResource(id = R.string.custom_port_dialog_title), + input = { + CustomPortTextField( + value = port.value, + onSubmit = { input -> + if (isValidPort) { + onSave(input.toPortOrNull()) + } + }, + onValueChanged = { input -> port.value = input }, + isValidValue = isValidPort, + maxCharLength = 5, + modifier = Modifier.testTag(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG).fillMaxWidth(), + ) }, - containerColor = MaterialTheme.colorScheme.surface, - titleContentColor = MaterialTheme.colorScheme.onSurface, - onDismissRequest = onDismiss, + message = + stringResource( + id = R.string.custom_port_dialog_valid_ranges, + allowedPortRanges.asString(), + ), + confirmButtonEnabled = isValidPort, + confirmButtonText = stringResource(id = R.string.custom_port_dialog_submit), + onResetButtonText = stringResource(R.string.custom_port_dialog_remove), + onBack = onDismiss, + onReset = + if (initialPort != null) { + { onSave(null) } + } else { + null + }, + onConfirm = { onSave(port.value.toPortOrNull()) }, ) }