diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/EditListPreference.kt b/app/src/main/java/com/geeksville/mesh/ui/components/EditListPreference.kt index b130656b..39e69fd9 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/EditListPreference.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/EditListPreference.kt @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.ButtonDefaults import androidx.compose.material.ContentAlpha import androidx.compose.material.Icon @@ -20,21 +21,27 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color 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.unit.dp +import com.geeksville.mesh.ModuleConfigProtos.RemoteHardwarePin +import com.geeksville.mesh.ModuleConfigProtos.RemoteHardwarePinType import com.geeksville.mesh.R +import com.geeksville.mesh.copy +import com.geeksville.mesh.remoteHardwarePin @Composable -fun EditListPreference( +inline fun EditListPreference( title: String, - list: List, + list: List, maxCount: Int, enabled: Boolean, keyboardActions: KeyboardActions, - onValuesChanged: (List) -> Unit, + crossinline onValuesChanged: (List) -> Unit, modifier: Modifier = Modifier, ) { - val listState = remember(list) { mutableStateListOf().apply { addAll(list) } } + val listState = remember(list) { mutableStateListOf().apply { addAll(list) } } Column(modifier = modifier) { Text( @@ -44,13 +51,14 @@ fun EditListPreference( color = if (!enabled) MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled) else Color.Unspecified, ) listState.forEachIndexed { index, value -> - EditTextPreference( + // handle lora.ignoreIncoming: List + if (value is Int) EditTextPreference( title = "${index + 1}/$maxCount", value = value, enabled = enabled, keyboardActions = keyboardActions, onValueChanged = { - listState[index] = it + listState[index] = it as T onValuesChanged(listState) }, modifier = modifier.fillMaxWidth(), @@ -69,10 +77,75 @@ fun EditListPreference( } } ) + + // handle remoteHardware.availablePins: List + 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( 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, colors = ButtonDefaults.buttonColors( disabledContentColor = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled) @@ -84,12 +157,28 @@ fun EditListPreference( @Preview(showBackground = true) @Composable private fun EditListPreferencePreview() { - EditListPreference( - title = "Ignore incoming", - list = listOf(12345,67890), - maxCount = 4, - enabled = true, - keyboardActions = KeyboardActions {}, - onValuesChanged = { }, - ) + Column { + EditListPreference( + title = "Ignore incoming", + list = listOf(12345, 67890), + maxCount = 4, + enabled = true, + 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 = {}, + ) + } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/config/RemoteHardwareConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/components/config/RemoteHardwareConfigItemList.kt index 9718c0a2..9632244a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/config/RemoteHardwareConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/config/RemoteHardwareConfigItemList.kt @@ -2,6 +2,7 @@ package com.geeksville.mesh.ui.components.config import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.text.KeyboardActions import androidx.compose.material.Divider import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -14,6 +15,7 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.tooling.preview.Preview import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.RemoteHardwareConfig 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.PreferenceFooter import com.geeksville.mesh.ui.components.SwitchPreference @@ -42,6 +44,30 @@ fun RemoteHardwareConfigItemList( } 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 { PreferenceFooter( enabled = remoteHardwareInput != remoteHardwareConfig,