From 7be051a6645ec892b16bc4f696a28f2ebc267f9c Mon Sep 17 00:00:00 2001 From: Zane Schepke Date: Tue, 23 Sep 2025 07:32:07 -0400 Subject: [PATCH] fix: can't edit ping target bug closes #959 --- .../textbox/SubmitConfigurationTextBox.kt | 94 ------------------ .../components/pingConfigItem.kt | 95 +++++++++++++++++-- 2 files changed, 85 insertions(+), 104 deletions(-) delete mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/textbox/SubmitConfigurationTextBox.kt diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/textbox/SubmitConfigurationTextBox.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/textbox/SubmitConfigurationTextBox.kt deleted file mode 100644 index a3192911..00000000 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/common/textbox/SubmitConfigurationTextBox.kt +++ /dev/null @@ -1,94 +0,0 @@ -package com.zaneschepke.wireguardautotunnel.ui.common.textbox - -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.interaction.collectIsFocusedAsState -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Save -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.* -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalFocusManager -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.KeyboardCapitalization -import androidx.compose.ui.unit.dp - -@Composable -fun SubmitConfigurationTextBox( - value: String?, - label: String, - hint: String, - modifier: Modifier = Modifier, - isErrorValue: (value: String?) -> Boolean, - onSubmit: (value: String) -> Unit, - supportingText: @Composable (() -> Unit)? = null, - keyboardOptions: KeyboardOptions = - KeyboardOptions(capitalization = KeyboardCapitalization.None, imeAction = ImeAction.Done), -) { - val focusManager = LocalFocusManager.current - val interactionSource = remember { MutableInteractionSource() } - val isFocused by interactionSource.collectIsFocusedAsState() - val keyboardController = LocalSoftwareKeyboardController.current - - var stateValue by remember { mutableStateOf(value ?: "") } - - CustomTextField( - isError = isErrorValue(stateValue), - textStyle = - MaterialTheme.typography.bodySmall.copy(color = MaterialTheme.colorScheme.onSurface), - value = stateValue, - onValueChange = { stateValue = it }, - interactionSource = interactionSource, - supportingText = supportingText, - label = { - Text( - label, - color = MaterialTheme.colorScheme.onSurface, - style = MaterialTheme.typography.labelMedium, - ) - }, - containerColor = MaterialTheme.colorScheme.surface, - placeholder = { - Text( - hint, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.outline, - ) - }, - modifier = modifier.fillMaxWidth().height(48.dp), - singleLine = true, - keyboardOptions = keyboardOptions, - keyboardActions = - KeyboardActions( - onDone = { - onSubmit(stateValue) - keyboardController?.hide() - } - ), - trailing = { - if (!isErrorValue(stateValue) && isFocused) { - IconButton( - onClick = { - onSubmit(stateValue) - keyboardController?.hide() - focusManager.clearFocus() - } - ) { - val icon = Icons.Outlined.Save - Icon( - imageVector = icon, - contentDescription = icon.name, - tint = MaterialTheme.colorScheme.primary, - ) - } - } - }, - ) -} diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/tunnels/tunneloptions/components/pingConfigItem.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/tunnels/tunneloptions/components/pingConfigItem.kt index 6cde22c7..408d0fb6 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/tunnels/tunneloptions/components/pingConfigItem.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/tunnels/tunneloptions/components/pingConfigItem.kt @@ -1,16 +1,36 @@ package com.zaneschepke.wireguardautotunnel.ui.screens.tunnels.tunneloptions.components import android.util.Patterns +import androidx.compose.foundation.interaction.MutableInteractionSource 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.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Save +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.unit.dp import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.domain.model.TunnelConf import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionItem -import com.zaneschepke.wireguardautotunnel.ui.common.textbox.SubmitConfigurationTextBox +import com.zaneschepke.wireguardautotunnel.ui.common.textbox.CustomTextField import com.zaneschepke.wireguardautotunnel.util.extensions.isValidIpv4orIpv6Address @Composable @@ -18,18 +38,73 @@ fun pingConfigItem(tunnelConf: TunnelConf, onSubmit: (ip: String) -> Unit): Sele return SelectionItem( title = {}, description = { + val focusManager = LocalFocusManager.current + val keyboardController = LocalSoftwareKeyboardController.current + + var stateValue by remember { mutableStateOf(tunnelConf.pingTarget ?: "") } + val isError by + remember(stateValue) { + derivedStateOf { + stateValue.isNotBlank() && + !stateValue.isValidIpv4orIpv6Address() && + !Patterns.DOMAIN_NAME.matcher(stateValue).matches() + } + } Column(verticalArrangement = Arrangement.spacedBy(16.dp)) { - SubmitConfigurationTextBox( - value = tunnelConf.pingTarget, - label = stringResource(R.string.set_custom_ping_target), - hint = stringResource(R.string.ip_or_hostname), - isErrorValue = { - it?.isNotBlank() == true && - !it.isValidIpv4orIpv6Address() && - !Patterns.DOMAIN_NAME.matcher(it).matches() + CustomTextField( + isError = isError, + textStyle = + MaterialTheme.typography.bodySmall.copy( + color = MaterialTheme.colorScheme.onSurface + ), + value = stateValue, + onValueChange = { stateValue = it }, + interactionSource = remember { MutableInteractionSource() }, + label = { + Text( + stringResource(R.string.set_custom_ping_target), + color = MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.labelMedium, + ) }, + placeholder = { + Text( + stringResource(R.string.ip_or_hostname), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.outline, + ) + }, + containerColor = MaterialTheme.colorScheme.surface, supportingText = { Text(stringResource(R.string.ping_target_description)) }, - onSubmit = onSubmit, + modifier = + Modifier.padding(top = 5.dp, bottom = 10.dp) + .fillMaxWidth() + .padding(end = 16.dp), + singleLine = true, + keyboardOptions = + KeyboardOptions( + capitalization = KeyboardCapitalization.None, + imeAction = ImeAction.Done, + ), + keyboardActions = KeyboardActions(onDone = { onSubmit(stateValue) }), + trailing = { + if (!isError) { + IconButton( + onClick = { + onSubmit(stateValue) + keyboardController?.hide() + focusManager.clearFocus() + } + ) { + val icon = Icons.Outlined.Save + Icon( + imageVector = icon, + contentDescription = icon.name, + tint = MaterialTheme.colorScheme.primary, + ) + } + } + }, ) } },