mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2026-01-08 17:24:31 +01:00
Add switch between macro and text input
This commit is contained in:
@@ -71,6 +71,7 @@ fun BackIconAppBar(text: String, onClick: () -> Unit) {
|
||||
IconButton(onClick = { onClick() }) {
|
||||
Icon(
|
||||
Icons.Default.ArrowBack,
|
||||
tint = MaterialTheme.colorScheme.onPrimary,
|
||||
contentDescription = stringResource(id = R.string.back_screen),
|
||||
)
|
||||
}
|
||||
@@ -103,6 +104,7 @@ fun LoggerIconAppBar(text: String, onClick: () -> Unit, onLoggerClick: () -> Uni
|
||||
IconButton(onClick = { onClick() }) {
|
||||
Icon(
|
||||
Icons.Default.ArrowBack,
|
||||
tint = MaterialTheme.colorScheme.onPrimary,
|
||||
contentDescription = stringResource(id = R.string.back_screen),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import no.nordicsemi.android.material.you.*
|
||||
import no.nordicsemi.android.theme.view.SectionTitle
|
||||
import no.nordicsemi.android.uart.R
|
||||
import no.nordicsemi.android.uart.data.MacroEol
|
||||
import no.nordicsemi.android.utils.EMPTY
|
||||
|
||||
@Composable
|
||||
internal fun InputSection(onEvent: (UARTViewEvent) -> Unit) {
|
||||
val text = rememberSaveable { mutableStateOf(String.EMPTY) }
|
||||
val hint = stringResource(id = R.string.uart_input_hint)
|
||||
val checkedItem = rememberSaveable { mutableStateOf(MacroEol.values()[0]) }
|
||||
|
||||
val items = MacroEol.values().map {
|
||||
RadioButtonItem(it.toDisplayString(), it == checkedItem.value)
|
||||
}
|
||||
val viewEntity = RadioGroupViewEntity(items)
|
||||
|
||||
ScreenSection {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
SectionTitle(
|
||||
resId = R.drawable.ic_input,
|
||||
title = stringResource(R.string.uart_input),
|
||||
menu = {
|
||||
IconButton(onClick = { onEvent(MacroInputSwitchClick) }) {
|
||||
Icon(
|
||||
painterResource(id = R.drawable.ic_macro),
|
||||
contentDescription = stringResource(id = R.string.uart_input_macro),
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.uart_macro_dialog_eol),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
|
||||
RadioButtonGroup(viewEntity) {
|
||||
val i = items.indexOf(it)
|
||||
checkedItem.value = MacroEol.values()[i]
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(modifier = Modifier.weight(1f)) {
|
||||
TextField(text = text.value, hint = hint) {
|
||||
text.value = it
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
Button(
|
||||
onClick = { onEvent(OnRunInput(text.value, checkedItem.value)) },
|
||||
modifier = Modifier.padding(top = 6.dp)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.uart_send))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import no.nordicsemi.android.material.you.ScreenSection
|
||||
import no.nordicsemi.android.theme.view.SectionTitle
|
||||
import no.nordicsemi.android.uart.R
|
||||
|
||||
@Composable
|
||||
internal fun MacroSection(viewState: UARTViewState, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val showAddDialog = rememberSaveable { mutableStateOf(false) }
|
||||
val showDeleteDialog = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
if (showAddDialog.value) {
|
||||
UARTAddConfigurationDialog(onEvent) { showAddDialog.value = false }
|
||||
}
|
||||
|
||||
if (showDeleteDialog.value) {
|
||||
DeleteConfigurationDialog(onEvent) { showDeleteDialog.value = false }
|
||||
}
|
||||
|
||||
ScreenSection {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
SectionTitle(
|
||||
resId = R.drawable.ic_macro,
|
||||
title = stringResource(R.string.uart_macros),
|
||||
menu = {
|
||||
IconButton(onClick = { onEvent(MacroInputSwitchClick) }) {
|
||||
Icon(
|
||||
painterResource(id = R.drawable.ic_input),
|
||||
contentDescription = stringResource(id = R.string.uart_input_macro),
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Row {
|
||||
Box(modifier = Modifier.weight(1f)) {
|
||||
UARTConfigurationPicker(viewState, onEvent)
|
||||
}
|
||||
|
||||
IconButton(onClick = { showAddDialog.value = true }) {
|
||||
Icon(Icons.Default.Add, stringResource(id = R.string.uart_configuration_add))
|
||||
}
|
||||
|
||||
viewState.selectedConfiguration?.let {
|
||||
|
||||
if (!viewState.isConfigurationEdited) {
|
||||
IconButton(onClick = { onEvent(OnEditConfiguration) }) {
|
||||
Icon(
|
||||
Icons.Default.Edit,
|
||||
stringResource(id = R.string.uart_configuration_edit)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
IconButton(onClick = { onEvent(OnEditConfiguration) }) {
|
||||
Icon(
|
||||
painterResource(id = R.drawable.ic_pencil_off),
|
||||
stringResource(id = R.string.uart_configuration_edit)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(onClick = { showDeleteDialog.value = true }) {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
stringResource(id = R.string.uart_configuration_delete)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewState.selectedConfiguration?.let {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
UARTMacroView(it, viewState.isConfigurationEdited, onEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeleteConfigurationDialog(onEvent: (UARTViewEvent) -> Unit, onDismiss: () -> Unit) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.uart_delete_dialog_title),
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(id = R.string.uart_delete_dialog_info))
|
||||
},
|
||||
confirmButton = {
|
||||
Button(onClick = {
|
||||
onDismiss()
|
||||
onEvent(OnDeleteConfiguration)
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.uart_delete_dialog_confirm))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = onDismiss) {
|
||||
Text(text = stringResource(id = R.string.uart_delete_dialog_cancel))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import no.nordicsemi.android.theme.view.SectionTitle
|
||||
import no.nordicsemi.android.uart.R
|
||||
import no.nordicsemi.android.uart.data.UARTRecord
|
||||
import no.nordicsemi.android.uart.data.UARTRecordType
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
internal fun OutputSection(records: List<UARTRecord>, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val scrollDown = remember { mutableStateOf(true) }
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
SectionTitle(
|
||||
resId = R.drawable.ic_output,
|
||||
title = stringResource(R.string.uart_output),
|
||||
modifier = Modifier,
|
||||
menu = { Menu(scrollDown, onEvent) }
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
LazyColumn(
|
||||
userScrollEnabled = !scrollDown.value,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
state = listState
|
||||
) {
|
||||
if (records.isEmpty()) {
|
||||
item { Text(text = stringResource(id = R.string.uart_output_placeholder)) }
|
||||
} else {
|
||||
records.forEach {
|
||||
item {
|
||||
MessageItem(record = it)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(records, scrollDown.value) {
|
||||
if (!scrollDown.value || records.isEmpty()) {
|
||||
return@LaunchedEffect
|
||||
}
|
||||
launch {
|
||||
listState.scrollToItem(records.lastIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MessageItem(record: UARTRecord) {
|
||||
Column {
|
||||
Text(
|
||||
text = record.timeToString(),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.outline
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = createRecordText(record = record),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = createRecordColor(record = record)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Menu(scrollDown: MutableState<Boolean>, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val icon = when (scrollDown.value) {
|
||||
true -> R.drawable.ic_sync_down_off
|
||||
false -> R.drawable.ic_sync_down
|
||||
}
|
||||
Row {
|
||||
IconButton(onClick = { scrollDown.value = !scrollDown.value }) {
|
||||
Icon(
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = stringResource(id = R.string.uart_scroll_down)
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(onClick = { onEvent(ClearOutputItems) }) {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
contentDescription = stringResource(id = R.string.uart_clear_items),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun createRecordText(record: UARTRecord): String {
|
||||
return when (record.type) {
|
||||
UARTRecordType.INPUT -> stringResource(id = R.string.uart_input_log, record.text)
|
||||
UARTRecordType.OUTPUT -> stringResource(id = R.string.uart_output_log, record.text)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun createRecordColor(record: UARTRecord): Color {
|
||||
return when (record.type) {
|
||||
UARTRecordType.INPUT -> colorResource(id = R.color.nordicGrass)
|
||||
UARTRecordType.OUTPUT -> MaterialTheme.colorScheme.onBackground
|
||||
}
|
||||
}
|
||||
|
||||
private val datFormatter = SimpleDateFormat("dd MMMM yyyy, HH:mm:ss", Locale.ENGLISH)
|
||||
|
||||
private fun UARTRecord.timeToString(): String {
|
||||
return datFormatter.format(timestamp)
|
||||
}
|
||||
@@ -1,37 +1,18 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
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.graphics.Color
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import no.nordicsemi.android.material.you.*
|
||||
import no.nordicsemi.android.theme.view.SectionTitle
|
||||
import no.nordicsemi.android.material.you.ScreenSection
|
||||
import no.nordicsemi.android.uart.R
|
||||
import no.nordicsemi.android.uart.data.MacroEol
|
||||
import no.nordicsemi.android.uart.data.UARTData
|
||||
import no.nordicsemi.android.uart.data.UARTRecord
|
||||
import no.nordicsemi.android.uart.data.UARTRecordType
|
||||
import no.nordicsemi.android.utils.EMPTY
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
internal fun UARTContentView(
|
||||
@@ -52,11 +33,11 @@ internal fun UARTContentView(
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
// MacroSection(viewState, onEvent)
|
||||
//
|
||||
// Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
InputSection(onEvent = onEvent)
|
||||
if (viewState.isInputVisible) {
|
||||
InputSection(onEvent = onEvent)
|
||||
} else {
|
||||
MacroSection(viewState, onEvent)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
@@ -67,266 +48,3 @@ internal fun UARTContentView(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InputSection(onEvent: (UARTViewEvent) -> Unit) {
|
||||
val text = rememberSaveable { mutableStateOf(String.EMPTY) }
|
||||
val hint = stringResource(id = R.string.uart_input_hint)
|
||||
val checkedItem = rememberSaveable { mutableStateOf(MacroEol.values()[0]) }
|
||||
|
||||
val items = MacroEol.values().map {
|
||||
RadioButtonItem(it.toDisplayString(), it == checkedItem.value)
|
||||
}
|
||||
val viewEntity = RadioGroupViewEntity(items)
|
||||
|
||||
ScreenSection {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
SectionTitle(resId = R.drawable.ic_input, title = stringResource(R.string.uart_input))
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.uart_macro_dialog_eol),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
|
||||
RadioButtonGroup(viewEntity) {
|
||||
val i = items.indexOf(it)
|
||||
checkedItem.value = MacroEol.values()[i]
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Box(modifier = Modifier.weight(1f)) {
|
||||
TextField(text = text.value, hint = hint) {
|
||||
text.value = it
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
Button(
|
||||
onClick = { onEvent(OnRunInput(text.value, checkedItem.value)) },
|
||||
modifier = Modifier.padding(top = 6.dp)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.uart_send))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MacroSection(viewState: UARTViewState, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val showAddDialog = rememberSaveable { mutableStateOf(false) }
|
||||
val showDeleteDialog = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
if (showAddDialog.value) {
|
||||
UARTAddConfigurationDialog(onEvent) { showAddDialog.value = false }
|
||||
}
|
||||
|
||||
if (showDeleteDialog.value) {
|
||||
DeleteConfigurationDialog(onEvent) { showDeleteDialog.value = false }
|
||||
}
|
||||
|
||||
ScreenSection {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
SectionTitle(resId = R.drawable.ic_input, title = stringResource(R.string.uart_macros))
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Row {
|
||||
Box(modifier = Modifier.weight(1f)) {
|
||||
UARTConfigurationPicker(viewState, onEvent)
|
||||
}
|
||||
|
||||
IconButton(onClick = { showAddDialog.value = true }) {
|
||||
Icon(Icons.Default.Add, stringResource(id = R.string.uart_configuration_add))
|
||||
}
|
||||
|
||||
viewState.selectedConfiguration?.let {
|
||||
|
||||
if (!viewState.isConfigurationEdited) {
|
||||
IconButton(onClick = { onEvent(OnEditConfiguration) }) {
|
||||
Icon(
|
||||
Icons.Default.Edit,
|
||||
stringResource(id = R.string.uart_configuration_edit)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
IconButton(onClick = { onEvent(OnEditConfiguration) }) {
|
||||
Icon(
|
||||
painterResource(id = R.drawable.ic_pencil_off),
|
||||
stringResource(id = R.string.uart_configuration_edit)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(onClick = { showDeleteDialog.value = true }) {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
stringResource(id = R.string.uart_configuration_delete)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewState.selectedConfiguration?.let {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
UARTMacroView(it, viewState.isConfigurationEdited, onEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeleteConfigurationDialog(onEvent: (UARTViewEvent) -> Unit, onDismiss: () -> Unit) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(id = R.string.uart_delete_dialog_title),
|
||||
style = MaterialTheme.typography.headlineSmall
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Text(text = stringResource(id = R.string.uart_delete_dialog_info))
|
||||
},
|
||||
confirmButton = {
|
||||
Button(onClick = {
|
||||
onDismiss()
|
||||
onEvent(OnDeleteConfiguration)
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.uart_delete_dialog_confirm))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Button(onClick = onDismiss) {
|
||||
Text(text = stringResource(id = R.string.uart_delete_dialog_cancel))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun OutputSection(records: List<UARTRecord>, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val scrollDown = remember { mutableStateOf(true) }
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
SectionTitle(
|
||||
resId = R.drawable.ic_output,
|
||||
title = stringResource(R.string.uart_output),
|
||||
modifier = Modifier,
|
||||
menu = { Menu(scrollDown, onEvent) }
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
LazyColumn(
|
||||
userScrollEnabled = !scrollDown.value,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(),
|
||||
state = listState
|
||||
) {
|
||||
if (records.isEmpty()) {
|
||||
item { Text(text = stringResource(id = R.string.uart_output_placeholder)) }
|
||||
} else {
|
||||
records.forEach {
|
||||
item {
|
||||
MessageItem(record = it)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(records) {
|
||||
if (!scrollDown.value || records.isEmpty()) {
|
||||
return@LaunchedEffect
|
||||
}
|
||||
launch {
|
||||
listState.scrollToItem(records.lastIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Menu(scrollDown: MutableState<Boolean>, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val icon = when (scrollDown.value) {
|
||||
true -> R.drawable.ic_sync_down_off
|
||||
false -> R.drawable.ic_sync_down
|
||||
}
|
||||
Row {
|
||||
IconButton(onClick = { scrollDown.value = !scrollDown.value }) {
|
||||
Icon(
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = stringResource(id = R.string.uart_scroll_down)
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(onClick = { onEvent(ClearOutputItems) }) {
|
||||
Icon(
|
||||
Icons.Default.Delete,
|
||||
contentDescription = stringResource(id = R.string.uart_clear_items),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MessageItem(record: UARTRecord) {
|
||||
Column {
|
||||
Text(
|
||||
text = record.timeToString(),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.outline
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = createRecordText(record = record),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = createRecordColor(record = record)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun createRecordText(record: UARTRecord): String {
|
||||
return when (record.type) {
|
||||
UARTRecordType.INPUT -> stringResource(id = R.string.uart_input_log, record.text)
|
||||
UARTRecordType.OUTPUT -> stringResource(id = R.string.uart_output_log, record.text)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun createRecordColor(record: UARTRecord): Color {
|
||||
return when (record.type) {
|
||||
UARTRecordType.INPUT -> colorResource(id = R.color.nordicGrass)
|
||||
UARTRecordType.OUTPUT -> MaterialTheme.colorScheme.onBackground
|
||||
}
|
||||
}
|
||||
|
||||
private val datFormatter = SimpleDateFormat("dd MMMM yyyy, HH:mm:ss", Locale.ENGLISH)
|
||||
|
||||
private fun UARTRecord.timeToString(): String {
|
||||
return datFormatter.format(timestamp)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ internal data class UARTViewState(
|
||||
val selectedConfigurationName: String? = null,
|
||||
val isConfigurationEdited: Boolean = false,
|
||||
val configurations: List<UARTConfiguration> = emptyList(),
|
||||
val uartManagerState: HTSManagerState = NoDeviceState
|
||||
val uartManagerState: HTSManagerState = NoDeviceState,
|
||||
val isInputVisible: Boolean = true
|
||||
) {
|
||||
val showEditDialog: Boolean = editedPosition != null
|
||||
|
||||
|
||||
@@ -23,3 +23,5 @@ internal object DisconnectEvent : UARTViewEvent()
|
||||
|
||||
internal object NavigateUp : UARTViewEvent()
|
||||
internal object OpenLogger : UARTViewEvent()
|
||||
|
||||
internal object MacroInputSwitchClick : UARTViewEvent()
|
||||
|
||||
@@ -83,9 +83,14 @@ internal class UARTViewModel @Inject constructor(
|
||||
ClearOutputItems -> repository.clearItems()
|
||||
OpenLogger -> repository.openLogger()
|
||||
is OnRunInput -> repository.sendText(event.text, event.newLineChar)
|
||||
MacroInputSwitchClick -> onMacroInputSwitch()
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun onMacroInputSwitch() {
|
||||
_state.value = _state.value.copy(isInputVisible = !state.value.isInputVisible)
|
||||
}
|
||||
|
||||
private fun onEditConfiguration() {
|
||||
val isEdited = _state.value.isConfigurationEdited
|
||||
_state.value = _state.value.copy(isConfigurationEdited = !isEdited)
|
||||
|
||||
10
profile_uart/src/main/res/drawable/ic_macro.xml
Normal file
10
profile_uart/src/main/res/drawable/ic_macro.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#000000"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M4,8h4L8,4L4,4v4zM10,20h4v-4h-4v4zM4,20h4v-4L4,16v4zM4,14h4v-4L4,10v4zM10,14h4v-4h-4v4zM16,4v4h4L20,4h-4zM10,8h4L14,4h-4v4zM16,14h4v-4h-4v4zM16,20h4v-4h-4v4z" />
|
||||
</vector>
|
||||
@@ -53,6 +53,7 @@
|
||||
<string name="uart_delete_dialog_confirm">Confirm</string>
|
||||
<string name="uart_delete_dialog_cancel">Cancel</string>
|
||||
|
||||
<string name="uart_input_macro">Click to switch between text input and macro input.</string>
|
||||
<string name="uart_clear_items">Clear items.</string>
|
||||
<string name="uart_scroll_down">Click to constantly scroll view to the latest available log.</string>
|
||||
<string name="uart_input_log">--> %s</string>
|
||||
|
||||
Reference in New Issue
Block a user