sforkowany z mirror/meshtastic-android
feat: add RemoteHardwarePin config
rodzic
8bc628de9f
commit
1fe669fb73
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.wrapContentSize
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
import androidx.compose.foundation.text.KeyboardActions
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.ButtonDefaults
|
import androidx.compose.material.ButtonDefaults
|
||||||
import androidx.compose.material.ContentAlpha
|
import androidx.compose.material.ContentAlpha
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
|
@ -20,21 +21,27 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.geeksville.mesh.ModuleConfigProtos.RemoteHardwarePin
|
||||||
|
import com.geeksville.mesh.ModuleConfigProtos.RemoteHardwarePinType
|
||||||
import com.geeksville.mesh.R
|
import com.geeksville.mesh.R
|
||||||
|
import com.geeksville.mesh.copy
|
||||||
|
import com.geeksville.mesh.remoteHardwarePin
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun EditListPreference(
|
inline fun <reified T> EditListPreference(
|
||||||
title: String,
|
title: String,
|
||||||
list: List<Int>,
|
list: List<T>,
|
||||||
maxCount: Int,
|
maxCount: Int,
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
keyboardActions: KeyboardActions,
|
keyboardActions: KeyboardActions,
|
||||||
onValuesChanged: (List<Int>) -> Unit,
|
crossinline onValuesChanged: (List<T>) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val listState = remember(list) { mutableStateListOf<Int>().apply { addAll(list) } }
|
val listState = remember(list) { mutableStateListOf<T>().apply { addAll(list) } }
|
||||||
|
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
Text(
|
Text(
|
||||||
|
@ -44,13 +51,14 @@ fun EditListPreference(
|
||||||
color = if (!enabled) MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled) else Color.Unspecified,
|
color = if (!enabled) MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled) else Color.Unspecified,
|
||||||
)
|
)
|
||||||
listState.forEachIndexed { index, value ->
|
listState.forEachIndexed { index, value ->
|
||||||
EditTextPreference(
|
// handle lora.ignoreIncoming: List<Int>
|
||||||
|
if (value is Int) EditTextPreference(
|
||||||
title = "${index + 1}/$maxCount",
|
title = "${index + 1}/$maxCount",
|
||||||
value = value,
|
value = value,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
keyboardActions = keyboardActions,
|
keyboardActions = keyboardActions,
|
||||||
onValueChanged = {
|
onValueChanged = {
|
||||||
listState[index] = it
|
listState[index] = it as T
|
||||||
onValuesChanged(listState)
|
onValuesChanged(listState)
|
||||||
},
|
},
|
||||||
modifier = modifier.fillMaxWidth(),
|
modifier = modifier.fillMaxWidth(),
|
||||||
|
@ -69,10 +77,75 @@ fun EditListPreference(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// handle remoteHardware.availablePins: List<RemoteHardwarePin>
|
||||||
|
if (value is RemoteHardwarePin) {
|
||||||
|
EditTextPreference(
|
||||||
|
title = "GPIO pin",
|
||||||
|
value = value.gpioPin,
|
||||||
|
enabled = enabled,
|
||||||
|
keyboardActions = keyboardActions,
|
||||||
|
onValueChanged = {
|
||||||
|
if (it in 0..255) {
|
||||||
|
listState[index] = value.copy { gpioPin = it } as T
|
||||||
|
onValuesChanged(listState)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
EditTextPreference(
|
||||||
|
title = "Name",
|
||||||
|
value = value.name,
|
||||||
|
maxSize = 14, // name max_size:15
|
||||||
|
enabled = enabled,
|
||||||
|
isError = false,
|
||||||
|
keyboardOptions = KeyboardOptions.Default.copy(
|
||||||
|
keyboardType = KeyboardType.Text, imeAction = ImeAction.Done
|
||||||
|
),
|
||||||
|
keyboardActions = keyboardActions,
|
||||||
|
onValueChanged = {
|
||||||
|
listState[index] = value.copy { name = it } as T
|
||||||
|
onValuesChanged(listState)
|
||||||
|
},
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
listState.removeAt(index)
|
||||||
|
onValuesChanged(listState)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
Icons.TwoTone.Close,
|
||||||
|
stringResource(R.string.delete),
|
||||||
|
modifier = Modifier.wrapContentSize(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
DropDownPreference(
|
||||||
|
title = "Type",
|
||||||
|
enabled = enabled,
|
||||||
|
items = RemoteHardwarePinType.values()
|
||||||
|
.filter { it != RemoteHardwarePinType.UNRECOGNIZED }
|
||||||
|
.map { it to it.name },
|
||||||
|
selectedItem = value.type,
|
||||||
|
onItemSelected = {
|
||||||
|
listState[index] = value.copy { type = it } as T
|
||||||
|
onValuesChanged(listState)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onClick = { listState.add(listState.size, 0) },
|
onClick = {
|
||||||
|
// Add element based on the type T
|
||||||
|
val newElement = when (T::class) {
|
||||||
|
Int::class -> 0 as T
|
||||||
|
RemoteHardwarePin::class -> remoteHardwarePin {} as T
|
||||||
|
else -> throw IllegalArgumentException("Unsupported type: ${T::class}")
|
||||||
|
}
|
||||||
|
listState.add(listState.size, newElement)
|
||||||
|
},
|
||||||
enabled = maxCount > listState.size,
|
enabled = maxCount > listState.size,
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
disabledContentColor = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)
|
disabledContentColor = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)
|
||||||
|
@ -84,12 +157,28 @@ fun EditListPreference(
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
private fun EditListPreferencePreview() {
|
private fun EditListPreferencePreview() {
|
||||||
EditListPreference(
|
Column {
|
||||||
title = "Ignore incoming",
|
EditListPreference(
|
||||||
list = listOf(12345,67890),
|
title = "Ignore incoming",
|
||||||
maxCount = 4,
|
list = listOf(12345, 67890),
|
||||||
enabled = true,
|
maxCount = 4,
|
||||||
keyboardActions = KeyboardActions {},
|
enabled = true,
|
||||||
onValuesChanged = { },
|
keyboardActions = KeyboardActions {},
|
||||||
)
|
onValuesChanged = {},
|
||||||
|
)
|
||||||
|
EditListPreference(
|
||||||
|
title = "Available pins",
|
||||||
|
list = listOf(
|
||||||
|
remoteHardwarePin {
|
||||||
|
gpioPin = 12
|
||||||
|
name = "Front door"
|
||||||
|
type = RemoteHardwarePinType.DIGITAL_READ
|
||||||
|
},
|
||||||
|
),
|
||||||
|
maxCount = 4,
|
||||||
|
enabled = true,
|
||||||
|
keyboardActions = KeyboardActions {},
|
||||||
|
onValuesChanged = {},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.geeksville.mesh.ui.components.config
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.material.Divider
|
import androidx.compose.material.Divider
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
@ -14,6 +15,7 @@ import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.RemoteHardwareConfig
|
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.RemoteHardwareConfig
|
||||||
import com.geeksville.mesh.copy
|
import com.geeksville.mesh.copy
|
||||||
|
import com.geeksville.mesh.ui.components.EditListPreference
|
||||||
import com.geeksville.mesh.ui.components.PreferenceCategory
|
import com.geeksville.mesh.ui.components.PreferenceCategory
|
||||||
import com.geeksville.mesh.ui.components.PreferenceFooter
|
import com.geeksville.mesh.ui.components.PreferenceFooter
|
||||||
import com.geeksville.mesh.ui.components.SwitchPreference
|
import com.geeksville.mesh.ui.components.SwitchPreference
|
||||||
|
@ -42,6 +44,30 @@ fun RemoteHardwareConfigItemList(
|
||||||
}
|
}
|
||||||
item { Divider() }
|
item { Divider() }
|
||||||
|
|
||||||
|
item {
|
||||||
|
SwitchPreference(title = "Allow undefined pin access",
|
||||||
|
checked = remoteHardwareInput.allowUndefinedPinAccess,
|
||||||
|
enabled = enabled,
|
||||||
|
onCheckedChange = {
|
||||||
|
remoteHardwareInput = remoteHardwareInput.copy { allowUndefinedPinAccess = it }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
item { Divider() }
|
||||||
|
|
||||||
|
item {
|
||||||
|
EditListPreference(title = "Available pins",
|
||||||
|
list = remoteHardwareInput.availablePinsList,
|
||||||
|
maxCount = 4, // available_pins max_count:4
|
||||||
|
enabled = enabled,
|
||||||
|
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
|
||||||
|
onValuesChanged = { list ->
|
||||||
|
remoteHardwareInput = remoteHardwareInput.copy {
|
||||||
|
availablePins.clear()
|
||||||
|
availablePins.addAll(list)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
item {
|
item {
|
||||||
PreferenceFooter(
|
PreferenceFooter(
|
||||||
enabled = remoteHardwareInput != remoteHardwareConfig,
|
enabled = remoteHardwareInput != remoteHardwareConfig,
|
||||||
|
|
Ładowanie…
Reference in New Issue