From 7b1b91e5da771d5ab8d88543db157bd259a68d21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sylwester=20Zieli=C5=84ski?= Date: Thu, 17 Feb 2022 11:00:33 +0100 Subject: [PATCH] Apply fixes to UART profile --- .../nordicsemi/android/uart/data/UARTMacro.kt | 9 +- .../android/uart/data/UARTManager.kt | 3 +- .../android/uart/data/UARTParser.kt | 9 ++ .../android/uart/view/UARTAddMacroDialog.kt | 133 +++++++++++++----- .../android/uart/view/UARTContentView.kt | 10 +- .../android/uart/view/UARTMapper.kt | 15 ++ .../nordicsemi/android/uart/view/UARTViews.kt | 13 +- profile_uart/src/main/res/values/strings.xml | 9 ++ 8 files changed, 144 insertions(+), 57 deletions(-) create mode 100644 profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTParser.kt create mode 100644 profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTMapper.kt diff --git a/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTMacro.kt b/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTMacro.kt index ae42f710..d8dd866d 100644 --- a/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTMacro.kt +++ b/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTMacro.kt @@ -1,6 +1,7 @@ package no.nordicsemi.android.uart.data -data class UARTMacro( - val alias: String, - val command: String, -) +data class UARTMacro(val command: String, val newLineChar: NewLineChar) + +enum class NewLineChar { + LF, CR_LF, CR +} diff --git a/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTManager.kt b/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTManager.kt index 4af26704..e8415b66 100644 --- a/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTManager.kt +++ b/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTManager.kt @@ -36,7 +36,6 @@ import no.nordicsemi.android.ble.common.callback.battery.BatteryLevelResponse import no.nordicsemi.android.ble.ktx.asFlow import no.nordicsemi.android.ble.ktx.asValidResponseFlow import no.nordicsemi.android.service.ConnectionObserverAdapter -import no.nordicsemi.android.uart.data.UARTData import no.nordicsemi.android.utils.EMPTY import no.nordicsemi.android.utils.launchWithCatch import java.util.* @@ -76,7 +75,7 @@ internal class UARTManager( override fun initialize() { setNotificationCallback(txCharacteristic).asFlow().onEach { val text: String = it.getStringValue(0) ?: String.EMPTY - data.tryEmit(data.value.copy(text = text)) + data.value = data.value.copy(text = text) } requestMtu(260).enqueue() diff --git a/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTParser.kt b/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTParser.kt new file mode 100644 index 00000000..a766d2f7 --- /dev/null +++ b/profile_uart/src/main/java/no/nordicsemi/android/uart/data/UARTParser.kt @@ -0,0 +1,9 @@ +package no.nordicsemi.android.uart.data + +fun NewLineChar.parseString(text: String): String { + return when (this) { + NewLineChar.LF -> text + NewLineChar.CR_LF -> text.replace("\n", "\r\n") + NewLineChar.CR -> text.replace("\n", "\r") + } +} diff --git a/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTAddMacroDialog.kt b/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTAddMacroDialog.kt index 38125332..e2d4bc36 100644 --- a/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTAddMacroDialog.kt +++ b/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTAddMacroDialog.kt @@ -1,63 +1,124 @@ package no.nordicsemi.android.uart.view -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.size -import androidx.compose.material3.AlertDialog +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import no.nordicsemi.android.material.you.HorizontalLabelRadioButtonGroup +import no.nordicsemi.android.material.you.RadioButtonItem +import no.nordicsemi.android.material.you.RadioGroupViewEntity import no.nordicsemi.android.material.you.TextField import no.nordicsemi.android.uart.R +import no.nordicsemi.android.uart.data.NewLineChar import no.nordicsemi.android.uart.data.UARTMacro import no.nordicsemi.android.utils.EMPTY @Composable internal fun UARTAddMacroDialog(onDismiss: () -> Unit, onEvent: (UARTViewEvent) -> Unit) { - val alias = remember { mutableStateOf(String.EMPTY) } val command = remember { mutableStateOf(String.EMPTY) } + val newLineChar = remember { mutableStateOf(NewLineChar.LF) } + val isError = remember { mutableStateOf(false) } - AlertDialog( - onDismissRequest = onDismiss, - containerColor = MaterialTheme.colorScheme.background, - title = { - Text(text = stringResource(id = R.string.uart_macro_dialog_title)) - }, - text = { + Dialog(onDismissRequest = { onDismiss() }) { + Surface( + color = MaterialTheme.colorScheme.background, + shape = RoundedCornerShape(10.dp), + shadowElevation = 0.dp, + ) { Column { - TextField(text = alias.value, hint = stringResource(id = R.string.uart_macro_dialog_alias)) { - alias.value = it - } + Text( + text = stringResource(id = R.string.uart_macro_dialog_title), + style = MaterialTheme.typography.headlineSmall, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + ) - Spacer(modifier = Modifier.size(16.dp)) + Column(modifier = Modifier.verticalScroll(rememberScrollState())) { + Column(modifier = Modifier.padding(bottom = 8.dp, start = 16.dp, end = 16.dp)) { - TextField(text = command.value, hint = stringResource(id = R.string.uart_macro_dialog_command)) { - command.value = it + NewLineCharSection(newLineChar.value) { newLineChar.value = it } + + Spacer(modifier = Modifier.size(16.dp)) + + TextField( + text = command.value, + hint = stringResource(id = R.string.uart_macro_dialog_command) + ) { + isError.value = false + command.value = it + } + + if (isError.value) { + Text( + text = stringResource(id = R.string.uart_macro_error), + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.error + ) + } + + Spacer(modifier = Modifier.size(16.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + TextButton(onClick = { onDismiss() }) { + Text(stringResource(id = R.string.uart_macro_dialog_dismiss)) + } + + Spacer(modifier = Modifier.size(16.dp)) + + TextButton(onClick = { + if (isCommandValid(command.value)) { + onDismiss() + onEvent(OnCreateMacro(UARTMacro(command.value, newLineChar.value))) + } else { + isError.value = true + } + }) { + Text(stringResource(id = R.string.uart_macro_dialog_confirm)) + } + } + } } } - }, - confirmButton = { - TextButton( - onClick = { - onDismiss() - onEvent(OnCreateMacro(UARTMacro(alias.value, command.value))) - } - ) { - Text(stringResource(id = R.string.uart_macro_dialog_confirm)) - } - }, - dismissButton = { - TextButton( - onClick = { onDismiss() } - ) { - Text(stringResource(id = R.string.uart_macro_dialog_dismiss)) - } } - ) + } +} + +@Composable +private fun NewLineCharSection(checkedItem: NewLineChar, onItemClick: (NewLineChar) -> Unit) { + val items = NewLineChar.values().map { + RadioButtonItem(it.toDisplayString(), it == checkedItem) + } + val viewEntity = RadioGroupViewEntity(items) + + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + text = stringResource(id = R.string.uart_macro_dialog_eol), + style = MaterialTheme.typography.labelLarge + ) + + HorizontalLabelRadioButtonGroup(viewEntity) { + val i = items.indexOf(it) + onItemClick(NewLineChar.values()[i]) + } + } +} + +private fun isCommandValid(command: String): Boolean { + return command.isNotBlank() } diff --git a/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTContentView.kt b/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTContentView.kt index 9e917411..845dacc6 100644 --- a/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTContentView.kt +++ b/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTContentView.kt @@ -26,15 +26,13 @@ internal fun UARTContentView(state: UARTData, macros: List, onEvent: horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(16.dp) ) { - InputSection(macros, onEvent) + OutputSection(state.text) Spacer(modifier = Modifier.height(16.dp)) - if (state.text.isNotEmpty()) { - OutputSection(state.text) + InputSection(macros, onEvent) - Spacer(modifier = Modifier.height(16.dp)) - } + Spacer(modifier = Modifier.height(16.dp)) Button( onClick = { onEvent(DisconnectEvent) } @@ -94,7 +92,7 @@ private fun OutputSection(text: String) { Spacer(modifier = Modifier.height(16.dp)) - Text(text = text) + Text(text = text.ifBlank { stringResource(id = R.string.uart_output_placeholder) }) } } } diff --git a/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTMapper.kt b/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTMapper.kt new file mode 100644 index 00000000..31655f90 --- /dev/null +++ b/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTMapper.kt @@ -0,0 +1,15 @@ +package no.nordicsemi.android.uart.view + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import no.nordicsemi.android.uart.R +import no.nordicsemi.android.uart.data.NewLineChar + +@Composable +fun NewLineChar.toDisplayString(): String { + return when (this) { + NewLineChar.LF -> stringResource(id = R.string.uart_macro_dialog_lf) + NewLineChar.CR_LF -> stringResource(id = R.string.uart_macro_dialog_cr_lf) + NewLineChar.CR -> stringResource(id = R.string.uart_macro_dialog_cr) + } +} diff --git a/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTViews.kt b/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTViews.kt index 98bef87e..dd0a0b3d 100644 --- a/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTViews.kt +++ b/profile_uart/src/main/java/no/nordicsemi/android/uart/view/UARTViews.kt @@ -1,12 +1,7 @@ package no.nordicsemi.android.uart.view import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Delete @@ -42,11 +37,11 @@ internal fun MacroItem(macro: UARTMacro, onEvent: (UARTViewEvent) -> Unit) { Spacer(modifier = Modifier.size(16.dp)) - Column(modifier = Modifier.weight(1f)) { + Column(modifier = Modifier.weight(1f).padding(vertical = 8.dp)) { Text( - text = macro.alias, + text = stringResource(id = R.string.uart_macro_dialog_selected_eol, macro.newLineChar.toDisplayString()), style = MaterialTheme.typography.titleMedium, - color = MaterialTheme.colorScheme.onPrimaryContainer + color = MaterialTheme.colorScheme.onPrimaryContainer, ) Text( text = stringResource(id = R.string.uart_command_field, macro.command), diff --git a/profile_uart/src/main/res/values/strings.xml b/profile_uart/src/main/res/values/strings.xml index d5e9a1e8..90ec249d 100644 --- a/profile_uart/src/main/res/values/strings.xml +++ b/profile_uart/src/main/res/values/strings.xml @@ -20,4 +20,13 @@ Command Confirm Dismiss + + EOL: + EOL: %s + LF + CR + LF + CR + + The incoming messages will be displayed here. + Provided command cannot be empty.