mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat: add password TextField
This commit is contained in:
parent
f222fe4d5e
commit
79bf8d1536
7 changed files with 175 additions and 62 deletions
|
|
@ -0,0 +1,66 @@
|
|||
package com.geeksville.mesh.ui.components
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
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.Modifier
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
||||
@Composable
|
||||
fun EditIPv4Preference(
|
||||
title: String,
|
||||
value: Int,
|
||||
enabled: Boolean,
|
||||
keyboardActions: KeyboardActions,
|
||||
onValueChanged: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val pattern = """\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b""".toRegex()
|
||||
|
||||
fun convertIntToIpAddress(int: Int): String {
|
||||
return "${int and 0xff}.${int shr 8 and 0xff}.${int shr 16 and 0xff}.${int shr 24 and 0xff}"
|
||||
}
|
||||
|
||||
fun convertIpAddressToInt(ipAddress: String): Int? = ipAddress.split(".")
|
||||
.map { it.toIntOrNull() }.reversed() // little-endian byte order
|
||||
.fold(0) { total, next ->
|
||||
if (next == null) return null else total shl 8 or next
|
||||
}
|
||||
|
||||
var valueState by remember(value) { mutableStateOf(convertIntToIpAddress(value)) }
|
||||
|
||||
EditTextPreference(
|
||||
title = title,
|
||||
value = valueState,
|
||||
enabled = enabled,
|
||||
isError = convertIntToIpAddress(value) != valueState,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Number, imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = keyboardActions,
|
||||
onValueChanged = {
|
||||
valueState = it
|
||||
if (pattern.matches(it)) convertIpAddressToInt(it)?.let { int -> onValueChanged(int) }
|
||||
},
|
||||
onFocusChanged = {},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun EditIPv4PreferencePreview() {
|
||||
EditIPv4Preference(
|
||||
title = "IP Address",
|
||||
value = 16820416,
|
||||
enabled = true,
|
||||
keyboardActions = KeyboardActions {},
|
||||
onValueChanged = {}
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.geeksville.mesh.ui.components
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
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.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.geeksville.mesh.R
|
||||
|
||||
@Composable
|
||||
fun EditPasswordPreference(
|
||||
title: String,
|
||||
value: String,
|
||||
maxSize: Int,
|
||||
enabled: Boolean,
|
||||
keyboardActions: KeyboardActions,
|
||||
onValueChanged: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var isPasswordVisible by remember { mutableStateOf(false) }
|
||||
|
||||
EditTextPreference(
|
||||
title = title,
|
||||
value = value,
|
||||
maxSize = maxSize,
|
||||
enabled = enabled,
|
||||
isError = false,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Password, imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = keyboardActions,
|
||||
onValueChanged = {
|
||||
onValueChanged(it)
|
||||
},
|
||||
onFocusChanged = {},
|
||||
visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
trailingIcon = {
|
||||
IconButton(onClick = { isPasswordVisible = !isPasswordVisible }) {
|
||||
Icon(
|
||||
painter = if (isPasswordVisible) painterResource(R.drawable.ic_twotone_visibility_off_24)
|
||||
else painterResource(R.drawable.ic_twotone_visibility_24),
|
||||
contentDescription = if (isPasswordVisible) "Hide password" else "Show password",
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun EditPasswordPreferencePreview() {
|
||||
EditPasswordPreference(
|
||||
title = "Password",
|
||||
value = "top secret",
|
||||
maxSize = 63,
|
||||
enabled = true,
|
||||
keyboardActions = KeyboardActions {},
|
||||
onValueChanged = {}
|
||||
)
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.focus.FocusState
|
|||
import androidx.compose.ui.focus.onFocusEvent
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
|
|
@ -127,47 +128,6 @@ fun EditTextPreference(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EditIPv4Preference(
|
||||
title: String,
|
||||
value: Int,
|
||||
enabled: Boolean,
|
||||
keyboardActions: KeyboardActions,
|
||||
onValueChanged: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val pattern = """\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b""".toRegex()
|
||||
|
||||
fun convertIntToIpAddress(int: Int): String {
|
||||
return "${int and 0xff}.${int shr 8 and 0xff}.${int shr 16 and 0xff}.${int shr 24 and 0xff}"
|
||||
}
|
||||
|
||||
fun convertIpAddressToInt(ipAddress: String): Int? = ipAddress.split(".")
|
||||
.map { it.toIntOrNull() }.reversed() // little-endian byte order
|
||||
.fold(0) { total, next ->
|
||||
if (next == null) return null else total shl 8 or next
|
||||
}
|
||||
|
||||
var valueState by remember(value) { mutableStateOf(convertIntToIpAddress(value)) }
|
||||
|
||||
EditTextPreference(
|
||||
title = title,
|
||||
value = valueState,
|
||||
enabled = enabled,
|
||||
isError = convertIntToIpAddress(value) != valueState,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Number, imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = keyboardActions,
|
||||
onValueChanged = {
|
||||
valueState = it
|
||||
if (pattern.matches(it)) convertIpAddressToInt(it)?.let { int -> onValueChanged(int) }
|
||||
},
|
||||
onFocusChanged = {},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun EditTextPreference(
|
||||
title: String,
|
||||
|
|
@ -181,6 +141,7 @@ fun EditTextPreference(
|
|||
maxSize: Int = 0, // max_size - 1 (in bytes)
|
||||
onFocusChanged: (FocusState) -> Unit = {},
|
||||
trailingIcon: (@Composable () -> Unit)? = null,
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
) {
|
||||
var isFocused by remember { mutableStateOf(false) }
|
||||
|
||||
|
|
@ -202,13 +163,14 @@ fun EditTextPreference(
|
|||
label = { Text(title) },
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
visualTransformation = visualTransformation,
|
||||
trailingIcon = {
|
||||
if (trailingIcon != null) {
|
||||
trailingIcon()
|
||||
} else {
|
||||
if (isError) Icon(Icons.TwoTone.Info, "Error", tint = MaterialTheme.colors.error)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
if (maxSize > 0 && isFocused) {
|
||||
|
|
@ -247,12 +209,5 @@ private fun EditTextPreferencePreview() {
|
|||
keyboardActions = KeyboardActions {},
|
||||
onValueChanged = {}
|
||||
)
|
||||
EditIPv4Preference(
|
||||
title = "IP Address",
|
||||
value = 16820416,
|
||||
enabled = true,
|
||||
keyboardActions = KeyboardActions {},
|
||||
onValueChanged = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import androidx.compose.ui.text.input.KeyboardType
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.MQTTConfig
|
||||
import com.geeksville.mesh.copy
|
||||
import com.geeksville.mesh.ui.components.EditPasswordPreference
|
||||
import com.geeksville.mesh.ui.components.EditTextPreference
|
||||
import com.geeksville.mesh.ui.components.PreferenceCategory
|
||||
import com.geeksville.mesh.ui.components.PreferenceFooter
|
||||
|
|
@ -72,14 +73,10 @@ fun MQTTConfigItemList(
|
|||
}
|
||||
|
||||
item {
|
||||
EditTextPreference(title = "Password",
|
||||
EditPasswordPreference(title = "Password",
|
||||
value = mqttInput.password,
|
||||
maxSize = 63, // password max_size:64
|
||||
enabled = enabled,
|
||||
isError = false,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Text, imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
|
||||
onValueChanged = { mqttInput = mqttInput.copy { password = it } })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.geeksville.mesh.ConfigProtos.Config.NetworkConfig
|
|||
import com.geeksville.mesh.copy
|
||||
import com.geeksville.mesh.ui.components.DropDownPreference
|
||||
import com.geeksville.mesh.ui.components.EditIPv4Preference
|
||||
import com.geeksville.mesh.ui.components.EditPasswordPreference
|
||||
import com.geeksville.mesh.ui.components.EditTextPreference
|
||||
import com.geeksville.mesh.ui.components.PreferenceCategory
|
||||
import com.geeksville.mesh.ui.components.PreferenceFooter
|
||||
|
|
@ -63,18 +64,12 @@ fun NetworkConfigItemList(
|
|||
}
|
||||
|
||||
item {
|
||||
EditTextPreference(title = "PSK",
|
||||
EditPasswordPreference(title = "PSK",
|
||||
value = networkInput.wifiPsk,
|
||||
maxSize = 63, // wifi_psk max_size:64
|
||||
enabled = enabled,
|
||||
isError = false,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Password, imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
|
||||
onValueChanged = {
|
||||
networkInput = networkInput.copy { wifiPsk = it }
|
||||
})
|
||||
onValueChanged = { networkInput = networkInput.copy { wifiPsk = it } })
|
||||
}
|
||||
|
||||
item {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue