Merge pull request #109 from NordicSemiconductor/feature/addSendTextToUartProfile

Feature/add send text to uart profile
This commit is contained in:
Sylwester Zieliński
2022-04-11 15:55:52 +02:00
committed by GitHub
17 changed files with 197 additions and 36 deletions

View File

@@ -20,7 +20,7 @@ jobs:
SONATYPE_STATING_PROFILE_ID: ${{ secrets.SONATYPE_STATING_PROFILE_ID }} SONATYPE_STATING_PROFILE_ID: ${{ secrets.SONATYPE_STATING_PROFILE_ID }}
run: | run: |
pwd pwd
echo "${{ secrets.GOOGLE_SERVICES }}" | base64 --decode > lib_analytics/src/main/res/values/keys.xml echo "${{ secrets.GOOGLE_SERVICES }}" | base64 --decode > lib_analytics/src/main/res/values/values.xml
echo "${{ secrets.KEYSTORE_FILE }}" > keystore.asc echo "${{ secrets.KEYSTORE_FILE }}" > keystore.asc
gpg -d --passphrase "${{ secrets.KEYSTORE_FILE_PSWD }}" --batch keystore.asc > keystore gpg -d --passphrase "${{ secrets.KEYSTORE_FILE_PSWD }}" --batch keystore.asc > keystore
echo "${{ secrets.GPG_FILE }}" > sec.gpg.asc echo "${{ secrets.GPG_FILE }}" > sec.gpg.asc

View File

@@ -9,3 +9,14 @@ dependencies {
implementation 'com.google.firebase:firebase-analytics' implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-crashlytics' implementation 'com.google.firebase:firebase-crashlytics'
} }
task copyGoogleIdValuesTask(type: Copy) {
from 'src/main/res/values/values.xml'
into "$project.buildDir/generated/res/google-services/release/values/"
}
import com.google.firebase.crashlytics.buildtools.gradle.tasks.UploadMappingFileTask
tasks.withType(UploadMappingFileTask).configureEach {
dependsOn(copyGoogleIdValuesTask)
}

View File

@@ -3,12 +3,7 @@ package no.nordicsemi.android.theme.view
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
@@ -28,6 +23,7 @@ import androidx.compose.ui.unit.sp
fun SectionTitle( fun SectionTitle(
@DrawableRes resId: Int, @DrawableRes resId: Int,
title: String, title: String,
menu: @Composable (() -> Unit)? = null,
modifier: Modifier = Modifier.fillMaxWidth() modifier: Modifier = Modifier.fillMaxWidth()
) { ) {
Row( Row(
@@ -49,10 +45,12 @@ fun SectionTitle(
Spacer(modifier = Modifier.size(8.dp)) Spacer(modifier = Modifier.size(8.dp))
Text( Text(
text = title, text = title,
textAlign = TextAlign.Center, textAlign = TextAlign.Start,
fontSize = 24.sp, fontSize = 24.sp,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f)
) )
menu?.invoke()
} }
} }

View File

@@ -5,10 +5,13 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -19,17 +22,22 @@ import no.nordicsemi.android.theme.view.BatteryLevelView
import no.nordicsemi.android.theme.view.SectionTitle import no.nordicsemi.android.theme.view.SectionTitle
@Composable @Composable
internal fun HRSContentView(state: HRSData, onEvent: (HRSScreenViewEvent) -> Unit) { internal fun HRSContentView(state: HRSData, zoomIn: Boolean, onEvent: (HRSScreenViewEvent) -> Unit) {
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) { ) {
ScreenSection { ScreenSection {
SectionTitle(resId = R.drawable.ic_chart_line, title = "Data") SectionTitle(
resId = R.drawable.ic_chart_line,
title = stringResource(id = R.string.hrs_section_data),
menu = { Menu(zoomIn, onEvent) }
)
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
LineChartView(state) LineChartView(state, zoomIn)
} }
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
@@ -48,8 +56,22 @@ internal fun HRSContentView(state: HRSData, onEvent: (HRSScreenViewEvent) -> Uni
} }
} }
@Composable
private fun Menu(zoomIn: Boolean, onEvent: (HRSScreenViewEvent) -> Unit) {
val icon = when (zoomIn) {
true -> R.drawable.ic_zoom_out
false -> R.drawable.ic_zoom_in
}
IconButton(onClick = { onEvent(SwitchZoomEvent) }) {
Icon(
painter = painterResource(id = icon),
contentDescription = stringResource(id = R.string.hrs_zoom_icon)
)
}
}
@Preview @Preview
@Composable @Composable
private fun Preview() { private fun Preview() {
HRSContentView(state = HRSData()) { } HRSContentView(state = HRSData(), zoomIn = false) { }
} }

View File

@@ -11,12 +11,11 @@ import androidx.hilt.navigation.compose.hiltViewModel
import no.nordicsemi.android.hrs.R import no.nordicsemi.android.hrs.R
import no.nordicsemi.android.hrs.viewmodel.HRSViewModel import no.nordicsemi.android.hrs.viewmodel.HRSViewModel
import no.nordicsemi.android.service.* import no.nordicsemi.android.service.*
import no.nordicsemi.android.theme.view.BackIconAppBar
import no.nordicsemi.android.theme.view.LoggerIconAppBar import no.nordicsemi.android.theme.view.LoggerIconAppBar
import no.nordicsemi.ui.scanner.ui.DeviceConnectingView
import no.nordicsemi.ui.scanner.ui.NoDeviceView
import no.nordicsemi.android.utils.exhaustive import no.nordicsemi.android.utils.exhaustive
import no.nordicsemi.ui.scanner.ui.DeviceConnectingView
import no.nordicsemi.ui.scanner.ui.DeviceDisconnectedView import no.nordicsemi.ui.scanner.ui.DeviceDisconnectedView
import no.nordicsemi.ui.scanner.ui.NoDeviceView
import no.nordicsemi.ui.scanner.ui.Reason import no.nordicsemi.ui.scanner.ui.Reason
@Composable @Composable
@@ -40,7 +39,7 @@ fun HRSScreen() {
is LinkLossResult -> DeviceDisconnectedView(Reason.LINK_LOSS, navigateUp) is LinkLossResult -> DeviceDisconnectedView(Reason.LINK_LOSS, navigateUp)
is MissingServiceResult -> DeviceDisconnectedView(Reason.MISSING_SERVICE, navigateUp) is MissingServiceResult -> DeviceDisconnectedView(Reason.MISSING_SERVICE, navigateUp)
is UnknownErrorResult -> DeviceDisconnectedView(Reason.UNKNOWN, navigateUp) is UnknownErrorResult -> DeviceDisconnectedView(Reason.UNKNOWN, navigateUp)
is SuccessResult -> HRSContentView(state.result.data) { viewModel.onEvent(it) } is SuccessResult -> HRSContentView(state.result.data, state.zoomIn) { viewModel.onEvent(it) }
} }
}.exhaustive }.exhaustive
} }

View File

@@ -2,6 +2,8 @@ package no.nordicsemi.android.hrs.view
internal sealed class HRSScreenViewEvent internal sealed class HRSScreenViewEvent
internal object SwitchZoomEvent : HRSScreenViewEvent()
internal object DisconnectEvent : HRSScreenViewEvent() internal object DisconnectEvent : HRSScreenViewEvent()
internal object NavigateUpEvent : HRSScreenViewEvent() internal object NavigateUpEvent : HRSScreenViewEvent()

View File

@@ -5,6 +5,9 @@ import no.nordicsemi.android.service.BleManagerResult
internal sealed class HRSViewState internal sealed class HRSViewState
internal data class WorkingState(val result: BleManagerResult<HRSData>) : HRSViewState() internal data class WorkingState(
val result: BleManagerResult<HRSData>,
val zoomIn: Boolean = false,
) : HRSViewState()
internal object NoDeviceState : HRSViewState() internal object NoDeviceState : HRSViewState()

View File

@@ -17,24 +17,31 @@ import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
import no.nordicsemi.android.hrs.data.HRSData import no.nordicsemi.android.hrs.data.HRSData
import java.util.*
private const val X_AXIS_ELEMENTS_COUNT = 40f private const val X_AXIS_ELEMENTS_COUNT = 40f
private const val AXIS_MIN = 0
private const val AXIS_MAX = 300
@Composable @Composable
internal fun LineChartView(state: HRSData) { internal fun LineChartView(state: HRSData, zoomIn: Boolean,) {
val items = state.heartRates.takeLast(X_AXIS_ELEMENTS_COUNT.toInt()).reversed() val items = state.heartRates.takeLast(X_AXIS_ELEMENTS_COUNT.toInt()).reversed()
val isSystemInDarkTheme = isSystemInDarkTheme() val isSystemInDarkTheme = isSystemInDarkTheme()
AndroidView( AndroidView(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(300.dp), .height(300.dp),
factory = { createLineChartView(isSystemInDarkTheme, it, items) }, factory = { createLineChartView(isSystemInDarkTheme, it, items, zoomIn) },
update = { updateData(items, it) } update = { updateData(items, it, zoomIn) }
) )
} }
internal fun createLineChartView(isDarkTheme: Boolean, context: Context, points: List<Int>): LineChart { internal fun createLineChartView(
isDarkTheme: Boolean,
context: Context,
points: List<Int>,
zoomIn: Boolean
): LineChart {
return LineChart(context).apply { return LineChart(context).apply {
description.isEnabled = false description.isEnabled = false
@@ -73,8 +80,8 @@ internal fun createLineChartView(isDarkTheme: Boolean, context: Context, points:
axisLeft.apply { axisLeft.apply {
enableGridDashedLine(10f, 10f, 0f) enableGridDashedLine(10f, 10f, 0f)
axisMaximum = 300f axisMaximum = points.getMax(zoomIn)
axisMinimum = 100f axisMinimum = points.getMin(zoomIn)
} }
axisRight.isEnabled = false axisRight.isEnabled = false
@@ -153,12 +160,16 @@ internal fun createLineChartView(isDarkTheme: Boolean, context: Context, points:
} }
} }
private fun updateData(points: List<Int>, chart: LineChart) { private fun updateData(points: List<Int>, chart: LineChart, zoomIn: Boolean) {
val entries = points.mapIndexed { i, v -> val entries = points.mapIndexed { i, v ->
Entry(-i.toFloat(), v.toFloat()) Entry(-i.toFloat(), v.toFloat())
}.reversed() }.reversed()
with(chart) { with(chart) {
axisLeft.apply {
axisMaximum = points.getMax(zoomIn)
axisMinimum = points.getMin(zoomIn)
}
if (data != null && data.dataSetCount > 0) { if (data != null && data.dataSetCount > 0) {
val set1 = data!!.getDataSetByIndex(0) as LineDataSet val set1 = data!!.getDataSetByIndex(0) as LineDataSet
set1.values = entries set1.values = entries
@@ -169,3 +180,19 @@ private fun updateData(points: List<Int>, chart: LineChart) {
} }
} }
} }
private fun List<Int>.getMin(zoomIn: Boolean): Float {
return if (zoomIn) {
minOrNull() ?: AXIS_MIN
} else {
AXIS_MIN
}.toFloat()
}
private fun List<Int>.getMax(zoomIn: Boolean): Float {
return if (zoomIn) {
maxOrNull() ?: AXIS_MAX
} else {
AXIS_MAX
}.toFloat()
}

View File

@@ -31,7 +31,8 @@ internal class HRSViewModel @Inject constructor(
} }
repository.data.onEach { repository.data.onEach {
_state.value = WorkingState(it) val zoomIn = (_state.value as? WorkingState)?.zoomIn ?: false
_state.value = WorkingState(it, zoomIn)
}.launchIn(viewModelScope) }.launchIn(viewModelScope)
} }
@@ -57,9 +58,16 @@ internal class HRSViewModel @Inject constructor(
DisconnectEvent -> disconnect() DisconnectEvent -> disconnect()
NavigateUpEvent -> navigationManager.navigateUp() NavigateUpEvent -> navigationManager.navigateUp()
OpenLoggerEvent -> repository.openLogger() OpenLoggerEvent -> repository.openLogger()
SwitchZoomEvent -> onZoomButtonClicked()
}.exhaustive }.exhaustive
} }
private fun onZoomButtonClicked() {
(_state.value as? WorkingState)?.let {
_state.value = it.copy(zoomIn = !it.zoomIn)
}
}
private fun disconnect() { private fun disconnect() {
repository.release() repository.release()
navigationManager.navigateUp() navigationManager.navigateUp()

View File

@@ -0,0 +1,13 @@
<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="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
<path
android:fillColor="@android:color/white"
android:pathData="M12,10h-2v2H9v-2H7V9h2V7h1v2h2v1z" />
</vector>

View 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="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14zM7,9h5v1L7,10z" />
</vector>

View File

@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="hrs_title">HRS</string> <string name="hrs_title">HRS</string>
<string name="hrs_section_data">Data</string>
<string name="hrs_zoom_icon">Icon to zoom chart in or out</string>
</resources> </resources>

View File

@@ -55,6 +55,10 @@ class UARTRepository @Inject internal constructor(
} }
} }
fun sendText(text: String, newLineChar: MacroEol) {
manager?.send(text.parseWithNewLineChar(newLineChar))
}
fun runMacro(macro: UARTMacro) { fun runMacro(macro: UARTMacro) {
macro.command?.parseWithNewLineChar(macro.newLineChar)?.let { macro.command?.parseWithNewLineChar(macro.newLineChar)?.let {
manager?.send(it) manager?.send(it)

View File

@@ -1,6 +1,5 @@
package no.nordicsemi.android.uart.view package no.nordicsemi.android.uart.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Add
@@ -15,11 +14,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import no.nordicsemi.android.material.you.ScreenSection import no.nordicsemi.android.material.you.*
import no.nordicsemi.android.theme.view.SectionTitle import no.nordicsemi.android.theme.view.SectionTitle
import no.nordicsemi.android.uart.R 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.UARTData
import no.nordicsemi.android.uart.data.UARTOutputRecord import no.nordicsemi.android.uart.data.UARTOutputRecord
import no.nordicsemi.android.utils.EMPTY
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@@ -33,13 +34,17 @@ internal fun UARTContentView(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) { ) {
InputSection(viewState, onEvent) InputSection(onEvent = onEvent)
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.size(16.dp))
MacroSection(viewState, onEvent)
Spacer(modifier = Modifier.size(16.dp))
OutputSection(state.displayMessages, onEvent) OutputSection(state.displayMessages, onEvent)
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.size(16.dp))
Button( Button(
onClick = { onEvent(DisconnectEvent) } onClick = { onEvent(DisconnectEvent) }
@@ -50,7 +55,58 @@ internal fun UARTContentView(
} }
@Composable @Composable
private fun InputSection(viewState: UARTViewState, onEvent: (UARTViewEvent) -> Unit) { 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 showAddDialog = rememberSaveable { mutableStateOf(false) }
val showDeleteDialog = rememberSaveable { mutableStateOf(false) } val showDeleteDialog = rememberSaveable { mutableStateOf(false) }
@@ -66,7 +122,7 @@ private fun InputSection(viewState: UARTViewState, onEvent: (UARTViewEvent) -> U
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
SectionTitle(resId = R.drawable.ic_input, title = stringResource(R.string.uart_input)) SectionTitle(resId = R.drawable.ic_input, title = stringResource(R.string.uart_macros))
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
@@ -169,7 +225,7 @@ private fun OutputSection(records: List<UARTOutputRecord>, onEvent: (UARTViewEve
} }
} }
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.size(16.dp))
Column(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.fillMaxWidth()) {
if (records.isEmpty()) { if (records.isEmpty()) {

View File

@@ -1,5 +1,6 @@
package no.nordicsemi.android.uart.view package no.nordicsemi.android.uart.view
import no.nordicsemi.android.uart.data.MacroEol
import no.nordicsemi.android.uart.data.UARTConfiguration import no.nordicsemi.android.uart.data.UARTConfiguration
import no.nordicsemi.android.uart.data.UARTMacro import no.nordicsemi.android.uart.data.UARTMacro
@@ -15,6 +16,7 @@ internal data class OnAddConfiguration(val name: String) : UARTViewEvent()
internal object OnEditConfiguration : UARTViewEvent() internal object OnEditConfiguration : UARTViewEvent()
internal object OnDeleteConfiguration : UARTViewEvent() internal object OnDeleteConfiguration : UARTViewEvent()
internal data class OnRunMacro(val macro: UARTMacro) : UARTViewEvent() internal data class OnRunMacro(val macro: UARTMacro) : UARTViewEvent()
internal data class OnRunInput(val text: String, val newLineChar: MacroEol) : UARTViewEvent()
internal object ClearOutputItems : UARTViewEvent() internal object ClearOutputItems : UARTViewEvent()
internal object DisconnectEvent : UARTViewEvent() internal object DisconnectEvent : UARTViewEvent()

View File

@@ -82,6 +82,7 @@ internal class UARTViewModel @Inject constructor(
OnEditConfiguration -> onEditConfiguration() OnEditConfiguration -> onEditConfiguration()
ClearOutputItems -> repository.clearItems() ClearOutputItems -> repository.clearItems()
OpenLogger -> repository.openLogger() OpenLogger -> repository.openLogger()
is OnRunInput -> repository.sendText(event.text, event.newLineChar)
}.exhaustive }.exhaustive
} }

View File

@@ -8,7 +8,10 @@
<string name="uart_configuration_delete">Delete selected configuration.</string> <string name="uart_configuration_delete">Delete selected configuration.</string>
<string name="uart_configuration_edit">Edit selected configuration.</string> <string name="uart_configuration_edit">Edit selected configuration.</string>
<string name="uart_input">Macros</string> <string name="uart_send">Send</string>
<string name="uart_input">Input</string>
<string name="uart_input_hint">Text to send</string>
<string name="uart_macros">Macros</string>
<string name="uart_output">Output</string> <string name="uart_output">Output</string>
<string name="uart_configuration_picker_hint">Select configuration</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_not_selected">Not selected.</string>