refactor: split configs into individual components (#623)

This commit is contained in:
Andre K 2023-04-17 17:13:26 -03:00 committed by GitHub
parent 6fe5f2733a
commit a5fa47292e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 2793 additions and 1756 deletions

View file

@ -41,35 +41,41 @@ fun PreferenceFooter(
Row(
modifier = modifier
.fillMaxWidth()
.size(48.dp),
.height(64.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Button(
modifier = modifier
.fillMaxWidth()
.height(48.dp)
.weight(1f),
enabled = enabled,
onClick = onNegativeClicked,
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red)
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Red.copy(alpha = 0.6f),
disabledContentColor = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)
)
) {
Text(
text = stringResource(id = negativeText),
style = MaterialTheme.typography.body1,
color = if (!enabled) MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled) else Color.Unspecified,
)
}
Button(
modifier = modifier
.fillMaxWidth()
.height(48.dp)
.weight(1f),
enabled = enabled,
onClick = onPositiveClicked,
colors = ButtonDefaults.buttonColors(backgroundColor = Color.Green)
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Green.copy(alpha = 0.6f),
disabledContentColor = MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)
)
) {
Text(
text = stringResource(id = positiveText),
style = MaterialTheme.typography.body1,
color = if (!enabled) MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled) else Color.DarkGray,
)
}
}

View file

@ -0,0 +1,73 @@
package com.geeksville.mesh.ui.components
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.material.Card
import androidx.compose.material.ContentAlpha
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@Composable
fun TextDividerPreference(
title: String,
modifier: Modifier = Modifier,
enabled: Boolean = true,
trailingIcon: ImageVector? = null,
) {
TextDividerPreference(
title = AnnotatedString(text = title),
enabled = enabled,
modifier = modifier,
trailingIcon = trailingIcon,
)
}
@Composable
fun TextDividerPreference(
title: AnnotatedString,
modifier: Modifier = Modifier,
enabled: Boolean = true,
trailingIcon: ImageVector? = null,
) {
Card(
modifier = modifier.fillMaxWidth(),
backgroundColor = if (isSystemInDarkTheme()) Color.DarkGray else Color.LightGray,
) {
Row(
modifier = modifier
.fillMaxWidth()
.padding(all = 16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = title,
style = MaterialTheme.typography.body1,
color = if (!enabled) MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled) else Color.Unspecified,
)
if (trailingIcon != null) Icon(
trailingIcon, "trailingIcon",
modifier = modifier
.fillMaxWidth()
.wrapContentWidth(Alignment.End),
)
}
}
}
@Preview(showBackground = true)
@Composable
private fun TextDividerPreferencePreview() {
TextDividerPreference(title = "Advanced settings")
}

View file

@ -0,0 +1,119 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.AudioConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.DropDownPreference
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun AudioConfigItemList(
audioConfig: AudioConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (AudioConfig) -> Unit,
) {
var audioInput by remember(audioConfig) { mutableStateOf(audioConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Audio Config") }
item {
SwitchPreference(title = "CODEC 2 enabled",
checked = audioInput.codec2Enabled,
enabled = enabled,
onCheckedChange = { audioInput = audioInput.copy { codec2Enabled = it } })
}
item { Divider() }
item {
EditTextPreference(title = "PTT pin",
value = audioInput.pttPin,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { audioInput = audioInput.copy { pttPin = it } })
}
item {
DropDownPreference(title = "CODEC2 sample rate",
enabled = enabled,
items = AudioConfig.Audio_Baud.values()
.filter { it != AudioConfig.Audio_Baud.UNRECOGNIZED }
.map { it to it.name },
selectedItem = audioInput.bitrate,
onItemSelected = { audioInput = audioInput.copy { bitrate = it } })
}
item { Divider() }
item {
EditTextPreference(title = "I2S word select",
value = audioInput.i2SWs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { audioInput = audioInput.copy { i2SWs = it } })
}
item {
EditTextPreference(title = "I2S data in",
value = audioInput.i2SSd,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { audioInput = audioInput.copy { i2SSd = it } })
}
item {
EditTextPreference(title = "I2S data out",
value = audioInput.i2SDin,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { audioInput = audioInput.copy { i2SDin = it } })
}
item {
EditTextPreference(title = "I2S clock",
value = audioInput.i2SSck,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { audioInput = audioInput.copy { i2SSck = it } })
}
item {
PreferenceFooter(
enabled = audioInput != audioConfig,
onCancelClicked = {
focusManager.clearFocus()
audioInput = audioConfig
},
onSaveClicked = { onSaveClicked(audioInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun AudioConfigPreview(){
AudioConfigItemList(
audioConfig = AudioConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,90 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ConfigProtos.Config.BluetoothConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.DropDownPreference
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun BluetoothConfigItemList(
bluetoothConfig: BluetoothConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (BluetoothConfig) -> Unit,
) {
var bluetoothInput by remember(bluetoothConfig) { mutableStateOf(bluetoothConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Bluetooth Config") }
item {
SwitchPreference(title = "Bluetooth enabled",
checked = bluetoothInput.enabled,
enabled = enabled,
onCheckedChange = { bluetoothInput = bluetoothInput.copy { this.enabled = it } })
}
item { Divider() }
item {
DropDownPreference(title = "Pairing mode",
enabled = enabled,
items = BluetoothConfig.PairingMode.values()
.filter { it != BluetoothConfig.PairingMode.UNRECOGNIZED }
.map { it to it.name },
selectedItem = bluetoothInput.mode,
onItemSelected = { bluetoothInput = bluetoothInput.copy { mode = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Fixed PIN",
value = bluetoothInput.fixedPin,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
if (it.toString().length == 6) // ensure 6 digits
bluetoothInput = bluetoothInput.copy { fixedPin = it }
})
}
item {
PreferenceFooter(
enabled = bluetoothInput != bluetoothConfig,
onCancelClicked = {
focusManager.clearFocus()
bluetoothInput = bluetoothConfig
},
onSaveClicked = { onSaveClicked(bluetoothInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun BluetoothConfigPreview(){
BluetoothConfigItemList(
bluetoothConfig = BluetoothConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,187 @@
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.foundation.text.KeyboardOptions
import androidx.compose.material.Divider
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.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.CannedMessageConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.DropDownPreference
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun CannedMessageConfigItemList(
cannedMessageConfig: CannedMessageConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (CannedMessageConfig) -> Unit,
) {
var cannedMessageInput by remember(cannedMessageConfig) { mutableStateOf(cannedMessageConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Canned Message Config") }
item {
SwitchPreference(title = "Canned message enabled",
checked = cannedMessageInput.enabled,
enabled = enabled,
onCheckedChange = {
cannedMessageInput = cannedMessageInput.copy { this.enabled = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Rotary encoder #1 enabled",
checked = cannedMessageInput.rotary1Enabled,
enabled = enabled,
onCheckedChange = {
cannedMessageInput = cannedMessageInput.copy { rotary1Enabled = it }
})
}
item { Divider() }
item {
EditTextPreference(title = "GPIO pin for rotary encoder A port",
value = cannedMessageInput.inputbrokerPinA,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
cannedMessageInput = cannedMessageInput.copy { inputbrokerPinA = it }
})
}
item {
EditTextPreference(title = "GPIO pin for rotary encoder B port",
value = cannedMessageInput.inputbrokerPinB,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
cannedMessageInput = cannedMessageInput.copy { inputbrokerPinB = it }
})
}
item {
EditTextPreference(title = "GPIO pin for rotary encoder Press port",
value = cannedMessageInput.inputbrokerPinPress,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
cannedMessageInput = cannedMessageInput.copy { inputbrokerPinPress = it }
})
}
item {
DropDownPreference(title = "Generate input event on Press",
enabled = enabled,
items = CannedMessageConfig.InputEventChar.values()
.filter { it != CannedMessageConfig.InputEventChar.UNRECOGNIZED }
.map { it to it.name },
selectedItem = cannedMessageInput.inputbrokerEventPress,
onItemSelected = {
cannedMessageInput = cannedMessageInput.copy { inputbrokerEventPress = it }
})
}
item { Divider() }
item {
DropDownPreference(title = "Generate input event on CW",
enabled = enabled,
items = CannedMessageConfig.InputEventChar.values()
.filter { it != CannedMessageConfig.InputEventChar.UNRECOGNIZED }
.map { it to it.name },
selectedItem = cannedMessageInput.inputbrokerEventCw,
onItemSelected = {
cannedMessageInput = cannedMessageInput.copy { inputbrokerEventCw = it }
})
}
item { Divider() }
item {
DropDownPreference(title = "Generate input event on CCW",
enabled = enabled,
items = CannedMessageConfig.InputEventChar.values()
.filter { it != CannedMessageConfig.InputEventChar.UNRECOGNIZED }
.map { it to it.name },
selectedItem = cannedMessageInput.inputbrokerEventCcw,
onItemSelected = {
cannedMessageInput = cannedMessageInput.copy { inputbrokerEventCcw = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Up/Down/Select input enabled",
checked = cannedMessageInput.updown1Enabled,
enabled = enabled,
onCheckedChange = {
cannedMessageInput = cannedMessageInput.copy { updown1Enabled = it }
})
}
item { Divider() }
item {
EditTextPreference(title = "Allow input source",
value = cannedMessageInput.allowInputSource,
maxSize = 63, // allow_input_source max_size:16
enabled = enabled,
isError = false,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Text, imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
cannedMessageInput = cannedMessageInput.copy { allowInputSource = it }
})
}
item {
SwitchPreference(title = "Send bell",
checked = cannedMessageInput.sendBell,
enabled = enabled,
onCheckedChange = {
cannedMessageInput = cannedMessageInput.copy { sendBell = it }
})
}
item { Divider() }
item {
PreferenceFooter(
enabled = cannedMessageInput != cannedMessageConfig,
onCancelClicked = {
focusManager.clearFocus()
cannedMessageInput = cannedMessageConfig
},
onSaveClicked = { onSaveClicked(cannedMessageInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun CannedMessageConfigPreview(){
CannedMessageConfigItemList(
cannedMessageConfig = CannedMessageConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,138 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ConfigProtos.Config.DeviceConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.DropDownPreference
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun DeviceConfigItemList(
deviceConfig: DeviceConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (DeviceConfig) -> Unit,
) {
var deviceInput by remember(deviceConfig) { mutableStateOf(deviceConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Device Config") }
item {
DropDownPreference(title = "Role",
enabled = enabled,
items = DeviceConfig.Role.values()
.filter { it != DeviceConfig.Role.UNRECOGNIZED }
.map { it to it.name },
selectedItem = deviceInput.role,
onItemSelected = { deviceInput = deviceInput.copy { role = it } })
}
item { Divider() }
item {
SwitchPreference(title = "Serial output enabled",
checked = deviceInput.serialEnabled,
enabled = enabled,
onCheckedChange = { deviceInput = deviceInput.copy { serialEnabled = it } })
}
item { Divider() }
item {
SwitchPreference(title = "Debug log enabled",
checked = deviceInput.debugLogEnabled,
enabled = enabled,
onCheckedChange = { deviceInput = deviceInput.copy { debugLogEnabled = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Redefine PIN_BUTTON",
value = deviceInput.buttonGpio,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
deviceInput = deviceInput.copy { buttonGpio = it }
})
}
item {
EditTextPreference(title = "Redefine PIN_BUZZER",
value = deviceInput.buzzerGpio,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
deviceInput = deviceInput.copy { buzzerGpio = it }
})
}
item {
DropDownPreference(title = "Rebroadcast mode",
enabled = enabled,
items = DeviceConfig.RebroadcastMode.values()
.filter { it != DeviceConfig.RebroadcastMode.UNRECOGNIZED }
.map { it to it.name },
selectedItem = deviceInput.rebroadcastMode,
onItemSelected = { deviceInput = deviceInput.copy { rebroadcastMode = it } })
}
item { Divider() }
item {
EditTextPreference(title = "NodeInfo broadcast interval (seconds)",
value = deviceInput.nodeInfoBroadcastSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
deviceInput = deviceInput.copy { nodeInfoBroadcastSecs = it }
})
}
item {
SwitchPreference(title = "Double tap as button press",
checked = deviceInput.doubleTapAsButtonPress,
enabled = enabled,
onCheckedChange = {
deviceInput = deviceInput.copy { doubleTapAsButtonPress = it }
})
}
item { Divider() }
item {
PreferenceFooter(
enabled = deviceInput != deviceConfig,
onCancelClicked = {
focusManager.clearFocus()
deviceInput = deviceConfig
},
onSaveClicked = { onSaveClicked(deviceInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun DeviceConfigPreview(){
DeviceConfigItemList(
deviceConfig = DeviceConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,155 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ConfigProtos.Config.DisplayConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.DropDownPreference
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun DisplayConfigItemList(
displayConfig: DisplayConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (DisplayConfig) -> Unit,
) {
var displayInput by remember(displayConfig) { mutableStateOf(displayConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Display Config") }
item {
EditTextPreference(title = "Screen timeout (seconds)",
value = displayInput.screenOnSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { displayInput = displayInput.copy { screenOnSecs = it } })
}
item {
DropDownPreference(title = "GPS coordinates format",
enabled = enabled,
items = DisplayConfig.GpsCoordinateFormat.values()
.filter { it != DisplayConfig.GpsCoordinateFormat.UNRECOGNIZED }
.map { it to it.name },
selectedItem = displayInput.gpsFormat,
onItemSelected = { displayInput = displayInput.copy { gpsFormat = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Auto screen carousel (seconds)",
value = displayInput.autoScreenCarouselSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
displayInput = displayInput.copy { autoScreenCarouselSecs = it }
})
}
item {
SwitchPreference(title = "Compass north top",
checked = displayInput.compassNorthTop,
enabled = enabled,
onCheckedChange = { displayInput = displayInput.copy { compassNorthTop = it } })
}
item { Divider() }
item {
SwitchPreference(title = "Flip screen",
checked = displayInput.flipScreen,
enabled = enabled,
onCheckedChange = { displayInput = displayInput.copy { flipScreen = it } })
}
item { Divider() }
item {
DropDownPreference(title = "Display units",
enabled = enabled,
items = DisplayConfig.DisplayUnits.values()
.filter { it != DisplayConfig.DisplayUnits.UNRECOGNIZED }
.map { it to it.name },
selectedItem = displayInput.units,
onItemSelected = { displayInput = displayInput.copy { units = it } })
}
item { Divider() }
item {
DropDownPreference(title = "Override OLED auto-detect",
enabled = enabled,
items = DisplayConfig.OledType.values()
.filter { it != DisplayConfig.OledType.UNRECOGNIZED }
.map { it to it.name },
selectedItem = displayInput.oled,
onItemSelected = { displayInput = displayInput.copy { oled = it } })
}
item { Divider() }
item {
DropDownPreference(title = "Display mode",
enabled = enabled,
items = DisplayConfig.DisplayMode.values()
.filter { it != DisplayConfig.DisplayMode.UNRECOGNIZED }
.map { it to it.name },
selectedItem = displayInput.displaymode,
onItemSelected = { displayInput = displayInput.copy { displaymode = it } })
}
item { Divider() }
item {
SwitchPreference(title = "Heading bold",
checked = displayInput.headingBold,
enabled = enabled,
onCheckedChange = { displayInput = displayInput.copy { headingBold = it } })
}
item { Divider() }
item {
SwitchPreference(title = "Wake screen on tap or motion",
checked = displayInput.wakeOnTapOrMotion,
enabled = enabled,
onCheckedChange = { displayInput = displayInput.copy { wakeOnTapOrMotion = it } })
}
item { Divider() }
item {
PreferenceFooter(
enabled = displayInput != displayConfig,
onCancelClicked = {
focusManager.clearFocus()
displayInput = displayConfig
},
onSaveClicked = { onSaveClicked(displayInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun DisplayConfigPreview(){
DisplayConfigItemList(
displayConfig = DisplayConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,208 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.ExternalNotificationConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
import com.geeksville.mesh.ui.components.TextDividerPreference
@Composable
fun ExternalNotificationConfigItemList(
externalNotificationConfig: ExternalNotificationConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (ExternalNotificationConfig) -> Unit,
) {
var externalNotificationInput by remember(externalNotificationConfig) {
mutableStateOf(externalNotificationConfig)
}
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "External Notification Config") }
item {
SwitchPreference(title = "External notification enabled",
checked = externalNotificationInput.enabled,
enabled = enabled,
onCheckedChange = {
externalNotificationInput = externalNotificationInput.copy { this.enabled = it }
})
}
item { TextDividerPreference("Notifications on message receipt", enabled = enabled) }
item {
SwitchPreference(title = "Alert message LED",
checked = externalNotificationInput.alertMessage,
enabled = enabled,
onCheckedChange = {
externalNotificationInput = externalNotificationInput.copy { alertMessage = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Alert message buzzer",
checked = externalNotificationInput.alertMessageBuzzer,
enabled = enabled,
onCheckedChange = {
externalNotificationInput =
externalNotificationInput.copy { alertMessageBuzzer = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Alert message vibra",
checked = externalNotificationInput.alertMessageVibra,
enabled = enabled,
onCheckedChange = {
externalNotificationInput =
externalNotificationInput.copy { alertMessageVibra = it }
})
}
item { TextDividerPreference("Notifications on alert/bell receipt", enabled = enabled) }
item {
SwitchPreference(title = "Alert bell LED",
checked = externalNotificationInput.alertBell,
enabled = enabled,
onCheckedChange = {
externalNotificationInput = externalNotificationInput.copy { alertBell = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Alert bell buzzer",
checked = externalNotificationInput.alertBellBuzzer,
enabled = enabled,
onCheckedChange = {
externalNotificationInput =
externalNotificationInput.copy { alertBellBuzzer = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Alert bell vibra",
checked = externalNotificationInput.alertBellVibra,
enabled = enabled,
onCheckedChange = {
externalNotificationInput =
externalNotificationInput.copy { alertBellVibra = it }
})
}
item { Divider() }
item {
EditTextPreference(title = "Output LED (GPIO)",
value = externalNotificationInput.output,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
externalNotificationInput = externalNotificationInput.copy { output = it }
})
}
if (externalNotificationInput.output != 0) item {
SwitchPreference(title = "Output LED active high",
checked = externalNotificationInput.active,
enabled = enabled,
onCheckedChange = {
externalNotificationInput = externalNotificationInput.copy { active = it }
})
}
item { Divider() }
item {
EditTextPreference(title = "Output buzzer (GPIO)",
value = externalNotificationInput.outputBuzzer,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
externalNotificationInput = externalNotificationInput.copy { outputBuzzer = it }
})
}
if (externalNotificationInput.outputBuzzer != 0) item {
SwitchPreference(title = "Use PWM buzzer",
checked = externalNotificationInput.usePwm,
enabled = enabled,
onCheckedChange = {
externalNotificationInput = externalNotificationInput.copy { usePwm = it }
})
}
item { Divider() }
item {
EditTextPreference(title = "Output vibra (GPIO)",
value = externalNotificationInput.outputVibra,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
externalNotificationInput = externalNotificationInput.copy { outputVibra = it }
})
}
item {
EditTextPreference(title = "Output duration (milliseconds)",
value = externalNotificationInput.outputMs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
externalNotificationInput = externalNotificationInput.copy { outputMs = it }
})
}
item {
EditTextPreference(title = "Nag timeout (seconds)",
value = externalNotificationInput.nagTimeout,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
externalNotificationInput = externalNotificationInput.copy { nagTimeout = it }
})
}
item {
PreferenceFooter(
enabled = externalNotificationInput != externalNotificationConfig,
onCancelClicked = {
focusManager.clearFocus()
externalNotificationInput = externalNotificationConfig
},
onSaveClicked = { onSaveClicked(externalNotificationInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun ExternalNotificationConfigPreview(){
ExternalNotificationConfigItemList(
externalNotificationConfig = ExternalNotificationConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,195 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ConfigProtos.Config.LoRaConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.DropDownPreference
import com.geeksville.mesh.ui.components.EditListPreference
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun LoRaConfigItemList(
loraConfig: LoRaConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (LoRaConfig) -> Unit,
) {
var loraInput by remember(loraConfig) { mutableStateOf(loraConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "LoRa Config") }
item {
SwitchPreference(title = "Use modem preset",
checked = loraInput.usePreset,
enabled = enabled,
onCheckedChange = { loraInput = loraInput.copy { usePreset = it } })
}
item { Divider() }
if (loraInput.usePreset) {
item {
DropDownPreference(title = "Modem preset",
enabled = enabled && loraInput.usePreset,
items = LoRaConfig.ModemPreset.values()
.filter { it != LoRaConfig.ModemPreset.UNRECOGNIZED }
.map { it to it.name },
selectedItem = loraInput.modemPreset,
onItemSelected = { loraInput = loraInput.copy { modemPreset = it } })
}
item { Divider() }
} else {
item {
EditTextPreference(title = "Bandwidth",
value = loraInput.bandwidth,
enabled = enabled && !loraInput.usePreset,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { loraInput = loraInput.copy { bandwidth = it } })
}
item {
EditTextPreference(title = "Spread factor",
value = loraInput.spreadFactor,
enabled = enabled && !loraInput.usePreset,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { loraInput = loraInput.copy { spreadFactor = it } })
}
item {
EditTextPreference(title = "Coding rate",
value = loraInput.codingRate,
enabled = enabled && !loraInput.usePreset,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { loraInput = loraInput.copy { codingRate = it } })
}
}
item {
EditTextPreference(title = "Frequency offset (MHz)",
value = loraInput.frequencyOffset,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { loraInput = loraInput.copy { frequencyOffset = it } })
}
item {
DropDownPreference(title = "Region (frequency plan)",
enabled = enabled,
items = LoRaConfig.RegionCode.values()
.filter { it != LoRaConfig.RegionCode.UNRECOGNIZED }
.map { it to it.name },
selectedItem = loraInput.region,
onItemSelected = { loraInput = loraInput.copy { region = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Hop limit",
value = loraInput.hopLimit,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { loraInput = loraInput.copy { hopLimit = it } })
}
item {
SwitchPreference(title = "TX enabled",
checked = loraInput.txEnabled,
enabled = enabled,
onCheckedChange = { loraInput = loraInput.copy { txEnabled = it } })
}
item { Divider() }
item {
EditTextPreference(title = "TX power",
value = loraInput.txPower,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { loraInput = loraInput.copy { txPower = it } })
}
item {
EditTextPreference(title = "Channel number",
value = loraInput.channelNum,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { loraInput = loraInput.copy { channelNum = it } })
}
item {
SwitchPreference(title = "Override Duty Cycle",
checked = loraInput.overrideDutyCycle,
enabled = enabled,
onCheckedChange = { loraInput = loraInput.copy { overrideDutyCycle = it } })
}
item { Divider() }
item {
EditListPreference(title = "Ignore incoming",
list = loraInput.ignoreIncomingList,
maxCount = 3, // ignore_incoming max_count:3
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValuesChanged = { list ->
loraInput = loraInput.copy {
ignoreIncoming.clear()
ignoreIncoming.addAll(list.filter { it != 0 })
}
})
}
item {
SwitchPreference(title = "SX126X RX boosted gain",
checked = loraInput.sx126XRxBoostedGain,
enabled = enabled,
onCheckedChange = { loraInput = loraInput.copy { sx126XRxBoostedGain = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Override frequency (MHz)",
value = loraInput.overrideFrequency,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { loraInput = loraInput.copy { overrideFrequency = it } })
}
item {
PreferenceFooter(
enabled = loraInput != loraConfig,
onCancelClicked = {
focusManager.clearFocus()
loraInput = loraConfig
},
onSaveClicked = { onSaveClicked(loraInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun LoRaConfigPreview(){
LoRaConfigItemList(
loraConfig = LoRaConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,146 @@
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.foundation.text.KeyboardOptions
import androidx.compose.material.Divider
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.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction
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.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun MQTTConfigItemList(
mqttConfig: MQTTConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (MQTTConfig) -> Unit,
) {
var mqttInput by remember(mqttConfig) { mutableStateOf(mqttConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "MQTT Config") }
item {
SwitchPreference(title = "MQTT enabled",
checked = mqttInput.enabled,
enabled = enabled,
onCheckedChange = { mqttInput = mqttInput.copy { this.enabled = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Address",
value = mqttInput.address,
maxSize = 63, // address 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 { address = it } })
}
item {
EditTextPreference(title = "Username",
value = mqttInput.username,
maxSize = 63, // username 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 { username = it } })
}
item {
EditTextPreference(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 } })
}
item {
SwitchPreference(title = "Encryption enabled",
checked = mqttInput.encryptionEnabled,
enabled = enabled,
onCheckedChange = { mqttInput = mqttInput.copy { encryptionEnabled = it } })
}
item { Divider() }
item {
SwitchPreference(title = "JSON output enabled",
checked = mqttInput.jsonEnabled,
enabled = enabled,
onCheckedChange = { mqttInput = mqttInput.copy { jsonEnabled = it } })
}
item { Divider() }
item {
SwitchPreference(title = "TLS enabled",
checked = mqttInput.tlsEnabled,
enabled = enabled,
onCheckedChange = { mqttInput = mqttInput.copy { tlsEnabled = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Root topic",
value = mqttInput.root,
maxSize = 15, // root max_size:16
enabled = enabled,
isError = false,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Text, imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { mqttInput = mqttInput.copy { root = it } })
}
item {
PreferenceFooter(
enabled = mqttInput != mqttConfig,
onCancelClicked = {
focusManager.clearFocus()
mqttInput = mqttConfig
},
onSaveClicked = { onSaveClicked(mqttInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun MQTTConfigPreview(){
MQTTConfigItemList(
mqttConfig = MQTTConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,195 @@
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.foundation.text.KeyboardOptions
import androidx.compose.material.Divider
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.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
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.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun NetworkConfigItemList(
networkConfig: NetworkConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (NetworkConfig) -> Unit,
) {
var networkInput by remember(networkConfig) { mutableStateOf(networkConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Network Config") }
item {
SwitchPreference(title = "WiFi enabled",
checked = networkInput.wifiEnabled,
enabled = enabled,
onCheckedChange = { networkInput = networkInput.copy { wifiEnabled = it } })
}
item { Divider() }
item {
EditTextPreference(title = "SSID",
value = networkInput.wifiSsid,
maxSize = 32, // wifi_ssid max_size:33
enabled = enabled,
isError = false,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Text, imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
networkInput = networkInput.copy { wifiSsid = it }
})
}
item {
EditTextPreference(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 }
})
}
item {
EditTextPreference(title = "NTP server",
value = networkInput.ntpServer,
maxSize = 32, // ntp_server max_size:33
enabled = enabled,
isError = networkInput.ntpServer.isEmpty(),
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
networkInput = networkInput.copy { ntpServer = it }
})
}
item {
EditTextPreference(title = "rsyslog server",
value = networkInput.rsyslogServer,
maxSize = 32, // rsyslog_server max_size:33
enabled = enabled,
isError = false,
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
networkInput = networkInput.copy { rsyslogServer = it }
})
}
item {
SwitchPreference(title = "Ethernet enabled",
checked = networkInput.ethEnabled,
enabled = enabled,
onCheckedChange = { networkInput = networkInput.copy { ethEnabled = it } })
}
item { Divider() }
item {
DropDownPreference(title = "IPv4 mode",
enabled = enabled,
items = NetworkConfig.AddressMode.values()
.filter { it != NetworkConfig.AddressMode.UNRECOGNIZED }
.map { it to it.name },
selectedItem = networkInput.addressMode,
onItemSelected = { networkInput = networkInput.copy { addressMode = it } })
}
item { Divider() }
item {
EditIPv4Preference(title = "IP",
value = networkInput.ipv4Config.ip,
enabled = enabled && networkInput.addressMode == NetworkConfig.AddressMode.STATIC,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
val ipv4 = networkInput.ipv4Config.copy { ip = it }
networkInput = networkInput.copy { ipv4Config = ipv4 }
})
}
item {
EditIPv4Preference(title = "Gateway",
value = networkInput.ipv4Config.gateway,
enabled = enabled && networkInput.addressMode == NetworkConfig.AddressMode.STATIC,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
val ipv4 = networkInput.ipv4Config.copy { gateway = it }
networkInput = networkInput.copy { ipv4Config = ipv4 }
})
}
item {
EditIPv4Preference(title = "Subnet",
value = networkInput.ipv4Config.subnet,
enabled = enabled && networkInput.addressMode == NetworkConfig.AddressMode.STATIC,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
val ipv4 = networkInput.ipv4Config.copy { subnet = it }
networkInput = networkInput.copy { ipv4Config = ipv4 }
})
}
item {
EditIPv4Preference(title = "DNS",
value = networkInput.ipv4Config.dns,
enabled = enabled && networkInput.addressMode == NetworkConfig.AddressMode.STATIC,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
val ipv4 = networkInput.ipv4Config.copy { dns = it }
networkInput = networkInput.copy { ipv4Config = ipv4 }
})
}
item {
PreferenceFooter(
enabled = networkInput != networkConfig,
onCancelClicked = {
focusManager.clearFocus()
networkInput = networkConfig
},
onSaveClicked = { onSaveClicked(networkInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun NetworkConfigPreview(){
NetworkConfigItemList(
networkConfig = NetworkConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,200 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.ConfigProtos.Config.PositionConfig
import com.geeksville.mesh.Position
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.BitwisePreference
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun PositionConfigItemList(
positionInfo: Position?,
positionConfig: PositionConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (Pair<Position?, PositionConfig>) -> Unit,
) {
var locationInput by remember(positionInfo) { mutableStateOf(positionInfo) }
var positionInput by remember(positionConfig) { mutableStateOf(positionConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Position Config") }
item {
EditTextPreference(title = "Position broadcast interval (seconds)",
value = positionInput.positionBroadcastSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
positionInput = positionInput.copy { positionBroadcastSecs = it }
})
}
item {
SwitchPreference(title = "Smart position enabled",
checked = positionInput.positionBroadcastSmartEnabled,
enabled = enabled,
onCheckedChange = {
positionInput = positionInput.copy { positionBroadcastSmartEnabled = it }
})
}
item { Divider() }
if (positionInput.positionBroadcastSmartEnabled) {
item {
EditTextPreference(title = "Smart broadcast minimum distance (meters)",
value = positionInput.broadcastSmartMinimumDistance,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
positionInput = positionInput.copy { broadcastSmartMinimumDistance = it }
})
}
item {
EditTextPreference(title = "Smart broadcast minimum interval (seconds)",
value = positionInput.broadcastSmartMinimumIntervalSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
positionInput = positionInput.copy { broadcastSmartMinimumIntervalSecs = it }
})
}
}
item {
SwitchPreference(title = "Use fixed position",
checked = positionInput.fixedPosition,
enabled = enabled,
onCheckedChange = { positionInput = positionInput.copy { fixedPosition = it } })
}
item { Divider() }
if (positionInput.fixedPosition) {
item {
EditTextPreference(title = "Latitude",
value = locationInput?.latitude ?: 0.0,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { value ->
if (value >= -90 && value <= 90.0)
locationInput?.let { locationInput = it.copy(latitude = value) }
})
}
item {
EditTextPreference(title = "Longitude",
value = locationInput?.longitude ?: 0.0,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { value ->
if (value >= -180 && value <= 180.0)
locationInput?.let { locationInput = it.copy(longitude = value) }
})
}
item {
EditTextPreference(title = "Altitude (meters)",
value = locationInput?.altitude ?: 0,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { value ->
locationInput?.let { locationInput = it.copy(altitude = value) }
})
}
}
item {
SwitchPreference(title = "GPS enabled",
checked = positionInput.gpsEnabled,
enabled = enabled,
onCheckedChange = { positionInput = positionInput.copy { gpsEnabled = it } })
}
item { Divider() }
item {
EditTextPreference(title = "GPS update interval (seconds)",
value = positionInput.gpsUpdateInterval,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { positionInput = positionInput.copy { gpsUpdateInterval = it } })
}
item {
EditTextPreference(title = "Fix attempt duration (seconds)",
value = positionInput.gpsAttemptTime,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { positionInput = positionInput.copy { gpsAttemptTime = it } })
}
item {
BitwisePreference(title = "Position flags",
value = positionInput.positionFlags,
enabled = enabled,
items = ConfigProtos.Config.PositionConfig.PositionFlags.values()
.filter { it != PositionConfig.PositionFlags.UNSET && it != PositionConfig.PositionFlags.UNRECOGNIZED }
.map { it.number to it.name },
onItemSelected = { positionInput = positionInput.copy { positionFlags = it } }
)
}
item { Divider() }
item {
EditTextPreference(title = "Redefine GPS_RX_PIN",
value = positionInput.rxGpio,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { positionInput = positionInput.copy { rxGpio = it } })
}
item {
EditTextPreference(title = "Redefine GPS_TX_PIN",
value = positionInput.txGpio,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { positionInput = positionInput.copy { txGpio = it } })
}
item {
PreferenceFooter(
enabled = positionInput != positionConfig || locationInput != positionInfo,
onCancelClicked = {
focusManager.clearFocus()
locationInput = positionInfo
positionInput = positionConfig
},
onSaveClicked = { onSaveClicked(Pair(locationInput, positionInput)) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun PositionConfigPreview(){
PositionConfigItemList(
positionInfo = null,
positionConfig = PositionConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,125 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ConfigProtos.Config.PowerConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun PowerConfigItemList(
powerConfig: PowerConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (PowerConfig) -> Unit,
) {
var powerInput by remember(powerConfig) { mutableStateOf(powerConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Power Config") }
item {
SwitchPreference(title = "Enable power saving mode",
checked = powerInput.isPowerSaving,
enabled = enabled,
onCheckedChange = { powerInput = powerInput.copy { isPowerSaving = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Shutdown on battery delay (seconds)",
value = powerInput.onBatteryShutdownAfterSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
powerInput = powerInput.copy { onBatteryShutdownAfterSecs = it }
})
}
item {
EditTextPreference(title = "ADC multiplier override ratio",
value = powerInput.adcMultiplierOverride,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { powerInput = powerInput.copy { adcMultiplierOverride = it } })
}
item {
EditTextPreference(title = "Wait for Bluetooth duration (seconds)",
value = powerInput.waitBluetoothSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { powerInput = powerInput.copy { waitBluetoothSecs = it } })
}
item {
EditTextPreference(title = "Mesh SDS timeout (seconds)",
value = powerInput.meshSdsTimeoutSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { powerInput = powerInput.copy { meshSdsTimeoutSecs = it } })
}
item {
EditTextPreference(title = "Super deep sleep duration (seconds)",
value = powerInput.sdsSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { powerInput = powerInput.copy { sdsSecs = it } })
}
item {
EditTextPreference(title = "Light sleep duration (seconds)",
value = powerInput.lsSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { powerInput = powerInput.copy { lsSecs = it } })
}
item {
EditTextPreference(title = "Minimum wake time (seconds)",
value = powerInput.minWakeSecs,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { powerInput = powerInput.copy { minWakeSecs = it } })
}
item {
PreferenceFooter(
enabled = powerInput != powerConfig,
onCancelClicked = {
focusManager.clearFocus()
powerInput = powerConfig
},
onSaveClicked = { onSaveClicked(powerInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun PowerConfigPreview(){
PowerConfigItemList(
powerConfig = PowerConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,83 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.RangeTestConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun RangeTestConfigItemList(
rangeTestConfig: RangeTestConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (RangeTestConfig) -> Unit,
) {
var rangeTestInput by remember(rangeTestConfig) { mutableStateOf(rangeTestConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Range Test Config") }
item {
SwitchPreference(title = "Range test enabled",
checked = rangeTestInput.enabled,
enabled = enabled,
onCheckedChange = { rangeTestInput = rangeTestInput.copy { this.enabled = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Sender message interval (seconds)",
value = rangeTestInput.sender,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { rangeTestInput = rangeTestInput.copy { sender = it } })
}
item {
SwitchPreference(title = "Save .CSV in storage (ESP32 only)",
checked = rangeTestInput.save,
enabled = enabled,
onCheckedChange = { rangeTestInput = rangeTestInput.copy { save = it } })
}
item { Divider() }
item {
PreferenceFooter(
enabled = rangeTestInput != rangeTestConfig,
onCancelClicked = {
focusManager.clearFocus()
rangeTestInput = rangeTestConfig
},
onSaveClicked = { onSaveClicked(rangeTestInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun RangeTestConfig(){
RangeTestConfigItemList(
rangeTestConfig = RangeTestConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,67 @@
package com.geeksville.mesh.ui.components.config
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Divider
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.focus.FocusManager
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.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun RemoteHardwareConfigItemList(
remoteHardwareConfig: RemoteHardwareConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (RemoteHardwareConfig) -> Unit,
) {
var remoteHardwareInput by remember(remoteHardwareConfig) { mutableStateOf(remoteHardwareConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Remote Hardware Config") }
item {
SwitchPreference(title = "Remote Hardware enabled",
checked = remoteHardwareInput.enabled,
enabled = enabled,
onCheckedChange = {
remoteHardwareInput = remoteHardwareInput.copy { this.enabled = it }
})
}
item { Divider() }
item {
PreferenceFooter(
enabled = remoteHardwareInput != remoteHardwareConfig,
onCancelClicked = {
focusManager.clearFocus()
remoteHardwareInput = remoteHardwareConfig
},
onSaveClicked = { onSaveClicked(remoteHardwareInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun RemoteHardwareConfigPreview(){
RemoteHardwareConfigItemList(
remoteHardwareConfig = RemoteHardwareConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,122 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.SerialConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.DropDownPreference
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun SerialConfigItemList(
serialConfig: SerialConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (SerialConfig) -> Unit,
) {
var serialInput by remember(serialConfig) { mutableStateOf(serialConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Serial Config") }
item {
SwitchPreference(title = "Serial enabled",
checked = serialInput.enabled,
enabled = enabled,
onCheckedChange = { serialInput = serialInput.copy { this.enabled = it } })
}
item { Divider() }
item {
SwitchPreference(title = "Echo enabled",
checked = serialInput.echo,
enabled = enabled,
onCheckedChange = { serialInput = serialInput.copy { echo = it } })
}
item { Divider() }
item {
EditTextPreference(title = "RX",
value = serialInput.rxd,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { serialInput = serialInput.copy { rxd = it } })
}
item {
EditTextPreference(title = "TX",
value = serialInput.txd,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { serialInput = serialInput.copy { txd = it } })
}
item {
DropDownPreference(title = "Serial baud rate",
enabled = enabled,
items = SerialConfig.Serial_Baud.values()
.filter { it != SerialConfig.Serial_Baud.UNRECOGNIZED }
.map { it to it.name },
selectedItem = serialInput.baud,
onItemSelected = { serialInput = serialInput.copy { baud = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Timeout",
value = serialInput.timeout,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { serialInput = serialInput.copy { timeout = it } })
}
item {
DropDownPreference(title = "Serial mode",
enabled = enabled,
items = SerialConfig.Serial_Mode.values()
.filter { it != SerialConfig.Serial_Mode.UNRECOGNIZED }
.map { it to it.name },
selectedItem = serialInput.mode,
onItemSelected = { serialInput = serialInput.copy { mode = it } })
}
item { Divider() }
item {
PreferenceFooter(
enabled = serialInput != serialConfig,
onCancelClicked = {
focusManager.clearFocus()
serialInput = serialConfig
},
onSaveClicked = { onSaveClicked(serialInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun SerialConfigPreview(){
SerialConfigItemList(
serialConfig = SerialConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,105 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.StoreForwardConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun StoreForwardConfigItemList(
storeForwardConfig: StoreForwardConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (StoreForwardConfig) -> Unit,
) {
var storeForwardInput by remember(storeForwardConfig) { mutableStateOf(storeForwardConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Store & Forward Config") }
item {
SwitchPreference(title = "Store & Forward enabled",
checked = storeForwardInput.enabled,
enabled = enabled,
onCheckedChange = {
storeForwardInput = storeForwardInput.copy { this.enabled = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Heartbeat",
checked = storeForwardInput.heartbeat,
enabled = enabled,
onCheckedChange = { storeForwardInput = storeForwardInput.copy { heartbeat = it } })
}
item { Divider() }
item {
EditTextPreference(title = "Number of records",
value = storeForwardInput.records,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { storeForwardInput = storeForwardInput.copy { records = it } })
}
item {
EditTextPreference(title = "History return max",
value = storeForwardInput.historyReturnMax,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
storeForwardInput = storeForwardInput.copy { historyReturnMax = it }
})
}
item {
EditTextPreference(title = "History return window",
value = storeForwardInput.historyReturnWindow,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
storeForwardInput = storeForwardInput.copy { historyReturnWindow = it }
})
}
item {
PreferenceFooter(
enabled = storeForwardInput != storeForwardConfig,
onCancelClicked = {
focusManager.clearFocus()
storeForwardInput = storeForwardConfig
},
onSaveClicked = { onSaveClicked(storeForwardInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun StoreForwardConfigPreview(){
StoreForwardConfigItemList(
storeForwardConfig = StoreForwardConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,109 @@
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
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig.TelemetryConfig
import com.geeksville.mesh.copy
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun TelemetryConfigItemList(
telemetryConfig: TelemetryConfig,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (TelemetryConfig) -> Unit,
) {
var telemetryInput by remember(telemetryConfig) { mutableStateOf(telemetryConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "Telemetry Config") }
item {
EditTextPreference(title = "Device metrics update interval (seconds)",
value = telemetryInput.deviceUpdateInterval,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
telemetryInput = telemetryInput.copy { deviceUpdateInterval = it }
})
}
item {
EditTextPreference(title = "Environment metrics update interval (seconds)",
value = telemetryInput.environmentUpdateInterval,
enabled = enabled,
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
telemetryInput = telemetryInput.copy { environmentUpdateInterval = it }
})
}
item {
SwitchPreference(title = "Environment metrics module enabled",
checked = telemetryInput.environmentMeasurementEnabled,
enabled = enabled,
onCheckedChange = {
telemetryInput = telemetryInput.copy { environmentMeasurementEnabled = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Environment metrics on-screen enabled",
checked = telemetryInput.environmentScreenEnabled,
enabled = enabled,
onCheckedChange = {
telemetryInput = telemetryInput.copy { environmentScreenEnabled = it }
})
}
item { Divider() }
item {
SwitchPreference(title = "Environment metrics use Fahrenheit",
checked = telemetryInput.environmentDisplayFahrenheit,
enabled = enabled,
onCheckedChange = {
telemetryInput = telemetryInput.copy { environmentDisplayFahrenheit = it }
})
}
item { Divider() }
item {
PreferenceFooter(
enabled = telemetryInput != telemetryConfig,
onCancelClicked = {
focusManager.clearFocus()
telemetryInput = telemetryConfig
},
onSaveClicked = { onSaveClicked(telemetryInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun TelemetryConfigPreview(){
TelemetryConfigItemList(
telemetryConfig = TelemetryConfig.getDefaultInstance(),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}

View file

@ -0,0 +1,121 @@
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.foundation.text.KeyboardOptions
import androidx.compose.material.Divider
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.focus.FocusManager
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.MeshUser
import com.geeksville.mesh.model.getInitials
import com.geeksville.mesh.ui.components.EditTextPreference
import com.geeksville.mesh.ui.components.PreferenceCategory
import com.geeksville.mesh.ui.components.PreferenceFooter
import com.geeksville.mesh.ui.components.RegularPreference
import com.geeksville.mesh.ui.components.SwitchPreference
@Composable
fun UserConfigItemList(
userConfig: MeshUser,
enabled: Boolean,
focusManager: FocusManager,
onSaveClicked: (MeshUser) -> Unit,
) {
var userInput by remember(userConfig) { mutableStateOf(userConfig) }
LazyColumn(
modifier = Modifier.fillMaxSize()
) {
item { PreferenceCategory(text = "User Config") }
item {
RegularPreference(title = "Node ID",
subtitle = userInput.id,
onClick = {})
}
item { Divider() }
item {
EditTextPreference(title = "Long name",
value = userInput.longName,
maxSize = 39, // long_name max_size:40
enabled = enabled,
isError = userInput.longName.isEmpty(),
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Text, imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = {
userInput = userInput.copy(longName = it)
if (getInitials(it).toByteArray().size <= 4) // short_name max_size:5
userInput = userInput.copy(shortName = getInitials(it))
})
}
item {
EditTextPreference(title = "Short name",
value = userInput.shortName,
maxSize = 4, // short_name max_size:5
enabled = enabled,
isError = userInput.shortName.isEmpty(),
keyboardOptions = KeyboardOptions.Default.copy(
keyboardType = KeyboardType.Text, imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
onValueChanged = { userInput = userInput.copy(shortName = it) })
}
item {
RegularPreference(title = "Hardware model",
subtitle = userInput.hwModel.name,
onClick = {})
}
item { Divider() }
item {
SwitchPreference(title = "Licensed amateur radio",
checked = userInput.isLicensed,
enabled = enabled,
onCheckedChange = { userInput = userInput.copy(isLicensed = it) })
}
item { Divider() }
item {
PreferenceFooter(
enabled = userInput != userConfig,
onCancelClicked = {
focusManager.clearFocus()
userInput = userConfig
}, onSaveClicked = { onSaveClicked(userInput) }
)
}
}
}
@Preview(showBackground = true)
@Composable
fun UserConfigPreview(){
UserConfigItemList(
userConfig = MeshUser(
id = "!a280d9c8",
longName = "Meshtastic d9c8",
shortName = "d9c8",
hwModel = MeshProtos.HardwareModel.RAK4631,
isLicensed = false
),
enabled = true,
focusManager = LocalFocusManager.current,
onSaveClicked = { },
)
}