mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2026-01-06 16:24:25 +01:00
Add UI for handling configurations for UART profile
This commit is contained in:
@@ -1,6 +1,17 @@
|
||||
package no.nordicsemi.android.uart.data
|
||||
|
||||
import no.nordicsemi.android.uart.db.XmlCommand
|
||||
|
||||
private const val MACROS_SIZES = 9
|
||||
|
||||
data class UARTConfiguration(
|
||||
val name: String,
|
||||
val macros: List<UARTMacro>
|
||||
)
|
||||
val macros: List<UARTMacro?> = List<UARTMacro?>(9) { null }
|
||||
) {
|
||||
|
||||
init {
|
||||
if (macros.size < 9) {
|
||||
throw IllegalArgumentException("Macros should always have 9 positions.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package no.nordicsemi.android.uart.data
|
||||
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import no.nordicsemi.android.uart.db.*
|
||||
@@ -16,7 +16,6 @@ import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
internal class UARTPersistentDataSource @Inject constructor(
|
||||
@ApplicationContext
|
||||
private val configurationsDao: ConfigurationsDao,
|
||||
) {
|
||||
|
||||
@@ -31,10 +30,14 @@ internal class UARTPersistentDataSource @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun createMacro(macros: Array<XmlCommand?>): List<UARTMacro> {
|
||||
return macros.filterNotNull().mapNotNull {
|
||||
val icon = MacroIcon.create(it.iconIndex)
|
||||
it.command?.let { c -> UARTMacro(icon, c, it.eol) }
|
||||
private fun createMacro(macros: Array<XmlCommand?>): List<UARTMacro?> {
|
||||
return macros.map {
|
||||
if (it == null) {
|
||||
null
|
||||
} else {
|
||||
val icon = MacroIcon.create(it.iconIndex)
|
||||
it.command?.let { c -> UARTMacro(icon, c, it.eol) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,4 +51,8 @@ internal class UARTPersistentDataSource @Inject constructor(
|
||||
|
||||
configurationsDao.insert(Configuration(0, configuration.name, xml, 0))
|
||||
}
|
||||
|
||||
suspend fun deleteConfiguration(configuration: UARTConfiguration) {
|
||||
configurationsDao.delete(configuration.name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import androidx.room.PrimaryKey
|
||||
@Entity(tableName = "configurations")
|
||||
internal data class Configuration(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
@ColumnInfo(name = "id") val id: Int,
|
||||
@ColumnInfo(name = "_id") val _id: Int?,
|
||||
@ColumnInfo(name = "name") val name: String,
|
||||
@ColumnInfo(name = "xml") val xml: String,
|
||||
@ColumnInfo(name = "deleted") val deleted: Int
|
||||
@ColumnInfo(name = "deleted", defaultValue = "0") val deleted: Int
|
||||
)
|
||||
|
||||
@@ -14,4 +14,7 @@ internal interface ConfigurationsDao {
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insert(configuration: Configuration)
|
||||
|
||||
@Query("DELETE FROM configurations WHERE name = :name")
|
||||
suspend fun delete(name: String)
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ import org.simpleframework.xml.core.PersistenceException
|
||||
import org.simpleframework.xml.core.Validate
|
||||
|
||||
@Root
|
||||
internal class XmlConfiguration {
|
||||
internal class XmlConfiguration @JvmOverloads constructor(
|
||||
@field:Attribute(required = false, empty = "Unnamed")
|
||||
var name: String? = "",
|
||||
|
||||
@Attribute(required = false, empty = "Unnamed")
|
||||
var name: String? = null
|
||||
|
||||
@ElementArray
|
||||
val commands: Array<XmlCommand?> = arrayOfNulls(COMMANDS_COUNT)
|
||||
@field:ElementArray
|
||||
var commands: Array<XmlCommand?> = arrayOfNulls(COMMANDS_COUNT)
|
||||
) {
|
||||
|
||||
@Validate
|
||||
@Throws(PersistenceException::class)
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import no.nordicsemi.android.material.you.TextField
|
||||
import no.nordicsemi.android.uart.R
|
||||
import no.nordicsemi.android.utils.EMPTY
|
||||
|
||||
@Composable
|
||||
internal fun UARTAddConfigurationDialog(onEvent: (UARTViewEvent) -> Unit) {
|
||||
val name = remember { mutableStateOf(String.EMPTY) }
|
||||
val isError = remember { mutableStateOf(false) }
|
||||
|
||||
Column {
|
||||
NameInput(name, isError)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
TextButton(onClick = { onEvent(OnEditFinish) }) {
|
||||
Text(stringResource(id = R.string.uart_macro_dialog_dismiss))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
TextButton(onClick = {
|
||||
if (isNameValid(name.value)) {
|
||||
onEvent(OnEditFinish)
|
||||
onEvent(OnAddConfiguration(name.value))
|
||||
} else {
|
||||
isError.value = true
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(id = R.string.uart_macro_dialog_confirm))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NameInput(
|
||||
name: MutableState<String>,
|
||||
isError: MutableState<Boolean>
|
||||
) {
|
||||
Column {
|
||||
TextField(
|
||||
text = name.value,
|
||||
hint = stringResource(id = R.string.uart_macro_dialog_command)
|
||||
) {
|
||||
isError.value = false
|
||||
name.value = it
|
||||
}
|
||||
|
||||
if (isError.value) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.uart_name_empty),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNameValid(name: String): Boolean {
|
||||
return name.isNotBlank()
|
||||
}
|
||||
@@ -1,18 +1,26 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.lazy.GridCells
|
||||
import androidx.compose.foundation.lazy.GridItemSpan
|
||||
import androidx.compose.foundation.lazy.LazyVerticalGrid
|
||||
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.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
@@ -26,13 +34,17 @@ import no.nordicsemi.android.uart.data.MacroIcon
|
||||
import no.nordicsemi.android.uart.data.UARTMacro
|
||||
import no.nordicsemi.android.utils.EMPTY
|
||||
|
||||
@Composable
|
||||
internal fun UARTAddMacroDialog(onDismiss: () -> Unit, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val command = remember { mutableStateOf(String.EMPTY) }
|
||||
val newLineChar = remember { mutableStateOf(MacroEol.LF) }
|
||||
val isError = remember { mutableStateOf(false) }
|
||||
private const val GRID_SIZE = 5
|
||||
|
||||
Dialog(onDismissRequest = { onDismiss() }) {
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
internal fun UARTAddMacroDialog(onEvent: (UARTViewEvent) -> Unit) {
|
||||
val newLineChar = remember { mutableStateOf(MacroEol.LF) }
|
||||
val command = remember { mutableStateOf(String.EMPTY) }
|
||||
val isError = remember { mutableStateOf(false) }
|
||||
val selectedIcon = remember { mutableStateOf(MacroIcon.values()[0]) }
|
||||
|
||||
Dialog(onDismissRequest = { onEvent(OnEditFinish) }) {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.background,
|
||||
shape = RoundedCornerShape(10.dp),
|
||||
@@ -47,59 +59,105 @@ internal fun UARTAddMacroDialog(onDismiss: () -> Unit, onEvent: (UARTViewEvent)
|
||||
.padding(16.dp)
|
||||
)
|
||||
|
||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
||||
Column(modifier = Modifier.padding(bottom = 8.dp, start = 16.dp, end = 16.dp)) {
|
||||
|
||||
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))
|
||||
}
|
||||
LazyVerticalGrid(
|
||||
cells = GridCells.Fixed(GRID_SIZE),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.wrapContentHeight()
|
||||
) {
|
||||
item(span = { GridItemSpan(GRID_SIZE) }) {
|
||||
Column {
|
||||
NewLineCharSection(newLineChar.value) { newLineChar.value = it }
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
TextButton(onClick = {
|
||||
if (isCommandValid(command.value)) {
|
||||
onDismiss()
|
||||
onEvent(OnCreateMacro(UARTMacro(MacroIcon.DOWN, command.value, newLineChar.value)))
|
||||
} else {
|
||||
isError.value = true
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(id = R.string.uart_macro_dialog_confirm))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item(span = { GridItemSpan(GRID_SIZE) }) {
|
||||
CommandInput(command, isError)
|
||||
}
|
||||
|
||||
items(20) { item ->
|
||||
val icon = MacroIcon.create(item)
|
||||
val background = if (selectedIcon.value == icon) {
|
||||
MaterialTheme.colorScheme.primaryContainer
|
||||
} else {
|
||||
MaterialTheme.colorScheme.secondaryContainer
|
||||
}
|
||||
|
||||
Image(
|
||||
painter = painterResource(id = icon.toResId()),
|
||||
contentDescription = stringResource(id = R.string.uart_macro_icon),
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.clickable { selectedIcon.value = icon }
|
||||
.background(background)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
TextButton(onClick = { onEvent(OnEditFinish) }) {
|
||||
Text(stringResource(id = R.string.uart_macro_dialog_dismiss))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
TextButton(onClick = {
|
||||
if (isCommandValid(command.value)) {
|
||||
onEvent(
|
||||
OnCreateMacro(
|
||||
UARTMacro(
|
||||
selectedIcon.value,
|
||||
command.value,
|
||||
newLineChar.value
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
isError.value = true
|
||||
}
|
||||
}) {
|
||||
Text(stringResource(id = R.string.uart_macro_dialog_confirm))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CommandInput(
|
||||
command: MutableState<String>,
|
||||
isError: MutableState<Boolean>
|
||||
) {
|
||||
Column {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NewLineCharSection(checkedItem: MacroEol, onItemClick: (MacroEol) -> Unit) {
|
||||
val items = MacroEol.values().map {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
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.stringResource
|
||||
import no.nordicsemi.android.theme.view.dialog.*
|
||||
import no.nordicsemi.android.uart.R
|
||||
import no.nordicsemi.android.uart.data.UARTConfiguration
|
||||
import no.nordicsemi.android.utils.exhaustive
|
||||
|
||||
@Composable
|
||||
internal fun UARTConfigurationPicker(state: UARTViewState, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val showDialog = rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
UARTConfigurationButton(state.selectedConfiguration) {
|
||||
showDialog.value = true
|
||||
}
|
||||
|
||||
if (showDialog.value) {
|
||||
SelectWheelSizeDialog(state) {
|
||||
when (it) {
|
||||
FlowCanceled -> showDialog.value = false
|
||||
is ItemSelectedResult -> {
|
||||
onEvent(OnConfigurationSelected(state.configurations[it.index]))
|
||||
showDialog.value = false
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun SelectWheelSizeDialog(state: UARTViewState, onEvent: (StringListDialogResult) -> Unit) {
|
||||
val wheelEntries = state.configurations.map { it.name }
|
||||
|
||||
StringListDialog(createConfig(wheelEntries) {
|
||||
onEvent(it)
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun createConfig(entries: List<String>, onResult: (StringListDialogResult) -> Unit): StringListDialogConfig {
|
||||
return StringListDialogConfig(
|
||||
title = stringResource(id = R.string.uart_configuration_picker_dialog).toAnnotatedString(),
|
||||
items = entries,
|
||||
onResult = onResult
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun UARTConfigurationButton(configuration: UARTConfiguration?, onClick: () -> Unit) {
|
||||
OutlinedButton(onClick = { onClick() }) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
){
|
||||
Column {
|
||||
Text(
|
||||
text = stringResource(id = R.string.uart_configuration_picker_hint),
|
||||
style = MaterialTheme.typography.labelSmall
|
||||
)
|
||||
val text = configuration?.name ?: stringResource(id = R.string.uart_configuration_picker_not_selected)
|
||||
Text(text = text, style = MaterialTheme.typography.bodyMedium)
|
||||
}
|
||||
|
||||
Icon(Icons.Default.ArrowDropDown, contentDescription = "")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
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.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -18,10 +20,9 @@ import no.nordicsemi.android.theme.view.ScreenSection
|
||||
import no.nordicsemi.android.theme.view.SectionTitle
|
||||
import no.nordicsemi.android.uart.R
|
||||
import no.nordicsemi.android.uart.data.UARTData
|
||||
import no.nordicsemi.android.uart.data.UARTMacro
|
||||
|
||||
@Composable
|
||||
internal fun UARTContentView(state: UARTData, macros: List<UARTMacro>, onEvent: (UARTViewEvent) -> Unit) {
|
||||
internal fun UARTContentView(state: UARTData, viewState: UARTViewState, onEvent: (UARTViewEvent) -> Unit) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.padding(16.dp)
|
||||
@@ -30,7 +31,7 @@ internal fun UARTContentView(state: UARTData, macros: List<UARTMacro>, onEvent:
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
InputSection(macros, onEvent)
|
||||
InputSection(viewState, onEvent)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
@@ -43,11 +44,11 @@ internal fun UARTContentView(state: UARTData, macros: List<UARTMacro>, onEvent:
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InputSection(macros: List<UARTMacro>, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val showSearchDialog = remember { mutableStateOf(false) }
|
||||
private fun InputSection(viewState: UARTViewState, onEvent: (UARTViewEvent) -> Unit) {
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
|
||||
if (showSearchDialog.value) {
|
||||
UARTAddMacroDialog(onDismiss = { showSearchDialog.value = false }, onEvent = onEvent)
|
||||
if (showDialog.value) {
|
||||
UARTAddConfigurationDialog(onEvent)
|
||||
}
|
||||
|
||||
ScreenSection {
|
||||
@@ -58,25 +59,31 @@ private fun InputSection(macros: List<UARTMacro>, onEvent: (UARTViewEvent) -> Un
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
macros.forEach {
|
||||
MacroItem(macro = it, onEvent = onEvent)
|
||||
Row {
|
||||
Box(modifier = Modifier.weight(1f)) {
|
||||
UARTConfigurationPicker(viewState, onEvent)
|
||||
}
|
||||
|
||||
IconButton(onClick = { showDialog.value = true }) {
|
||||
Icon(Icons.Default.Add, stringResource(id = R.string.uart_configuration_add))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
viewState.selectedConfiguration?.let {
|
||||
|
||||
IconButton(onClick = { onEvent(OnEditConfiguration) }) {
|
||||
Icon(Icons.Default.Edit, stringResource(id = R.string.uart_configuration_edit))
|
||||
}
|
||||
|
||||
IconButton(onClick = { onEvent(OnDeleteConfiguration) }) {
|
||||
Icon(Icons.Default.Delete, stringResource(id = R.string.uart_configuration_delete))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (macros.isEmpty()) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.uart_no_macros_info),
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
|
||||
viewState.selectedConfiguration?.let {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = { showSearchDialog.value = true }
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.uart_add_macro))
|
||||
UARTMacroView(it, viewState.isConfigurationEdited, onEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import no.nordicsemi.android.uart.R
|
||||
import no.nordicsemi.android.uart.data.UARTConfiguration
|
||||
import no.nordicsemi.android.uart.data.UARTMacro
|
||||
|
||||
private val divider = 4.dp
|
||||
private val buttonSize = 80.dp
|
||||
|
||||
@Composable
|
||||
internal fun UARTMacroView(
|
||||
configuration: UARTConfiguration,
|
||||
isEdited: Boolean,
|
||||
onEvent: (UARTViewEvent) -> Unit
|
||||
) {
|
||||
Column(modifier = Modifier.padding(horizontal = 16.dp)) {
|
||||
|
||||
Row {
|
||||
Item(configuration, isEdited, 0, onEvent)
|
||||
Spacer(modifier = Modifier.size(divider))
|
||||
Item(configuration, isEdited, 1, onEvent)
|
||||
Spacer(modifier = Modifier.size(divider))
|
||||
Item(configuration, isEdited, 2, onEvent)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(divider))
|
||||
|
||||
Row {
|
||||
Item(configuration, isEdited, 3, onEvent)
|
||||
Spacer(modifier = Modifier.size(divider))
|
||||
Item(configuration, isEdited, 4, onEvent)
|
||||
Spacer(modifier = Modifier.size(divider))
|
||||
Item(configuration, isEdited, 5, onEvent)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(divider))
|
||||
|
||||
Row {
|
||||
Item(configuration, isEdited, 6, onEvent)
|
||||
Spacer(modifier = Modifier.size(divider))
|
||||
Item(configuration, isEdited, 7, onEvent)
|
||||
Spacer(modifier = Modifier.size(divider))
|
||||
Item(configuration, isEdited, 8, onEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Item(
|
||||
configuration: UARTConfiguration,
|
||||
isEdited: Boolean,
|
||||
position: Int,
|
||||
onEvent: (UARTViewEvent) -> Unit
|
||||
) {
|
||||
val macro = configuration.macros.getOrNull(position)
|
||||
|
||||
if (macro == null) {
|
||||
EmptyButton(isEdited, position, onEvent)
|
||||
} else {
|
||||
MacroButton(macro, position, isEdited, onEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MacroButton(
|
||||
macro: UARTMacro,
|
||||
position: Int,
|
||||
isEdited: Boolean,
|
||||
onEvent: (UARTViewEvent) -> Unit
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(id = macro.icon.toResId()),
|
||||
contentDescription = stringResource(id = R.string.uart_macro_icon),
|
||||
modifier = Modifier
|
||||
.size(buttonSize)
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.clickable {
|
||||
if (isEdited) {
|
||||
onEvent(OnEditMacro(position))
|
||||
} else {
|
||||
onEvent(OnRunMacro(macro))
|
||||
}
|
||||
}
|
||||
.background(getBackground(isEdited))
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EmptyButton(
|
||||
isEdited: Boolean,
|
||||
position: Int,
|
||||
onEvent: (UARTViewEvent) -> Unit
|
||||
) {
|
||||
Box(modifier = Modifier
|
||||
.size(buttonSize)
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.clickable {
|
||||
if (isEdited) {
|
||||
onEvent(OnEditMacro(position))
|
||||
}
|
||||
}
|
||||
.background(getBackground(isEdited)))
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getBackground(isEdited: Boolean): Color {
|
||||
return if (!isEdited) {
|
||||
MaterialTheme.colorScheme.primary
|
||||
} else {
|
||||
MaterialTheme.colorScheme.secondary
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import no.nordicsemi.android.uart.R
|
||||
import no.nordicsemi.android.uart.data.MacroEol
|
||||
import no.nordicsemi.android.uart.data.MacroIcon
|
||||
|
||||
@Composable
|
||||
fun MacroEol.toDisplayString(): String {
|
||||
@@ -13,3 +15,29 @@ fun MacroEol.toDisplayString(): String {
|
||||
MacroEol.CR -> stringResource(id = R.string.uart_macro_dialog_cr)
|
||||
}
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
fun MacroIcon.toResId(): Int {
|
||||
return when (this) {
|
||||
MacroIcon.LEFT -> R.drawable.ic_uart_left
|
||||
MacroIcon.UP -> R.drawable.ic_uart_up
|
||||
MacroIcon.RIGHT -> R.drawable.ic_uart_right
|
||||
MacroIcon.DOWN -> R.drawable.ic_uart_down
|
||||
MacroIcon.SETTINGS -> R.drawable.ic_uart_settings
|
||||
MacroIcon.REW -> R.drawable.ic_uart_rewind
|
||||
MacroIcon.PLAY -> R.drawable.ic_uart_play
|
||||
MacroIcon.PAUSE -> R.drawable.ic_uart_pause
|
||||
MacroIcon.STOP -> R.drawable.ic_uart_stop
|
||||
MacroIcon.FWD -> R.drawable.ic_uart_forward
|
||||
MacroIcon.INFO -> R.drawable.ic_uart_about
|
||||
MacroIcon.NUMBER_1 -> R.drawable.ic_uart_1
|
||||
MacroIcon.NUMBER_2 -> R.drawable.ic_uart_2
|
||||
MacroIcon.NUMBER_3 -> R.drawable.ic_uart_3
|
||||
MacroIcon.NUMBER_4 -> R.drawable.ic_uart_4
|
||||
MacroIcon.NUMBER_5 -> R.drawable.ic_uart_5
|
||||
MacroIcon.NUMBER_6 -> R.drawable.ic_uart_6
|
||||
MacroIcon.NUMBER_7 -> R.drawable.ic_uart_7
|
||||
MacroIcon.NUMBER_8 -> R.drawable.ic_uart_8
|
||||
MacroIcon.NUMBER_9 -> R.drawable.ic_uart_9
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
@@ -23,6 +25,10 @@ fun UARTScreen() {
|
||||
val viewModel: UARTViewModel = hiltViewModel()
|
||||
val state = viewModel.state.collectAsState().value
|
||||
|
||||
if (state.showEditDialog) {
|
||||
UARTAddMacroDialog { viewModel.onEvent(it) }
|
||||
}
|
||||
|
||||
Column {
|
||||
val navigateUp = { viewModel.onEvent(NavigateUp) }
|
||||
|
||||
@@ -37,7 +43,7 @@ fun UARTScreen() {
|
||||
is LinkLossResult -> DeviceDisconnectedView(Reason.LINK_LOSS, navigateUp)
|
||||
is MissingServiceResult -> DeviceDisconnectedView(Reason.MISSING_SERVICE, navigateUp)
|
||||
is UnknownErrorResult -> DeviceDisconnectedView(Reason.UNKNOWN, navigateUp)
|
||||
is SuccessResult -> UARTContentView(state.uartManagerState.result.data, state.configuration) { viewModel.onEvent(it) }
|
||||
is SuccessResult -> UARTContentView(state.uartManagerState.result.data, state) { viewModel.onEvent(it) }
|
||||
}
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
@@ -5,9 +5,16 @@ import no.nordicsemi.android.uart.data.UARTConfiguration
|
||||
import no.nordicsemi.android.uart.data.UARTData
|
||||
|
||||
internal data class UARTViewState(
|
||||
val configuration: List<UARTConfiguration> = emptyList(),
|
||||
val editedPosition: Int? = null,
|
||||
val selectedConfigurationIndex: Int? = null,
|
||||
val isConfigurationEdited: Boolean = false,
|
||||
val configurations: List<UARTConfiguration> = emptyList(),
|
||||
val uartManagerState: HTSManagerState = NoDeviceState
|
||||
)
|
||||
) {
|
||||
val showEditDialog: Boolean = editedPosition != null
|
||||
|
||||
val selectedConfiguration: UARTConfiguration? = selectedConfigurationIndex?.let { configurations[it] }
|
||||
}
|
||||
|
||||
internal sealed class HTSManagerState
|
||||
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
package no.nordicsemi.android.uart.view
|
||||
|
||||
import no.nordicsemi.android.uart.data.UARTConfiguration
|
||||
import no.nordicsemi.android.uart.data.UARTMacro
|
||||
|
||||
internal sealed class UARTViewEvent
|
||||
|
||||
internal data class OnEditMacro(val position: Int) : UARTViewEvent()
|
||||
internal data class OnCreateMacro(val macro: UARTMacro) : UARTViewEvent()
|
||||
internal data class OnDeleteMacro(val macro: UARTMacro) : UARTViewEvent()
|
||||
internal object OnEditFinish : UARTViewEvent()
|
||||
|
||||
internal data class OnConfigurationSelected(val configuration: UARTConfiguration) : UARTViewEvent()
|
||||
internal data class OnAddConfiguration(val name: String) : UARTViewEvent()
|
||||
internal object OnEditConfiguration : UARTViewEvent()
|
||||
internal object OnDeleteConfiguration : UARTViewEvent()
|
||||
internal data class OnRunMacro(val macro: UARTMacro) : UARTViewEvent()
|
||||
|
||||
internal object DisconnectEvent : UARTViewEvent()
|
||||
|
||||
@@ -7,6 +7,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.launch
|
||||
import no.nordicsemi.android.navigation.*
|
||||
import no.nordicsemi.android.uart.data.UARTConfiguration
|
||||
import no.nordicsemi.android.uart.data.UARTMacro
|
||||
import no.nordicsemi.android.uart.data.UARTPersistentDataSource
|
||||
import no.nordicsemi.android.uart.data.UART_SERVICE_UUID
|
||||
@@ -39,7 +40,7 @@ internal class UARTViewModel @Inject constructor(
|
||||
}.launchIn(viewModelScope)
|
||||
|
||||
dataSource.getConfigurations().onEach {
|
||||
_state.value = _state.value.copy(configuration = it)
|
||||
_state.value = _state.value.copy(configurations = it)
|
||||
}.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
@@ -67,18 +68,68 @@ internal class UARTViewModel @Inject constructor(
|
||||
DisconnectEvent -> disconnect()
|
||||
is OnRunMacro -> repository.runMacro(event.macro)
|
||||
NavigateUp -> navigationManager.navigateUp()
|
||||
is OnEditMacro -> onEditMacro(event)
|
||||
OnEditFinish -> onEditFinish()
|
||||
is OnConfigurationSelected -> onConfigurationSelected(event)
|
||||
is OnAddConfiguration -> onAddConfiguration(event)
|
||||
OnDeleteConfiguration -> deleteConfiguration()
|
||||
OnEditConfiguration -> onEditConfiguration()
|
||||
}.exhaustive
|
||||
}
|
||||
|
||||
private fun onEditConfiguration() {
|
||||
_state.value = _state.value.copy(isConfigurationEdited = true)
|
||||
}
|
||||
|
||||
private fun onAddConfiguration(event: OnAddConfiguration) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
dataSource.saveConfiguration(UARTConfiguration(event.name))
|
||||
}
|
||||
}
|
||||
|
||||
private fun onEditMacro(event: OnEditMacro) {
|
||||
_state.value = _state.value.copy(editedPosition = event.position)
|
||||
}
|
||||
|
||||
private fun onEditFinish() {
|
||||
_state.value = _state.value.copy(editedPosition = null)
|
||||
}
|
||||
|
||||
private fun onConfigurationSelected(event: OnConfigurationSelected) {
|
||||
_state.value = _state.value.copy(selectedConfigurationIndex = _state.value.configurations.indexOf(event.configuration))
|
||||
}
|
||||
|
||||
private fun addNewMacro(macro: UARTMacro) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
dataSource.addNewMacro(macro)
|
||||
_state.value.selectedConfiguration?.let {
|
||||
val macros = it.macros.toMutableList().apply {
|
||||
set(_state.value.editedPosition!!, macro)
|
||||
}
|
||||
val newConf = it.copy(macros = macros)
|
||||
val newConfs = _state.value.configurations.map {
|
||||
if (it.name == newConf.name) {
|
||||
newConf
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
dataSource.saveConfiguration(newConf)
|
||||
_state.value = _state.value.copy(editedPosition = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteConfiguration() {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
_state.value.selectedConfiguration?.let {
|
||||
dataSource.deleteConfiguration(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun deleteMacro(macro: UARTMacro) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
dataSource.deleteMacro(macro)
|
||||
// dataSource.deleteMacro(macro)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_1.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_1.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10,7V9H12V17H14V7H10Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_2.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_2.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,7V9H13V11H11A2,2 0,0 0,9 13V17H11L15,17V15H11V13H13A2,2 0,0 0,15 11V9A2,2 0,0 0,13 7H9Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_3.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_3.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15,15V13.5A1.5,1.5 0,0 0,13.5 12A1.5,1.5 0,0 0,15 10.5V9C15,7.89 14.1,7 13,7H9V9H13V11H11V13H13V15H9V17H13A2,2 0,0 0,15 15"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_4.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_4.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,7V13H13V17H15V7H13V11H11V7H9Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_5.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_5.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,7V13H13V15H9V17H13A2,2 0,0 0,15 15V13A2,2 0,0 0,13 11H11V9H15V7H9Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_6.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_6.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,7V13H13V15H9V17H13A2,2 0,0 0,15 15V13A2,2 0,0 0,13 11H11V9H15V7H9Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_7.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_7.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,7V13H13V15H9V17H13A2,2 0,0 0,15 15V13A2,2 0,0 0,13 11H11V9H15V7H9Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_8.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_8.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,7V13H13V15H9V17H13A2,2 0,0 0,15 15V13A2,2 0,0 0,13 11H11V9H15V7H9Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_9.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_9.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9,7V13H13V15H9V17H13A2,2 0,0 0,15 15V13A2,2 0,0 0,13 11H11V9H15V7H9Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_about.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_about.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0,0 0,2 12A10,10 0,0 0,12 22A10,10 0,0 0,22 12A10,10 0,0 0,12 2M11,17H13V11H11V17Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_down.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_down.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_forward.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_forward.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M13,6V18L21.5,12M4,18L12.5,12L4,6V18Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_left.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_left.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_pause.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_pause.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M14,19H18V5H14M6,19H10V5H6V19Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_play.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_play.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8,5.14V19.14L19,12.14L8,5.14Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_rewind.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_rewind.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11.5,12L20,18V6M11,18V6L2.5,12L11,18Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_right.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_right.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_settings.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_settings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,15.5A3.5,3.5 0,0 1,8.5 12A3.5,3.5 0,0 1,12 8.5A3.5,3.5 0,0 1,15.5 12A3.5,3.5 0,0 1,12 15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_stop.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_stop.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M18,18H6V6H18V18Z"/>
|
||||
</vector>
|
||||
9
profile_uart/src/main/res/drawable/ic_uart_up.xml
Normal file
9
profile_uart/src/main/res/drawable/ic_uart_up.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z"/>
|
||||
</vector>
|
||||
44
profile_uart/src/main/res/drawable/uart_button.xml
Normal file
44
profile_uart/src/main/res/drawable/uart_button.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2015, Nordic Semiconductor
|
||||
~ All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
~
|
||||
~ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
~
|
||||
~ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~
|
||||
~ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
~ software without specific prior written permission.
|
||||
~
|
||||
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
~ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
~ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
~ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
~ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:maxLevel="0" android:drawable="@drawable/ic_uart_left" />
|
||||
<item android:maxLevel="1" android:drawable="@drawable/ic_uart_up" />
|
||||
<item android:maxLevel="2" android:drawable="@drawable/ic_uart_right" />
|
||||
<item android:maxLevel="3" android:drawable="@drawable/ic_uart_down" />
|
||||
<item android:maxLevel="4" android:drawable="@drawable/ic_uart_settings" />
|
||||
<item android:maxLevel="5" android:drawable="@drawable/ic_uart_rewind" />
|
||||
<item android:maxLevel="6" android:drawable="@drawable/ic_uart_play" />
|
||||
<item android:maxLevel="7" android:drawable="@drawable/ic_uart_pause" />
|
||||
<item android:maxLevel="8" android:drawable="@drawable/ic_uart_stop" />
|
||||
<item android:maxLevel="9" android:drawable="@drawable/ic_uart_forward" />
|
||||
<item android:maxLevel="10" android:drawable="@drawable/ic_uart_about" />
|
||||
<item android:maxLevel="11" android:drawable="@drawable/ic_uart_1" />
|
||||
<item android:maxLevel="12" android:drawable="@drawable/ic_uart_2" />
|
||||
<item android:maxLevel="13" android:drawable="@drawable/ic_uart_3" />
|
||||
<item android:maxLevel="14" android:drawable="@drawable/ic_uart_4" />
|
||||
<item android:maxLevel="15" android:drawable="@drawable/ic_uart_5" />
|
||||
<item android:maxLevel="16" android:drawable="@drawable/ic_uart_6" />
|
||||
<item android:maxLevel="17" android:drawable="@drawable/ic_uart_7" />
|
||||
<item android:maxLevel="18" android:drawable="@drawable/ic_uart_8" />
|
||||
<item android:maxLevel="19" android:drawable="@drawable/ic_uart_9" />
|
||||
</level-list>
|
||||
@@ -4,8 +4,15 @@
|
||||
|
||||
<string name="uart_no_macros_info">Please define a macro to send command to the device.</string>
|
||||
|
||||
<string name="uart_configuration_add">Add selected configuration.</string>
|
||||
<string name="uart_configuration_delete">Delete selected configuration.</string>
|
||||
<string name="uart_configuration_edit">Edit selected configuration.</string>
|
||||
|
||||
<string name="uart_input">Macros</string>
|
||||
<string name="uart_output">Output</string>
|
||||
<string name="uart_configuration_picker_hint">Select configuration</string>
|
||||
<string name="uart_configuration_picker_not_selected">Not selected.</string>
|
||||
<string name="uart_configuration_picker_dialog">Select configuration</string>
|
||||
|
||||
<string name="uart_command_field">Command: %s</string>
|
||||
|
||||
@@ -29,4 +36,9 @@
|
||||
|
||||
<string name="uart_output_placeholder">The incoming messages will be displayed here.</string>
|
||||
<string name="uart_macro_error">Provided command cannot be empty.</string>
|
||||
|
||||
<string name="uart_name">Name</string>
|
||||
<string name="uart_name_empty">Provided name cannot be empty.</string>
|
||||
|
||||
<string name="uart_macro_icon">Icon representing defined command.</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user