ble api update

This commit is contained in:
Vineyro 2025-04-18 11:54:28 +07:00
parent 0b8599dafa
commit 20c8842f95
74 changed files with 1928 additions and 3378 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
<bytecodeTargetLevel target="21" />
</component>
</project>

View File

@ -4,10 +4,10 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-11-15T06:34:28.043049200Z">
<DropdownSelection timestamp="2025-02-12T02:51:30.451430800Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=55381e0a" />
<DeviceId pluginId="PhysicalDevice" identifier="serial=BV5900DNS00004122" />
</handle>
</Target>
</DropdownSelection>

View File

@ -1,6 +1,6 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@ -19,8 +19,8 @@ android {
applicationId "llc.arma.ble"
minSdk 26
targetSdk 34
versionCode 46
versionName "1.4.18"
versionCode 50
versionName "1.4.24"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {

View File

@ -18,7 +18,6 @@
tools:targetApi="s" />
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.bluetooth_le"
android:required="true"/>

View File

@ -15,14 +15,17 @@ import android.view.SurfaceView
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
@ -43,6 +46,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
@ -99,140 +103,158 @@ class MainActivity : ComponentActivity() {
)
) {
ModalBottomSheetLayout(
sheetShape = RoundedCornerShape(
topStart = 25.dp,
topEnd = 25.dp
),
sheetElevation = 0.dp,
sheetState = modalState,
sheetContent = {
BoxWithConstraints {
val scope = rememberCoroutineScope()
val maxHeight = with(LocalDensity.current) {
this@BoxWithConstraints.constraints.maxHeight.toDp()
}
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
ModalBottomSheetLayout(
modifier = Modifier,
sheetShape = RoundedCornerShape(
topStart = 25.dp,
topEnd = 25.dp
),
sheetElevation = 0.dp,
sheetState = modalState,
sheetContent = {
Surface(
modifier = Modifier.fillMaxWidth()
val statusBarHeight = with(LocalDensity.current) {
WindowInsets.statusBars.getTop(this).toDp()
}
val scope = rememberCoroutineScope()
Column(
modifier = Modifier.heightIn(max = maxHeight - statusBarHeight),
horizontalAlignment = Alignment.CenterHorizontally
) {
Column(
modifier = Modifier.statusBarsPadding().navigationBarsPadding()
Surface(
modifier = Modifier.fillMaxWidth()
) {
Spacer(modifier = Modifier.height(14.dp))
Column(
modifier = Modifier.navigationBarsPadding()
) {
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
modifier = Modifier
.align(Alignment.CenterHorizontally)
.size(
width = 54.dp,
height = 5.dp
)
Spacer(modifier = Modifier.height(14.dp))
) {}
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
modifier = Modifier
.align(Alignment.CenterHorizontally)
.size(
width = 54.dp,
height = 5.dp
)
Spacer(modifier = Modifier.height(12.dp))
) {}
sheetContent()
Spacer(modifier = Modifier.height(12.dp))
sheetContent()
}
}
}
}
BackHandler(modalState.isVisible) {
scope.launch { modalState.hide() }
}
BackHandler(modalState.isVisible) {
scope.launch { modalState.hide() }
}
},
content = {
},
content = {
Surface(
modifier = Modifier
.fillMaxSize()
.navigationBarsPadding(),
color = MaterialTheme.colorScheme.background
) {
Surface(
modifier = Modifier
.fillMaxSize()
.navigationBarsPadding(),
color = MaterialTheme.colorScheme.background
) {
val multiplePermissionsState =
val multiplePermissionsState =
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
rememberMultiplePermissionsState(
listOf(
Manifest.permission.READ_MEDIA_VIDEO,
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT
)
)
}else{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
rememberMultiplePermissionsState(
listOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_MEDIA_VIDEO,
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT
)
)
} else {
rememberMultiplePermissionsState(
listOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
rememberMultiplePermissionsState(
listOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT
)
)
)
} else {
rememberMultiplePermissionsState(
listOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
)
}
}
var bleEnabled by remember {
mutableStateOf(mBluetoothAdapter.isEnabled)
}
var bleEnabled by remember {
mutableStateOf(mBluetoothAdapter.isEnabled)
}
val lifecycleOwner = LocalLifecycleOwner.current
val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
val lifecycleOwner = LocalLifecycleOwner.current
val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
LaunchedEffect(lifecycleState) {
bleEnabled = mBluetoothAdapter.isEnabled
}
LaunchedEffect(lifecycleState){
bleEnabled = mBluetoothAdapter.isEnabled
}
if (multiplePermissionsState.allPermissionsGranted) {
if (multiplePermissionsState.allPermissionsGranted) {
if (bleEnabled) {
if(bleEnabled) {
MainScreen()
MainScreen()
} else {
val context = LocalContext.current
LaunchedEffect(mBluetoothAdapter.isEnabled) {
val intent =
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
(context as Activity).startActivityForResult(
intent,
1
)
}
}
} else {
val context = LocalContext.current
LaunchedEffect(mBluetoothAdapter.isEnabled){
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
(context as Activity).startActivityForResult(intent, 1)
LaunchedEffect(multiplePermissionsState) {
multiplePermissionsState.launchMultiplePermissionRequest()
}
}
} else {
LaunchedEffect(multiplePermissionsState) {
multiplePermissionsState.launchMultiplePermissionRequest()
}
}
}
}
)
)
}
}
@ -242,23 +264,4 @@ class MainActivity : ComponentActivity() {
}
}
@Composable
fun Camera(){
AndroidView(
factory = {
val cameraManager = it.getSystemService(CameraManager::class.java)
cameraManager.cameraIdList.forEach {
println("$it is front: ${cameraManager.getCameraCharacteristics(it).get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT}")
}
return@AndroidView SurfaceView(it)
}
)
}

View File

@ -0,0 +1,110 @@
package llc.arma.ble.app.ui.common
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun PrimaryButton(
modifier: Modifier = Modifier,
label: String,
onClick: () -> Unit
) {
Surface(
modifier = modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = onClick
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = label
)
}
}
}
@Composable
fun SmallPrimaryButton(
modifier: Modifier = Modifier,
label: String,
onClick: () -> Unit
) {
Surface(
modifier = modifier
.padding(8.dp)
.height(48.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = onClick
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = label
)
}
}
}
@Composable
fun SecondaryButton(
modifier: Modifier = Modifier,
label: String,
onClick: () -> Unit
) {
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = onClick,
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = label
)
}
}
}

View File

@ -0,0 +1,68 @@
package llc.arma.ble.app.ui.common
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.SelectorItem
@Composable
fun TxLevelSelector(
tx: BleView.BleState.TX,
onSelect: (tx: BleView.BleState.TX) -> Unit,
){
var value by remember(tx) {
mutableStateOf(tx)
}
Column(
modifier = Modifier,
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Мощность",
style = MaterialTheme.typography.titleLarge
)
Column(
modifier = Modifier
.weight(1f)
.verticalScroll(rememberScrollState())
) {
BleView.BleState.TX.entries.forEach {
SelectorItem(
label = "${it.value} dBb (${it.powerPercentage} %)",
selected = it == value
){
value = it
}
}
}
PrimaryButton(
label = "Применить"
) {
onSelect(value)
}
}
}

View File

@ -14,7 +14,8 @@ class BleMapper @Inject constructor(
BleView.Beacon(
info = input.info,
state = BleView.BleState(
tx = txMapper.map(input.state.tx)
tx = txMapper.map(input.state.tx),
version = input.state.version
)
)
}
@ -22,7 +23,8 @@ class BleMapper @Inject constructor(
BleView.Thermometer(
info = input.info,
state = BleView.BleState(
tx = txMapper.map(input.state.tx)
tx = txMapper.map(input.state.tx),
version = input.state.version
),
thermometerState = BleView.Thermometer.ThermometerState(
temperature = BleView.Thermometer.ThermometerState.TemperatureState(input.thermometerState.temperature, false),
@ -36,11 +38,13 @@ class BleMapper @Inject constructor(
BleView.Accelerometer(
info = input.info,
state = BleView.BleState(
tx = txMapper.map(input.state.tx)
tx = txMapper.map(input.state.tx),
version = input.state.version
),
accelerometerState = BleView.Accelerometer.AccelerometerState(
saveHistorySettings = input.accelerometerState.saveHistorySettings,
historyInterval = input.accelerometerState.historyInterval
historyInterval = input.accelerometerState.historyInterval,
readInterval = input.accelerometerState.readInterval
)
)
}
@ -49,7 +53,8 @@ class BleMapper @Inject constructor(
BleView.Host(
info = input.info,
state = BleView.BleState(
tx = txMapper.map(input.state.tx)
tx = txMapper.map(input.state.tx),
version = input.state.version
),
hostState = BleView.Host.HostState(
historyInterval = input.hostState.historyInterval,

View File

@ -14,7 +14,8 @@ class BleViewMapper @Inject constructor(
Ble.Beacon(
info = input.info,
state = Ble.BleState(
tx = txMapper.map(input.state.tx)
tx = txMapper.map(input.state.tx),
version = input.state.version
)
)
}
@ -22,7 +23,8 @@ class BleViewMapper @Inject constructor(
Ble.Thermometer(
info = input.info,
state = Ble.BleState(
tx = txMapper.map(input.state.tx)
tx = txMapper.map(input.state.tx),
version = input.state.version
),
thermometerState = Ble.Thermometer.ThermometerState(
temperature = input.thermometerState.temperature.value,
@ -36,11 +38,13 @@ class BleViewMapper @Inject constructor(
Ble.Accelerometer(
info = input.info,
state = Ble.BleState(
tx = txMapper.map(input.state.tx)
tx = txMapper.map(input.state.tx),
version = input.state.version
),
accelerometerState = Ble.Accelerometer.AccelerometerState(
saveHistorySettings = input.accelerometerState.saveHistory,
historyInterval = input.accelerometerState.historyInterval,
readInterval = input.accelerometerState.readInterval
)
)
}
@ -49,7 +53,8 @@ class BleViewMapper @Inject constructor(
Ble.Host(
info = input.info,
state = Ble.BleState(
tx = txMapper.map(input.state.tx)
tx = txMapper.map(input.state.tx),
version = input.state.version
),
hostState = Ble.Host.HostState(
historyInterval = input.hostState.historyInterval,

View File

@ -4,6 +4,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import llc.arma.ble.data.repository.BleRepositoryImpl
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo
@ -20,10 +21,11 @@ sealed class BleView(
class AccelerometerState(
saveHistorySettings: Ble.Accelerometer.HistorySettings,
historyInterval: Long,
readInterval: Long
) {
var saveHistory by mutableStateOf(saveHistorySettings)
var historyInterval by mutableStateOf(historyInterval)
var historyInterval by mutableLongStateOf(historyInterval)
var readInterval by mutableLongStateOf(readInterval)
}
}
@ -52,7 +54,7 @@ sealed class BleView(
var temperature by mutableStateOf(temperature)
var saveHistory by mutableStateOf(saveHistory)
var historyInterval by mutableStateOf(historyInterval)
var historyInterval by mutableLongStateOf(historyInterval)
}
@ -75,7 +77,8 @@ sealed class BleView(
}
class BleState(
tx: TX
tx: TX,
val version: BleRepositoryImpl.Version
){
var tx by mutableStateOf(tx)

View File

@ -2,7 +2,6 @@ package llc.arma.ble.app.ui.screen
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@ -16,8 +15,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.BatteryFull
import androidx.compose.material.icons.rounded.Key
import androidx.compose.material.icons.rounded.NetworkCell
import androidx.compose.material.icons.rounded.ShortText
import androidx.compose.material3.Divider
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
@ -26,13 +24,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.screen.ble.icon
import llc.arma.ble.app.ui.screen.ble.localized
import llc.arma.ble.app.ui.screen.locale.icon
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.data.repository.BleRepositoryImpl
import llc.arma.ble.domain.model.BleInfo
@Composable
fun BleInfoView(
bleInfo: BleInfo
bleInfo: BleInfo,
version: BleRepositoryImpl.Version
) {
Surface(
@ -45,7 +45,7 @@ fun BleInfoView(
modifier = Modifier.padding(8.dp)
) {
Column() {
Column {
BleInfoItem(
icon = {
@ -54,21 +54,8 @@ fun BleInfoView(
contentDescription = null
)
},
title = "Тип метки",
subtitle = bleInfo.type.localized
)
SpecDivider()
BleInfoItem(
icon = {
Icon(
imageVector = Icons.Rounded.ShortText,
contentDescription = null
)
},
title = "Наименование",
subtitle = bleInfo.name
title = bleInfo.name,
subtitle = "${bleInfo.type.localized} v${version}"
)
SpecDivider()
@ -119,13 +106,13 @@ fun BleInfoView(
}
@Composable
private fun ColumnScope.SpecDivider(){
private fun SpecDivider(){
Spacer(modifier = Modifier.height(12.dp))
Spacer(modifier = Modifier.height(6.dp))
Divider()
HorizontalDivider()
Spacer(modifier = Modifier.height(12.dp))
Spacer(modifier = Modifier.height(6.dp))
}

View File

@ -3,9 +3,9 @@ package llc.arma.ble.app.ui.screen.ble
import llc.arma.ble.app.ui.common.ViewEvent
import llc.arma.ble.app.ui.common.ViewSideEffect
import llc.arma.ble.app.ui.common.ViewState
import llc.arma.ble.domain.model.BleFilter
import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.model.ConnectedBleInfo
import llc.arma.ble.domain.model.BleFilter
class BleListContract {

View File

@ -17,10 +17,12 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ContentAlpha
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowRightAlt
import androidx.compose.material.icons.rounded.ArrowRightAlt
import androidx.compose.material.icons.rounded.BatteryFull
import androidx.compose.material.icons.rounded.CompareArrows
@ -45,9 +47,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
@ -55,9 +59,10 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.SignalLevel
import llc.arma.ble.app.ui.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.locale.icon
import llc.arma.ble.domain.model.BleFilter
import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.model.ConnectedBleInfo
import llc.arma.ble.domain.model.BleFilter
import kotlin.math.pow
@OptIn(ExperimentalMaterial3Api::class)
@ -71,6 +76,8 @@ fun BleListScreen(
val bottomDialog = rememberBottomDialogState()
val scrollState = rememberLazyListState()
LaunchedEffect("effect"){
viewModel.effect.onEach {
when(it){
@ -95,6 +102,9 @@ fun BleListScreen(
Column {
TopAppBar(
modifier = Modifier
.zIndex(1f)
.shadow(if (scrollState.canScrollBackward) 8.dp else 0.dp),
title = {
Text(text = "Arma BLE")
},
@ -198,7 +208,9 @@ fun BleListScreen(
}
} else {
LazyColumn(
state = scrollState,
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.fillMaxSize()
) {
@ -211,9 +223,10 @@ fun BleListScreen(
}
items(items = filteredData) {
items(
items = filteredData,
key = { it.serial }
) {
BleItem(
ble = it,
@ -285,17 +298,16 @@ fun BleItem(
LaunchedEffect(ble.scanTime) {
while(true) {
time = SystemClock.elapsedRealtime()
delay(100)
delay(1000)
}
}
var alpha = if(SystemClock.elapsedRealtime() - ble.scanTime > 10_000){
val alpha = if(SystemClock.elapsedRealtime() - ble.scanTime > 10_000){
disabledAlpha
} else {
highAlpha
}
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp),
@ -303,8 +315,11 @@ fun BleItem(
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
.background(color)
.clickable { onClick() }
.padding(vertical = 8.dp, horizontal = 16.dp)
.clickable(onClick = onClick)
.padding(
vertical = 8.dp,
horizontal = 16.dp
)
.alpha(alpha)
) {
@ -369,9 +384,13 @@ fun BleItem(
Spacer(modifier = Modifier.width(4.dp))
val distance = remember(ble.rssi, ble.tx) {
String.format("%.3f", (10.0.pow((ble.tx.toDouble() - (ble.rssi?.toDouble() ?: 0.0) - 74) / 20))) + " м."
}
Text(
style = MaterialTheme.typography.bodyMedium,
text = String.format("%.3f", (10.0.pow((ble.tx.toDouble() - (ble.rssi?.toDouble() ?: 0.0) - 74) / 20))) + " м."
text = distance
)
}
@ -450,7 +469,7 @@ fun BleItem(
Icon(
modifier = Modifier.size(16.dp),
imageVector = Icons.Rounded.ArrowRightAlt,
imageVector = Icons.AutoMirrored.Rounded.ArrowRightAlt,
contentDescription = null
)
@ -481,10 +500,8 @@ fun BleItem(
}
}
}
}
@ -505,7 +522,7 @@ private fun ConnectedBleItem(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
.clickable { onClick() }
.clickable(onClick = onClick)
.background(MaterialTheme.colorScheme.tertiaryContainer.copy(alpha = .99f))
.padding(vertical = 8.dp, horizontal = 16.dp)

View File

@ -1,31 +1,23 @@
package llc.arma.ble.app.ui.screen.ble
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.BatteryFull
import androidx.compose.material.icons.rounded.Bluetooth
import androidx.compose.material.icons.rounded.Close
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.Nfc
import androidx.compose.material.icons.rounded.Search
import androidx.compose.material.icons.rounded.ShortText
import androidx.compose.material.icons.rounded.SignalCellularAlt
import androidx.compose.material.icons.rounded.Sort
import androidx.compose.material.icons.rounded.SortByAlpha
import androidx.compose.material.icons.rounded.Speed
import androidx.compose.material.icons.rounded.Thermostat
import androidx.compose.material.icons.rounded.Warning
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
@ -36,7 +28,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RangeSlider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -45,52 +36,13 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.model.BleFilter
import llc.arma.ble.domain.model.BleInfo
val BleFilter.Order.localized: String
get() {
return when(this){
BleFilter.Order.Asc -> "Прямой ↓"
BleFilter.Order.Desc -> "Обратный ↑"
}
}
val BleFilter.Field.localized: String
get() {
return when(this){
BleFilter.Field.Name -> "Имя"
BleFilter.Field.Mac -> "MAC"
BleFilter.Field.Distance -> "Расстояние"
BleFilter.Field.Dbm -> "dBm"
BleFilter.Field.Battery -> "Заряд"
}
}
val BleInfo.Type?.localized: String
get() {
return when(this){
BleInfo.Type.HOST -> "Хост"
BleInfo.Type.BEACON -> "Маяк"
BleInfo.Type.THERMOMETER -> "Термодатчик"
BleInfo.Type.ACCELEROMETER -> "Акселерометр"
null -> "Все"
}
}
val BleInfo.Type?.icon: ImageVector
get() {
return when(this){
BleInfo.Type.BEACON -> Icons.Rounded.Nfc
BleInfo.Type.THERMOMETER -> Icons.Rounded.Thermostat
BleInfo.Type.ACCELEROMETER -> Icons.Rounded.Speed
BleInfo.Type.HOST -> Icons.Rounded.Info
else -> Icons.Rounded.Warning
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Filter(
@ -98,9 +50,7 @@ fun Filter(
onEvent: (BleListContract.Event) -> Unit
) {
Column(
) {
Column {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
@ -112,6 +62,7 @@ fun Filter(
Column(
modifier = Modifier
.weight(1f)
.padding(horizontal = 12.dp)
.verticalScroll(rememberScrollState())
) {
@ -500,71 +451,20 @@ fun Filter(
}
Spacer(modifier = Modifier.height(20.dp))
}
Box(
modifier = Modifier
) {
Spacer(modifier = Modifier.height(8.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(BleListContract.Event.OnHideFilter)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
)
}
}
}
Spacer(modifier = Modifier.height(8.dp))
Box(
modifier = Modifier
) {
Surface(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.secondaryContainer,
onClick = {
onEvent(BleListContract.Event.OnResetFilter)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSecondaryContainer,
style = MaterialTheme.typography.labelLarge,
text = "Сбросить"
)
}
}
}
Spacer(modifier = Modifier.height(8.dp))
PrimaryButton(
label = "Применить"
) {
onEvent(BleListContract.Event.OnHideFilter)
}
SecondaryButton(
label = "Сбросить"
) {
onEvent(BleListContract.Event.OnResetFilter)
}
}

View File

@ -8,16 +8,16 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.animation.with
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.CircularProgressIndicator
@ -41,6 +41,7 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import llc.arma.ble.app.ui.common.SmallPrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerScreen
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerHistory
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerRealtime
@ -53,7 +54,7 @@ import llc.arma.ble.app.ui.screen.inspection.host.view.table.BleTableEditScreen
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerScreen
import llc.arma.ble.domain.model.Ble
@OptIn(ExperimentalMaterial3Api::class, ExperimentalAnimationApi::class)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ConnectionScreen(
onNavigationEvent: (ConnectionContract.Effect.Navigation) -> Unit
@ -97,7 +98,7 @@ fun ConnectionScreen(
},
content = {
Icon(
imageVector = Icons.Rounded.ArrowBack,
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null
)
}
@ -112,8 +113,8 @@ fun ConnectionScreen(
is ConnectionContract.State.Loading -> "Соединение.."
},
transitionSpec = {
(slideInVertically { height -> height } + fadeIn() with
slideOutVertically { height -> -height } + fadeOut()).using(
((slideInVertically { height -> height } + fadeIn()).togetherWith(
slideOutVertically { height -> -height } + fadeOut())).using(
SizeTransform(clip = false)
)
}
@ -149,18 +150,16 @@ fun ConnectionScreen(
is Ble.Thermometer -> {
Column(modifier = Modifier.weight(1f)) {
ThermometerScreen(
ble = state.ble,
onNavigationEvent = {
viewModel.setEvent(
ConnectionContract.Event.OnThermometerNavigationEvent(it)
ThermometerScreen(
ble = state.ble,
onNavigationEvent = {
viewModel.setEvent(
ConnectionContract.Event.OnThermometerNavigationEvent(
it
)
}
)
}
)
}
)
}
@ -313,27 +312,10 @@ private fun DisplayException(
Spacer(modifier = Modifier.height(18.dp))
Surface(
modifier = Modifier
.height(42.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(ConnectionContract.Event.RefreshBle)
}
SmallPrimaryButton(
label = "Повторить"
) {
Box(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimaryContainer,
style = MaterialTheme.typography.labelLarge,
text = "Повторить"
)
}
onEvent(ConnectionContract.Event.RefreshBle)
}
}

View File

@ -57,6 +57,7 @@ class AccelerometerContract {
object OnChangePassword : Event()
object OnSaveIntervalEdit : Event()
object OnReadIntervalEdit : Event()
object OnHideHistoryEdit : Event()
data class OnRealtimeViewModeChanged(
@ -107,6 +108,10 @@ class AccelerometerContract {
val interval: Long
) : Event()
data class OnReadIntervalChanged(
val interval: Long
) : Event()
}
sealed class State : ViewState {
@ -172,10 +177,12 @@ class AccelerometerContract {
object ShowFftAxisEdit : Effect()
object ShowFftModeEdit : Effect()
object HideIntervalPicker : Effect()
object ShowIntervalPicker : Effect()
object HideReadIntervalPicker : Effect()
object ShowReadIntervalPicker : Effect()
object ShowHistoryEdit : Effect()
sealed class Navigation : Effect() {

View File

@ -16,6 +16,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.TxLevelSelector
import llc.arma.ble.app.ui.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelFftAxisEdit
@ -28,12 +29,12 @@ import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.DisplayState
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.HistoryEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.IntervalEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.LoadingState
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.PowerEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.ReadIntervalEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.Write
import llc.arma.ble.domain.model.Ble
enum class SheetPage {
ACCEL_SCALE, SPECTRE_SCALE, HISTORY_MODE_EDIT, HISTORY_SCALE, HISTORY_EDIT, ACCEL_EDIT, ACCEL_REALTIME_EDIT, POWER, WRITE, ACCEL_MODE_EDIT, SPECTRE_MODE_EDIT, FREQUENCY_EDIT, AXIS_EDIT, FFT_MODE_EDIT, INTERVAL_EDIT
ACCEL_SCALE, SPECTRE_SCALE, HISTORY_MODE_EDIT, HISTORY_SCALE, HISTORY_EDIT, ACCEL_EDIT, ACCEL_REALTIME_EDIT, POWER, WRITE, ACCEL_MODE_EDIT, SPECTRE_MODE_EDIT, FREQUENCY_EDIT, AXIS_EDIT, FFT_MODE_EDIT, INTERVAL_EDIT, READ_INTERVAL_EDIT
}
@OptIn(ExperimentalMaterialApi::class)
@ -60,7 +61,7 @@ fun AccelerometerScreen(
key1 = bottomDialog.sheetState?.currentValue,
block = {
if(bottomDialog.sheetState?.currentValue == ModalBottomSheetValue.Hidden) {
bottomDialog.setContent({})
bottomDialog.setContent {}
sheetPage = null
}
}
@ -75,10 +76,10 @@ fun AccelerometerScreen(
val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) {
PowerEdit(
state = currentState.accelerometer,
onEvent = {
viewModel.setEvent(it)
TxLevelSelector(
tx = currentState.accelerometer.state.tx,
onSelect = {
viewModel.setEvent(AccelerometerContract.Event.OnPowerChanged(it))
}
)
}
@ -94,9 +95,7 @@ fun AccelerometerScreen(
Write(
state = it,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -111,9 +110,7 @@ fun AccelerometerScreen(
AccelViewEdit(
next = AccelerometerContract.Event.Next.ACCEL,
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -126,9 +123,7 @@ fun AccelerometerScreen(
AccelViewEdit(
next = AccelerometerContract.Event.Next.ACCEL,
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -141,9 +136,7 @@ fun AccelerometerScreen(
AccelViewEdit(
next = AccelerometerContract.Event.Next.HISTORY,
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -155,9 +148,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) {
AccelFrequencyEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -169,9 +160,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) {
AccelFftAxisEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -183,9 +172,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) {
AccelFftModeEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -197,9 +184,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) {
IntervalEdit(
state = currentState.accelerometer,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -212,9 +197,7 @@ fun AccelerometerScreen(
AccelScaleEdit(
next = AccelerometerContract.Event.Next.ACCEL,
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -227,9 +210,7 @@ fun AccelerometerScreen(
AccelScaleEdit(
next = AccelerometerContract.Event.Next.ACCEL,
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -242,9 +223,7 @@ fun AccelerometerScreen(
AccelScaleEdit(
next = AccelerometerContract.Event.Next.HISTORY,
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -256,9 +235,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) {
AccelEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -270,9 +247,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) {
HistoryEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -288,9 +263,20 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) {
AccelRealtimeViewEdit(
state = currentState,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
}
SheetPage.READ_INTERVAL_EDIT -> bottomDialog.show {
val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) {
ReadIntervalEdit(
state = currentState.accelerometer,
onEvent = viewModel::setEvent
)
}
@ -395,6 +381,18 @@ fun AccelerometerScreen(
sheetPage = null
delay(100)
}
AccelerometerContract.Effect.HideReadIntervalPicker -> {
sheetPage = null
delay(100)
}
AccelerometerContract.Effect.ShowReadIntervalPicker -> {
sheetPage = null
delay(100)
sheetPage = SheetPage.READ_INTERVAL_EDIT
}
}
}.launchIn(this)
}
@ -406,9 +404,7 @@ fun AccelerometerScreen(
DisplayState(
origin = state.origin,
ble = state.accelerometer,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
is AccelerometerContract.State.Loading -> LoadingState()

View File

@ -60,9 +60,39 @@ class AccelerometerViewModel @Inject constructor(
is AccelerometerContract.Event.OnHistoryScaleChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnHistoryViewModeChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnHideHistoryEdit -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnReadIntervalChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnReadIntervalEdit -> reduce(viewState.value, event)
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnReadIntervalChanged
) {
if(state is AccelerometerContract.State.Display) {
state.accelerometer.accelerometerState.readInterval = event.interval
}
setEffect {
AccelerometerContract.Effect.HideReadIntervalPicker
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnReadIntervalEdit
) {
setEffect {
AccelerometerContract.Effect.ShowReadIntervalPicker
}
}
private fun reduce(
state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnHideHistoryEdit
@ -426,7 +456,8 @@ class AccelerometerViewModel @Inject constructor(
tx = if(newBle.state.tx == state.origin.state.tx) null else newBle.state.tx,
saveHistorySettings = if(newBle.accelerometerState.saveHistorySettings == state.origin.accelerometerState.saveHistorySettings) null else newBle.accelerometerState.saveHistorySettings,
historyInterval = if(newBle.accelerometerState.historyInterval == state.origin.accelerometerState.historyInterval) null else newBle.accelerometerState.historyInterval,
)
readInterval = if(newBle.accelerometerState.readInterval == state.origin.accelerometerState.readInterval) null else newBle.accelerometerState.readInterval,
)
setState {
state.copy(

View File

@ -5,74 +5,22 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.domain.usecase.AccelScale
import llc.arma.ble.domain.usecase.FftAxis
import llc.arma.ble.domain.usecase.FftFrequency
import llc.arma.ble.domain.usecase.FftViewMode
val FftFrequency.localized: String
get() {
return when(this){
FftFrequency.OFF -> "откл"
FftFrequency.F_1 -> "1 Гц"
FftFrequency.F_10 -> "10 Гц"
FftFrequency.F_25 -> "25 Гц"
FftFrequency.F_50 -> "50 Гц"
FftFrequency.F_100 -> "100 Гц"
FftFrequency.F_200 -> "200 Гц"
FftFrequency.F_400 -> "400 Гц"
FftFrequency.F_1620 -> "1620 Гц"
FftFrequency.F_1344 -> "1344 Гц"
}
}
val FftAxis.localized: String
get() {
return when(this){
FftAxis.AUTO -> "Авто"
FftAxis.X -> "Ось X"
FftAxis.Y -> "Ось Y"
FftAxis.Z -> "Ось Z"
}
}
val FftViewMode.localized: String
get() {
return when(this){
FftViewMode.SPECTRE -> "Спектр"
FftViewMode.X -> "Ось X"
FftViewMode.Y -> "Ось Y"
FftViewMode.Z -> "Ось Z"
}
}
val AccelScale.localized: String
get() {
return when(this){
AccelScale.S_2 -> "2g"
AccelScale.S_4 -> "4g"
AccelScale.S_8 -> "8g"
AccelScale.S_16 -> "16g"
}
}
import llc.arma.ble.app.ui.screen.locale.localized
@Composable
fun AccelEdit(
@ -313,29 +261,10 @@ fun AccelEdit(
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnShowAccelerometerAccel)
}
PrimaryButton(
label = "Продолжить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Продолжить"
)
}
onEvent(AccelerometerContract.Event.OnShowAccelerometerAccel)
}
}

View File

@ -1,36 +1,57 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.usecase.FftAxis
@Composable
fun SelectorItem(
label: String,
selected: Boolean,
onClick: () -> Unit
){
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable(onClick = onClick)
.padding(4.dp)
) {
RadioButton(
selected = selected,
onClick = onClick
)
Text(text = label)
}
}
@Composable
fun AccelFftAxisEdit(
state: AccelerometerContract.State.Display,
onEvent: (AccelerometerContract.Event) -> Unit,
){
var fftAxis = state.fftAxis
Column(
modifier = Modifier
) {
@ -43,55 +64,23 @@ fun AccelFftAxisEdit(
Spacer(modifier = Modifier.height(16.dp))
FftAxis.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { onEvent(AccelerometerContract.Event.OnFftAxisChanged(it)) }
.padding(4.dp)
) {
RadioButton(
selected = it == fftAxis,
onClick = {
onEvent(AccelerometerContract.Event.OnFftAxisChanged(it))
}
)
Text(text = it.localized)
FftAxis.entries.forEach {
SelectorItem(
label = it.localized,
selected = it == state.fftAxis
){
onEvent(AccelerometerContract.Event.OnFftAxisChanged(it))
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
}

View File

@ -1,26 +1,17 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.usecase.FftViewMode
@Composable
@ -29,8 +20,6 @@ fun AccelFftModeEdit(
onEvent: (AccelerometerContract.Event) -> Unit,
){
var fftMode = state.fftViewMode
Column(
modifier = Modifier
) {
@ -43,55 +32,23 @@ fun AccelFftModeEdit(
Spacer(modifier = Modifier.height(16.dp))
FftViewMode.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { onEvent(AccelerometerContract.Event.OnFftModeChanged(it)) }
.padding(4.dp)
) {
RadioButton(
selected = it == fftMode,
onClick = {
onEvent(AccelerometerContract.Event.OnFftModeChanged(it))
}
)
Text(text = it.localized)
FftViewMode.entries.forEach {
SelectorItem(
label = it.localized,
selected = it == state.fftViewMode
){
onEvent(AccelerometerContract.Event.OnFftModeChanged(it))
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
}

View File

@ -1,26 +1,17 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.usecase.FftFrequency
@Composable
@ -29,8 +20,6 @@ fun AccelFrequencyEdit(
onEvent: (AccelerometerContract.Event) -> Unit,
){
var fftFrequency = state.fftFrequency
Column(
modifier = Modifier
) {
@ -43,55 +32,23 @@ fun AccelFrequencyEdit(
Spacer(modifier = Modifier.height(16.dp))
FftFrequency.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { onEvent(AccelerometerContract.Event.OnFftFrequencyChanged(it)) }
.padding(4.dp)
) {
RadioButton(
selected = it == fftFrequency,
onClick = {
onEvent(AccelerometerContract.Event.OnFftFrequencyChanged(it))
}
)
Text(text = it.localized)
FftFrequency.entries.forEach {
SelectorItem(
label = it.localized,
selected = it == state.fftFrequency
){
onEvent(AccelerometerContract.Event.OnFftFrequencyChanged(it))
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
}

View File

@ -1,19 +1,15 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -24,17 +20,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.usecase.AccelViewMode
import llc.arma.ble.domain.usecase.AccelViewMode.values
val RealtimeViewMode.localized: String
get() {
return when(this){
is RealtimeViewMode.Accel -> this.accelViewMode.localized
RealtimeViewMode.Spectre -> "Спектр"
}
}
sealed class RealtimeViewMode {
@ -68,27 +57,13 @@ fun AccelRealtimeViewEdit(
Spacer(modifier = Modifier.height(16.dp))
values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { value = RealtimeViewMode.Accel(it) }
.padding(4.dp)
) {
RadioButton(
selected = value is RealtimeViewMode.Accel && it == (value as RealtimeViewMode.Accel).accelViewMode,
onClick = {
value = RealtimeViewMode.Accel(it)
}
)
Text(text = it.localized)
AccelViewMode.entries.forEach {
SelectorItem(
label = it.localized,
selected = value is RealtimeViewMode.Accel && it == (value as RealtimeViewMode.Accel).accelViewMode
){
value = RealtimeViewMode.Accel(it)
}
}
@ -115,31 +90,11 @@ fun AccelRealtimeViewEdit(
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnRealtimeViewModeChanged(value))
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(AccelerometerContract.Event.OnRealtimeViewModeChanged(value))
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
}

View File

@ -1,26 +1,17 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.usecase.AccelScale
@ -31,7 +22,7 @@ fun AccelScaleEdit(
onEvent: (AccelerometerContract.Event) -> Unit,
){
var fftMode = when(next){
val fftMode = when(next){
AccelerometerContract.Event.Next.ACCEL ->
state.accelScale
AccelerometerContract.Event.Next.HISTORY -> {
@ -56,74 +47,33 @@ fun AccelScaleEdit(
Spacer(modifier = Modifier.height(16.dp))
AccelScale.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable {
when(next){
AccelerometerContract.Event.Next.ACCEL ->
onEvent(AccelerometerContract.Event.OnAccelScaleChanged(it))
AccelerometerContract.Event.Next.HISTORY ->
onEvent(AccelerometerContract.Event.OnHistoryScaleChanged(it))
}
}
.padding(4.dp)
) {
RadioButton(
selected = it == fftMode,
onClick = {
when(next){
AccelerometerContract.Event.Next.ACCEL ->
onEvent(AccelerometerContract.Event.OnAccelScaleChanged(it))
AccelerometerContract.Event.Next.HISTORY ->
onEvent(AccelerometerContract.Event.OnHistoryScaleChanged(it))
}
}
)
Text(text = it.localized)
AccelScale.entries.forEach {
SelectorItem(
label = it.localized,
selected = it == fftMode
){
when(next){
AccelerometerContract.Event.Next.ACCEL ->
onEvent(AccelerometerContract.Event.OnAccelScaleChanged(it))
AccelerometerContract.Event.Next.HISTORY ->
onEvent(AccelerometerContract.Event.OnHistoryScaleChanged(it))
}
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
when(next){
AccelerometerContract.Event.Next.ACCEL ->
onEvent(AccelerometerContract.Event.OnAccelEdit)
AccelerometerContract.Event.Next.HISTORY ->
onEvent(AccelerometerContract.Event.OnHistoryEdit)
}
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
when(next){
AccelerometerContract.Event.Next.ACCEL ->
onEvent(AccelerometerContract.Event.OnAccelEdit)
AccelerometerContract.Event.Next.HISTORY ->
onEvent(AccelerometerContract.Event.OnHistoryEdit)
}
}
}

View File

@ -1,50 +1,22 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.usecase.AccelViewMode
import llc.arma.ble.domain.usecase.AccelViewMode.ACCELERATION
import llc.arma.ble.domain.usecase.AccelViewMode.ANGLE
import llc.arma.ble.domain.usecase.AccelViewMode.PEAK_ACCELERATION
import llc.arma.ble.domain.usecase.AccelViewMode.RMS
import llc.arma.ble.domain.usecase.AccelViewMode.ROTATIONS
import llc.arma.ble.domain.usecase.AccelViewMode.VIBRATION
import llc.arma.ble.domain.usecase.AccelViewMode.values
val AccelViewMode.localized: String
get() {
return when(this){
ACCELERATION -> "Ускорение"
PEAK_ACCELERATION -> "Пиковое ускорение"
RMS -> "Среднеквадратичное ускорение"
VIBRATION -> "Вибрация"
ANGLE -> "Угол"
ROTATIONS -> "Обороты"
}
}
@Composable
fun AccelViewEdit(
@ -69,66 +41,32 @@ fun AccelViewEdit(
Spacer(modifier = Modifier.height(16.dp))
values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { value = it }
.padding(4.dp)
) {
RadioButton(
selected = it == value,
onClick = {
value = it
}
)
Text(text = it.localized)
AccelViewMode.entries.forEach {
SelectorItem(
label = it.localized,
selected = it == value
){
value = it
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
when(next){
AccelerometerContract.Event.Next.ACCEL -> {
onEvent(AccelerometerContract.Event.OnAccelViewModelChanged(value))
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
AccelerometerContract.Event.Next.HISTORY -> {
onEvent(AccelerometerContract.Event.OnHistoryViewModeChanged(value))
onEvent(AccelerometerContract.Event.OnHistoryEdit)
}
}
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
when(next){
AccelerometerContract.Event.Next.ACCEL -> {
onEvent(AccelerometerContract.Event.OnAccelViewModelChanged(value))
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
AccelerometerContract.Event.Next.HISTORY -> {
onEvent(AccelerometerContract.Event.OnHistoryViewModeChanged(value))
onEvent(AccelerometerContract.Event.OnHistoryEdit)
}
}
}

View File

@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material3.CircularProgressIndicator
@ -52,6 +53,7 @@ import llc.arma.ble.app.ui.common.BaseViewModel
import llc.arma.ble.app.ui.common.ViewEvent
import llc.arma.ble.app.ui.common.ViewSideEffect
import llc.arma.ble.app.ui.common.ViewState
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.common.ProgressState
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo
@ -112,7 +114,7 @@ fun AccelerometerSpectre(
IconButton(onClick = it) {
Icon(
imageVector = Icons.Rounded.ArrowBack,
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null
)
}
@ -168,7 +170,7 @@ fun AccelerometerSpectre(
modifier = Modifier.size(16.dp),
strokeWidth = 2.dp,
strokeCap = StrokeCap.Round,
progress = progressAnimation,
progress = { progressAnimation },
)
}
@ -318,7 +320,7 @@ fun Display(
CircularProgressIndicator(
strokeCap = StrokeCap.Round,
progress = progressAnimation,
progress = { progressAnimation },
modifier = Modifier.align(Alignment.Center)
)
@ -384,7 +386,7 @@ class AccelerometerSpectreContract {
val loadingHistoryState : ProgressState<List<Ble.Accelerometer.SpectrePoint>>
) : State()
object Exception : State()
data object Exception : State()
}
@ -424,8 +426,6 @@ class AccelerometerSpectreViewModel @Inject constructor(
if(state is AccelerometerSpectreContract.State.Display) {
//if(lastSerial != event.serial) {
lastSerial = event.serial
setState {

View File

@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material3.CircularProgressIndicator
@ -55,6 +56,7 @@ import llc.arma.ble.app.ui.common.BaseViewModel
import llc.arma.ble.app.ui.common.ViewEvent
import llc.arma.ble.app.ui.common.ViewSideEffect
import llc.arma.ble.app.ui.common.ViewState
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.usecase.AccelScale
@ -104,7 +106,7 @@ fun AccelerometerRealtime(
IconButton(onClick = it) {
Icon(
imageVector = Icons.Rounded.ArrowBack,
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null
)
}
@ -386,7 +388,7 @@ fun Display(
}
}
is Ble.Accelerometer.RealtimePoint.Common -> {
Column() {
Column {
Text(text = "Ось X:")
@ -596,7 +598,7 @@ class AccelerometerAccelViewModel @Inject constructor(
private val getAccelerometerMeasureBySerialFlow: GetAccelerometerMeasureBySerialFlow,
) : BaseViewModel<AccelerometerAccelContract.State, AccelerometerAccelContract.Event, AccelerometerAccelContract.Effect>() {
var measureJob: Job? = null
private var measureJob: Job? = null
private var lastSerial: String? = null

View File

@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material.icons.rounded.CloudUpload
import androidx.compose.material.icons.rounded.Refresh
@ -37,6 +38,7 @@ import com.patrykandpatrick.vico.compose.axis.vertical.startAxis
import com.patrykandpatrick.vico.compose.chart.Chart
import com.patrykandpatrick.vico.compose.chart.line.lineChart
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollSpec
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollState
import com.patrykandpatrick.vico.compose.component.textComponent
import com.patrykandpatrick.vico.core.axis.AxisPosition
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
@ -57,6 +59,7 @@ import llc.arma.ble.app.ui.common.BaseViewModel
import llc.arma.ble.app.ui.common.ViewEvent
import llc.arma.ble.app.ui.common.ViewSideEffect
import llc.arma.ble.app.ui.common.ViewState
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.common.ProgressState
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo
@ -67,7 +70,6 @@ import llc.arma.ble.domain.usecase.FftAxis
import llc.arma.ble.domain.usecase.FftFrequency
import llc.arma.ble.domain.usecase.FftViewMode
import llc.arma.ble.domain.usecase.GetAccelerometerHistoryBySerial
import llc.arma.ble.domain.usecase.GetBleBySerial
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
@ -103,13 +105,7 @@ fun AccelerometerHistory(
viewModel.setEvent(AccelerometerHistoryContract.Event.OnStart(ble.name, ble.serial, accelScale, accelMode, fftAxis, fftMode, frequency))
}
/*DisposableEffect("ble") {
onDispose {
viewModel.setEvent(AccelerometerHistoryContract.Event.StopMeasure)
}
}*/
Column() {
Column {
TopAppBar(
navigationIcon = {
@ -117,7 +113,7 @@ fun AccelerometerHistory(
IconButton(onClick = it) {
Icon(
imageVector = Icons.Rounded.ArrowBack,
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null
)
}
@ -348,6 +344,14 @@ fun Display(
guideline = axisGuidelineComponent()
)
val axis = bottomAxis(
tickLength = 0.dp,
valueFormatter = axisValueFormatter,
labelRotationDegrees = -90f,
)
val scrollState = rememberChartScrollState()
when(lastMeasure){
is Ble.Accelerometer.HistoryPoint.Acceleration,
is Ble.Accelerometer.HistoryPoint.Angle -> {
@ -359,11 +363,7 @@ fun Display(
chart = lineChart,
chartModelProducer = xProducer,
startAxis = startAxis(),
bottomAxis = bottomAxis(
tickLength = 0.dp,
valueFormatter = axisValueFormatter,
labelRotationDegrees = -90f,
),
bottomAxis = axis,
modifier = Modifier
.fillMaxWidth()
.weight(1f),
@ -382,11 +382,7 @@ fun Display(
chart = lineChart,
chartModelProducer = yProducer,
startAxis = startAxis(),
bottomAxis = bottomAxis(
tickLength = 0.dp,
valueFormatter = axisValueFormatter,
labelRotationDegrees = -90f,
),
bottomAxis = axis,
modifier = Modifier
.fillMaxWidth()
.weight(1f),
@ -405,11 +401,7 @@ fun Display(
chart = lineChart,
chartModelProducer = zProducer,
startAxis = startAxis(),
bottomAxis = bottomAxis(
tickLength = 0.dp,
valueFormatter = axisValueFormatter,
labelRotationDegrees = -90f,
),
bottomAxis = axis,
modifier = Modifier
.fillMaxWidth()
.weight(1f),
@ -509,7 +501,7 @@ fun Display(
CircularProgressIndicator(
strokeCap = StrokeCap.Round,
progress = progressAnimation,
progress = { progressAnimation },
modifier = Modifier.align(Alignment.Center)
)
@ -544,9 +536,9 @@ class AccelerometerHistoryContract {
sealed class Event : ViewEvent {
object StopMeasure : Event()
data object StopMeasure : Event()
object OnExport : Event()
data object OnExport : Event()
data class OnStart(
val bleName: String,
@ -577,7 +569,7 @@ class AccelerometerHistoryContract {
val loadingHistoryState : ProgressState<List<Ble.Accelerometer.HistoryPoint>>
) : State()
object Exception : State()
data object Exception : State()
}
@ -593,10 +585,9 @@ class AccelerometerHistoryContract {
class AccelerometerHistoryViewModel @Inject constructor(
private val getAccelerometerHistoryBySerial: GetAccelerometerHistoryBySerial,
private val exportToXlsx: ExportToXlsx,
private val getBleBySerial: GetBleBySerial
) : BaseViewModel<AccelerometerHistoryContract.State, AccelerometerHistoryContract.Event, AccelerometerHistoryContract.Effect>() {
var measureJob: Job? = null
private var measureJob: Job? = null
private var lastSerial: String? = null

View File

@ -1,33 +1,35 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowRight
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.BleInfoView
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.inspection.host.view.BleMenuItem
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.data.repository.BleRepositoryImpl
import llc.arma.ble.domain.model.Ble
@Composable
@ -37,11 +39,13 @@ fun DisplayState(
ble: BleView.Accelerometer
) {
Column() {
val scrollState = rememberScrollState()
Column {
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.verticalScroll(scrollState)
.weight(1f)
) {
@ -51,52 +55,22 @@ fun DisplayState(
horizontal = 8.dp
)
) {
BleInfoView(bleInfo = origin.info)
BleInfoView(
bleInfo = origin.info,
version = origin.state.version
)
}
Column(
modifier = Modifier,
content = {
Box(
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 8.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable {
onEvent(AccelerometerContract.Event.OnPowerEdit)
}
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Мощность"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = "${ble.state.tx.value} db"
)
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowDown,
contentDescription = null
)
}
BleMenuItem(
title = "Мощность",
subtitle = "${ble.state.tx.value} db",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowDown)
){
onEvent(AccelerometerContract.Event.OnPowerEdit)
}
Box(
@ -154,50 +128,43 @@ fun DisplayState(
if(ble.accelerometerState.saveHistory is Ble.Accelerometer.HistorySettings.Enabled) {
Box(
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 8.dp
)
val hours =
ble.accelerometerState.historyInterval / millisInHour
val minutes =
(ble.accelerometerState.historyInterval - (hours * millisInHour)) / millisInMinute
val seconds =
(ble.accelerometerState.historyInterval - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
BleMenuItem(
title = "Интервал измерений",
subtitle = "$hours ч. $minutes мин. $seconds сек.",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowDown)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable {
onEvent(AccelerometerContract.Event.OnSaveIntervalEdit)
}
.padding(8.dp)
onEvent(AccelerometerContract.Event.OnSaveIntervalEdit)
}
}
if(ble.state.version > BleRepositoryImpl.Version.fromString("0.0.0-0")) {
if (ble.accelerometerState.saveHistory is Ble.Accelerometer.HistorySettings.Enabled) {
val hours =
ble.accelerometerState.readInterval / millisInHour
val minutes =
(ble.accelerometerState.readInterval - (hours * millisInHour)) / millisInMinute
val seconds =
(ble.accelerometerState.readInterval - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
BleMenuItem(
title = "Интервал чтения",
subtitle = "$hours ч. $minutes мин. $seconds сек.",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowDown)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Интервал измерений"
)
val hours =
ble.accelerometerState.historyInterval / millisInHour
val minutes =
(ble.accelerometerState.historyInterval - (hours * millisInHour)) / millisInMinute
val seconds =
(ble.accelerometerState.historyInterval - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = "$hours ч. $minutes мин. $seconds сек."
)
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowDown,
contentDescription = null
)
onEvent(AccelerometerContract.Event.OnReadIntervalEdit)
}
@ -205,91 +172,25 @@ fun DisplayState(
}
Box(
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 8.dp
)
BleMenuItem(
title = "График измерений",
icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable {
when(origin.accelerometerState.saveHistorySettings){
is Ble.Accelerometer.HistorySettings.Disabled ->
onEvent(AccelerometerContract.Event.OnAccelEdit)
is Ble.Accelerometer.HistorySettings.Enabled ->
onEvent(AccelerometerContract.Event.OnShowAccelerometerHistory)
}
}
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "График измерений"
)
/*Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = when(origin.accelerometerState.saveHistorySettings){
Ble.Accelerometer.HistorySettings.Disabled -> "Текущие измерения"
is Ble.Accelerometer.HistorySettings.Enabled -> ""
}
)*/
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowRight,
contentDescription = null
)
when(origin.accelerometerState.saveHistorySettings){
is Ble.Accelerometer.HistorySettings.Disabled ->
onEvent(AccelerometerContract.Event.OnAccelEdit)
is Ble.Accelerometer.HistorySettings.Enabled ->
onEvent(AccelerometerContract.Event.OnShowAccelerometerHistory)
}
}
Box(
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 8.dp
)
BleMenuItem(
title = "Изменить пароль",
icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable {
onEvent(AccelerometerContract.Event.OnChangePassword)
}
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Изменить пароль"
)
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowRight,
contentDescription = null
)
}
onEvent(AccelerometerContract.Event.OnChangePassword)
}
}
@ -297,28 +198,18 @@ fun DisplayState(
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnShowWriteBlePreview)
}
PrimaryButton(
modifier = Modifier.shadow(
if(scrollState.canScrollForward){
8.dp
} else {
0.dp
}
).background(MaterialTheme.colorScheme.background),
label = "Сохранить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Сохранить"
)
}
onEvent(AccelerometerContract.Event.OnShowWriteBlePreview)
}

View File

@ -5,24 +5,22 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.domain.model.Ble
@Composable
@ -143,29 +141,10 @@ fun HistoryEdit(
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnHideHistoryEdit)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(AccelerometerContract.Event.OnHideHistoryEdit)
}
}

View File

@ -7,23 +7,18 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowUp
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -34,6 +29,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
@ -144,33 +140,14 @@ fun IntervalEdit(
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
AccelerometerContract.Event.OnSaveIntervalChanged(
value.toLong()
)
)
}
PrimaryButton(
label = "Применить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
onEvent(
AccelerometerContract.Event.OnSaveIntervalChanged(
value.toLong()
)
}
)
}
}

View File

@ -1,107 +0,0 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
@Composable
fun PowerEdit(
state: BleView.Accelerometer,
onEvent: (AccelerometerContract.Event) -> Unit,
){
var value by remember(state.state.tx) {
mutableStateOf(state.state.tx)
}
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Мощность",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
BleView.BleState.TX.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { value = it }
.padding(4.dp)
) {
RadioButton(
selected = it == value,
onClick = { value = it }
)
Text(text = it.value.toString() + " dBb (${it.powerPercentage} %)")
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
AccelerometerContract.Event.OnPowerChanged(
value
)
)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
)
}
}
}
}

View File

@ -0,0 +1,65 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.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.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.inspection.host.view.DurationPicker
@Composable
fun ReadIntervalEdit(
state: BleView.Accelerometer,
onEvent: (AccelerometerContract.Event) -> Unit,
){
var value by remember(state.accelerometerState.readInterval) {
mutableIntStateOf((state.accelerometerState.readInterval).toInt())
}
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Интервал чтения",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
DurationPicker(
modifier = Modifier.align(Alignment.CenterHorizontally),
value = value
) {
value = it
}
Spacer(modifier = Modifier.height(16.dp))
PrimaryButton(
label = "Применить"
) {
onEvent(
AccelerometerContract.Event.OnReadIntervalChanged(
value.toLong()
)
)
}
}
}

View File

@ -4,29 +4,26 @@ import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import llc.arma.ble.R
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
import llc.arma.ble.app.ui.screen.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.app.ui.screen.inspection.thermometer.localizedName
import llc.arma.ble.app.ui.screen.inspection.host.view.BleMenuItem
import llc.arma.ble.app.ui.screen.locale.localizedName
import llc.arma.ble.domain.model.Ble
@Composable
@ -50,175 +47,72 @@ fun Write(
when (state) {
is AccelerometerContract.State.Display.WriteState.DisplayPreview -> {
if(state.writeRequest.tx != null || state.writeRequest.saveHistorySettings != null || state.writeRequest.historyInterval != null) {
if(
state.writeRequest.tx != null ||
state.writeRequest.saveHistorySettings != null ||
state.writeRequest.historyInterval != null ||
state.writeRequest.readInterval != null
) {
state.writeRequest.tx?.let {
Box(
modifier = Modifier.padding(
vertical = 0.dp,
horizontal = 8.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.padding(8.dp)
) {
BleMenuItem(
title = "Мощность",
subtitle = "${it.localizedName} db",
)
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Мощность"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = "${it.localizedName} db"
)
}
}
}
}
state.writeRequest.saveHistorySettings?.let {
Box(
modifier = Modifier.padding(
vertical = 0.dp,
horizontal = 8.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Сохранять историю измерений"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = when(it){
Ble.Accelerometer.HistorySettings.Disabled -> "Выключено"
is Ble.Accelerometer.HistorySettings.Enabled -> "Включено"
}
)
}
}
}
BleMenuItem(
title = "Сохранять историю измерений",
subtitle = when(it){
Ble.Accelerometer.HistorySettings.Disabled -> "Выключено"
is Ble.Accelerometer.HistorySettings.Enabled -> "Включено"
},
)
}
state.writeRequest.historyInterval?.let {
Box(
modifier = Modifier.padding(
vertical = 0.dp,
horizontal = 8.dp
)
) {
val hours = it / millisInHour
val minutes = (it - (hours * millisInHour)) / millisInMinute
val seconds = (it - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.padding(8.dp)
) {
BleMenuItem(
title = "Интервал измерений",
subtitle = "$hours ч. $minutes мин. $seconds сек."
)
Column(
modifier = Modifier.weight(1f)
) {
}
Text(
text = "Интервал измерений"
)
state.writeRequest.readInterval?.let {
val hours = it / millisInHour
val minutes = (it - (hours * millisInHour)) / millisInMinute
val seconds = (it - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
val hours = it / millisInHour
val minutes = (it - (hours * millisInHour)) / millisInMinute
val seconds = (it - (hours * millisInHour) - (minutes * millisInMinute)) / millisInSecond
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = "$hours ч. $minutes мин. $seconds сек."
)
}
}
}
BleMenuItem(
title = "Интервал чтения",
subtitle = "$hours ч. $minutes мин. $seconds сек."
)
}
Spacer(modifier = Modifier.height(20.dp))
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnWriteBle)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
PrimaryButton(
label = "Записать"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Записать"
)
}
onEvent(AccelerometerContract.Event.OnWriteBle)
}
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
SecondaryButton(
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
} else {
@ -233,40 +127,20 @@ fun Write(
Spacer(modifier = Modifier.height(64.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
}
}
is AccelerometerContract.State.Display.WriteState.Writing -> {
Box {
Column() {
Column {
Spacer(modifier = Modifier.height(28.dp))
@ -278,29 +152,10 @@ fun Write(
Spacer(modifier = Modifier.height(48.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
SecondaryButton(
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
}
@ -324,7 +179,7 @@ fun Write(
modifier = Modifier
.size(125.dp)
.align(Alignment.Center),
painter = painterResource(llc.arma.ble.R.drawable.ic_done),
painter = painterResource(R.drawable.ic_done),
contentDescription = null
)
@ -339,29 +194,10 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
}
@ -400,29 +236,10 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(AccelerometerContract.Event.OnHideWriteBlePreview)
}
}

View File

@ -17,9 +17,9 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.TxLevelSelector
import llc.arma.ble.app.ui.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.inspection.beacon.view.DisplayState
import llc.arma.ble.app.ui.screen.inspection.beacon.view.PowerEdit
import llc.arma.ble.app.ui.screen.inspection.beacon.view.Write
import llc.arma.ble.domain.model.Ble
@ -92,12 +92,13 @@ fun BeaconScreen(
val currentState = viewModel.viewState.value
if(currentState is BeaconContract.State.Display) {
PowerEdit(
state = currentState.beacon,
onEvent = {
viewModel.setEvent(it)
}
)
TxLevelSelector(
tx = currentState.beacon.state.tx
) {
viewModel.setEvent(BeaconContract.Event.OnPowerChanged(it))
}
}
}
else -> {

View File

@ -1,32 +1,26 @@
package llc.arma.ble.app.ui.screen.inspection.beacon.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowRight
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.BleInfoView
import llc.arma.ble.app.ui.screen.inspection.beacon.BeaconContract
import llc.arma.ble.app.ui.screen.inspection.host.view.BleMenuItem
import llc.arma.ble.domain.model.Ble
@Composable
@ -36,11 +30,13 @@ fun DisplayState(
ble: BleView.Beacon
) {
Column() {
val scrollState = rememberScrollState()
Column {
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.verticalScroll(scrollState)
.weight(1f)
) {
@ -50,118 +46,48 @@ fun DisplayState(
horizontal = 8.dp
)
) {
BleInfoView(bleInfo = origin.info)
BleInfoView(
bleInfo = origin.info,
version = origin.state.version
)
}
Column(
modifier = Modifier,
content = {
Box(
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 8.dp
)
BleMenuItem(
title = "Мощность",
subtitle = "${ble.state.tx.value} db",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowDown)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable {
onEvent(BeaconContract.Event.OnPowerEdit)
}
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Мощность"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = "${ble.state.tx.value} db"
)
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowDown,
contentDescription = null
)
}
onEvent(BeaconContract.Event.OnPowerEdit)
}
Box(
modifier = Modifier.padding(
vertical = 8.dp,
horizontal = 8.dp
)
BleMenuItem(
title = "Изменить пароль",
icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable {
onEvent(BeaconContract.Event.OnChangePassword)
}
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Изменить пароль"
)
}
Icon(
imageVector = Icons.Rounded.KeyboardArrowRight,
contentDescription = null
)
}
onEvent(BeaconContract.Event.OnChangePassword)
}
}
)
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(BeaconContract.Event.OnShowWriteBlePreview)
}
PrimaryButton(
modifier = Modifier.shadow(
if(scrollState.canScrollForward){
8.dp
} else {
0.dp
}
).background(MaterialTheme.colorScheme.background),
label = "Сохранить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Сохранить"
)
}
onEvent(BeaconContract.Event.OnShowWriteBlePreview)
}
}

View File

@ -1,107 +0,0 @@
package llc.arma.ble.app.ui.screen.inspection.beacon.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.beacon.BeaconContract
@Composable
fun PowerEdit(
state: BleView.Beacon,
onEvent: (BeaconContract.Event) -> Unit,
){
var value by remember(state.state.tx) {
mutableStateOf(state.state.tx)
}
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Мощность",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
BleView.BleState.TX.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { value = it }
.padding(4.dp)
) {
RadioButton(
selected = it == value,
onClick = { value = it }
)
Text(text = it.value.toString() + " dBb (${it.powerPercentage} %)")
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
BeaconContract.Event.OnPowerChanged(
value
)
)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
)
}
}
}
}

View File

@ -6,16 +6,13 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -25,8 +22,10 @@ import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import llc.arma.ble.R
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
import llc.arma.ble.app.ui.screen.inspection.beacon.BeaconContract
import llc.arma.ble.app.ui.screen.inspection.thermometer.localizedName
import llc.arma.ble.app.ui.screen.locale.localizedName
@Composable
fun Write(
@ -88,54 +87,16 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(BeaconContract.Event.OnWriteBle)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
PrimaryButton(
label = "Записать"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Записать"
)
}
onEvent(BeaconContract.Event.OnWriteBle)
}
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
SecondaryButton(
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
} else {
@ -150,29 +111,10 @@ fun Write(
Spacer(modifier = Modifier.height(64.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
}
@ -183,7 +125,7 @@ fun Write(
Box {
Column() {
Column {
Spacer(modifier = Modifier.height(28.dp))
@ -195,29 +137,10 @@ fun Write(
Spacer(modifier = Modifier.height(48.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
SecondaryButton(
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
}
@ -256,29 +179,10 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
}
@ -317,29 +221,10 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(BeaconContract.Event.OnHideWriteBlePreview)
}
}

View File

@ -17,10 +17,10 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.TxLevelSelector
import llc.arma.ble.app.ui.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.inspection.host.view.DisplayState
import llc.arma.ble.app.ui.screen.inspection.host.view.IntervalEdit
import llc.arma.ble.app.ui.screen.inspection.host.view.PowerEdit
import llc.arma.ble.app.ui.screen.inspection.host.view.ReadIntervalEdit
import llc.arma.ble.app.ui.screen.inspection.host.view.Write
import llc.arma.ble.domain.model.Ble
@ -112,12 +112,11 @@ fun HostScreen(
val currentState = viewModel.viewState.value
if(currentState is HostContract.State.Display) {
PowerEdit(
state = currentState.host,
onEvent = {
viewModel.setEvent(it)
}
)
TxLevelSelector(
tx = currentState.host.state.tx
) {
viewModel.setEvent(HostContract.Event.OnPowerChanged(it))
}
}
}
SheetPage.INTERVAL_EDIT -> bottomDialog.show {

View File

@ -1,31 +1,30 @@
package llc.arma.ble.app.ui.screen.inspection.host.view
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowRight
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.BleInfoView
import llc.arma.ble.app.ui.screen.inspection.host.HostContract
@ -38,11 +37,13 @@ fun DisplayState(
ble: BleView.Host
) {
val scrollState = rememberScrollState()
Column {
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.verticalScroll(scrollState)
.weight(1f)
) {
@ -52,7 +53,10 @@ fun DisplayState(
horizontal = 8.dp
)
) {
BleInfoView(bleInfo = origin.info)
BleInfoView(
bleInfo = origin.info,
version = origin.state.version
)
}
Column(
@ -98,21 +102,21 @@ fun DisplayState(
BleMenuItem(
title = "График измерений",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowRight)
icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) {
onEvent(HostContract.Event.OnShowHostHistory)
}
BleMenuItem(
title = "Таблица BLE ID",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowRight)
icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) {
onEvent(HostContract.Event.OnShowHostBleTable)
}
BleMenuItem(
title = "Изменить пароль",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowRight)
icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) {
onEvent(HostContract.Event.OnChangePassword)
}
@ -122,29 +126,17 @@ fun DisplayState(
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(HostContract.Event.OnShowWriteBlePreview)
}
PrimaryButton(
modifier = Modifier.shadow(
if(scrollState.canScrollForward){
8.dp
} else {
0.dp
}
).background(MaterialTheme.colorScheme.background),
label = "Сохранить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Сохранить"
)
}
onEvent(HostContract.Event.OnShowWriteBlePreview)
}
}
@ -155,8 +147,8 @@ fun DisplayState(
fun BleMenuItem(
title: String,
subtitle: String? = null,
icon: Painter,
onClick: () -> Unit
icon: Painter? = null,
onClick: (() -> Unit) = {}
){
Box(
@ -170,7 +162,7 @@ fun BleMenuItem(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.clickable { onClick() }
.clickable(onClick = onClick)
.padding(8.dp)
) {
@ -192,10 +184,12 @@ fun BleMenuItem(
}
Icon(
painter = icon,
contentDescription = null
)
if (icon != null) {
Icon(
painter = icon,
contentDescription = null
)
}
}

View File

@ -20,10 +20,10 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ContentAlpha
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material.icons.rounded.Save
@ -52,15 +52,12 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewModelScope
import com.patrykandpatrick.vico.compose.axis.ChartShape
import com.patrykandpatrick.vico.compose.axis.axisGuidelineComponent
import com.patrykandpatrick.vico.compose.axis.axisLineComponent
import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis
import com.patrykandpatrick.vico.compose.axis.vertical.startAxis
import com.patrykandpatrick.vico.compose.chart.Chart
import com.patrykandpatrick.vico.compose.chart.column.columnChart
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollSpec
import com.patrykandpatrick.vico.compose.component.lineComponent
import com.patrykandpatrick.vico.compose.component.shapeComponent
import com.patrykandpatrick.vico.compose.component.textComponent
import com.patrykandpatrick.vico.core.axis.AxisPosition
@ -122,13 +119,7 @@ fun HostHistory(
viewModel.setEvent(HostHistoryContract.Event.OnStart(ble.name, ble.serial))
}
/*DisposableEffect("ble") {
onDispose {
viewModel.setEvent(AccelerometerHistoryContract.Event.StopMeasure)
}
}*/
Column() {
Column {
TopAppBar(
navigationIcon = {
@ -136,7 +127,7 @@ fun HostHistory(
IconButton(onClick = it) {
Icon(
imageVector = Icons.Rounded.ArrowBack,
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null
)
}
@ -217,6 +208,18 @@ val colorsStack = listOf(
Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c),
Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f),
Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee),
Color(0xff2f4f4f), Color(0xff7f0000), Color(0xFFFF0000), Color(0xffffd700),
Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c),
Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f),
Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee),
Color(0xff2f4f4f), Color(0xff7f0000), Color(0xFFFF0000), Color(0xffffd700),
Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c),
Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f),
Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee),
Color(0xff2f4f4f), Color(0xff7f0000), Color(0xFFFF0000), Color(0xffffd700),
Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c),
Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f),
Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee),
)
val startAxisValueFormatter =
@ -413,7 +416,7 @@ fun Display(
modifier = Modifier.verticalScroll(rememberScrollState())
) {
allSerials.mapIndexed { index, s ->
allSerials.mapIndexed { _, s ->
LegendItem(s = s)
}
@ -433,7 +436,7 @@ fun Display(
modifier = Modifier.horizontalScroll(rememberScrollState())
) {
allSerials.mapIndexed { index, s ->
allSerials.mapIndexed { _, s ->
LegendItem(s = s)
}
@ -490,7 +493,7 @@ fun Display(
CircularProgressIndicator(
strokeCap = StrokeCap.Round,
progress = progressAnimation,
progress = { progressAnimation },
modifier = Modifier.align(Alignment.Center)
)
@ -566,12 +569,11 @@ class HostHistoryContract {
@HiltViewModel
class HostHistoryViewModel @Inject constructor(
private val getHostHistoryBySerial: GetHostHistoryBySerial,
private val getBleBySerial: GetBleBySerial,
private val getBleNamesFlow: GetBleNamesFlow,
private val exportToXlsx: ExportToXlsx
) : BaseViewModel<HostHistoryContract.State, HostHistoryContract.Event, HostHistoryContract.Effect>() {
var measureJob: Job? = null
private var measureJob: Job? = null
private var lastSerial: String? = null

View File

@ -7,23 +7,18 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowUp
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -34,6 +29,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.host.HostContract
@ -68,33 +64,14 @@ fun IntervalEdit(
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
HostContract.Event.OnSaveIntervalChanged(
value.toLong()
)
)
}
PrimaryButton(
label = "Применить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
onEvent(
HostContract.Event.OnSaveIntervalChanged(
value.toLong()
)
}
)
}
}

View File

@ -1,107 +0,0 @@
package llc.arma.ble.app.ui.screen.inspection.host.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.host.HostContract
@Composable
fun PowerEdit(
state: BleView.Host,
onEvent: (HostContract.Event) -> Unit,
){
var value by remember(state.state.tx) {
mutableStateOf(state.state.tx)
}
Column(
modifier = Modifier
) {
Text(
modifier = Modifier.padding(horizontal = 12.dp),
text = "Мощность",
style = MaterialTheme.typography.titleLarge
)
Spacer(modifier = Modifier.height(16.dp))
BleView.BleState.TX.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { value = it }
.padding(4.dp)
) {
RadioButton(
selected = it == value,
onClick = { value = it }
)
Text(text = it.value.toString() + " dBb (${it.powerPercentage} %)")
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
HostContract.Event.OnPowerChanged(
value
)
)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
)
}
}
}
}

View File

@ -1,32 +1,13 @@
package llc.arma.ble.app.ui.screen.inspection.host.view
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowUp
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
@ -34,6 +15,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.host.HostContract
@ -68,33 +50,14 @@ fun ReadIntervalEdit(
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
HostContract.Event.OnSaveReadIntervalChanged(
value.toLong()
)
)
}
PrimaryButton(
label = "Применить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
onEvent(
HostContract.Event.OnSaveReadIntervalChanged(
value.toLong()
)
}
)
}
}

View File

@ -6,16 +6,13 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -25,8 +22,10 @@ import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import llc.arma.ble.R
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
import llc.arma.ble.app.ui.screen.inspection.host.HostContract
import llc.arma.ble.app.ui.screen.inspection.thermometer.localizedName
import llc.arma.ble.app.ui.screen.locale.localizedName
@Composable
fun Write(
@ -172,54 +171,16 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(HostContract.Event.OnWriteBle)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
PrimaryButton(
label = "Записать"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Записать"
)
}
onEvent(HostContract.Event.OnWriteBle)
}
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(HostContract.Event.OnHideWriteBlePreview)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
SecondaryButton(
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
} else {
@ -234,29 +195,10 @@ fun Write(
Spacer(modifier = Modifier.height(64.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
}
@ -267,7 +209,7 @@ fun Write(
Box {
Column() {
Column {
Spacer(modifier = Modifier.height(28.dp))
@ -279,29 +221,10 @@ fun Write(
Spacer(modifier = Modifier.height(48.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
SecondaryButton(
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
}
@ -340,29 +263,10 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
}
@ -401,29 +305,10 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(HostContract.Event.OnHideWriteBlePreview)
}
}

View File

@ -8,15 +8,14 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material.icons.rounded.ArrowBack
import androidx.compose.material.icons.rounded.RemoveCircleOutline
@ -47,6 +46,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.ble.BleItem
import llc.arma.ble.domain.model.BleInfo
@ -106,7 +106,7 @@ fun BleTableEditScreen(
}
}) {
Icon(
imageVector = Icons.Rounded.ArrowBack,
imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null
)
}
@ -169,28 +169,10 @@ fun BleTableEditScreen(
text = "Во время загрузки произошла ошибка",
)
Surface(
modifier = Modifier
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
viewModel.setEvent(BleTableEditContract.Event.OnStart(serial))
}
PrimaryButton(
label = "Повторить"
) {
Box(modifier = Modifier) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Повторить"
)
}
viewModel.setEvent(BleTableEditContract.Event.OnStart(serial))
}
}
@ -283,29 +265,10 @@ fun BleTableEditScreen(
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
viewModel.setEvent(BleTableEditContract.Event.OnWritePreview)
}
PrimaryButton(
label = "Записать"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Записать"
)
}
viewModel.setEvent(BleTableEditContract.Event.OnWritePreview)
}
if(editBle != null){
@ -343,33 +306,15 @@ fun BleTableEditScreen(
}
)
Surface(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
viewModel.setEvent(
BleTableEditContract.Event.OnAddBle(
ble = editBle!!.copy(name = name)
)
)
editBle = null
}
PrimaryButton(
label = "Сохранить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Сохранить"
viewModel.setEvent(
BleTableEditContract.Event.OnAddBle(
ble = editBle!!.copy(name = name)
)
}
)
editBle = null
}
}
@ -456,30 +401,10 @@ fun BleSelectorScreen(
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onClose()
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Сохранить"
)
}
}
PrimaryButton(
label = "Сохранить",
onClick = onClose
)
}

View File

@ -5,17 +5,14 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@ -25,6 +22,8 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import llc.arma.ble.R
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
@Composable
fun Write(
@ -85,98 +84,38 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(BleTableEditContract.Event.OnWrite)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
PrimaryButton(
label = "Записать"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Записать"
)
}
onEvent(BleTableEditContract.Event.OnWrite)
}
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
SecondaryButton (
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
}
is BleTableEditContract.State.Display.WriteState.Writing -> {
Box {
Column {
Column() {
Spacer(modifier = Modifier.height(28.dp))
Spacer(modifier = Modifier.height(28.dp))
CircularProgressIndicator(
strokeCap = StrokeCap.Round,
modifier = Modifier
.align(Alignment.CenterHorizontally)
)
CircularProgressIndicator(
strokeCap = StrokeCap.Round,
modifier = Modifier
.align(Alignment.CenterHorizontally)
)
Spacer(modifier = Modifier.height(48.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
}
Spacer(modifier = Modifier.height(48.dp))
SecondaryButton (
label = "Отменить"
) {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
}
@ -184,60 +123,37 @@ fun Write(
}
BleTableEditContract.State.Display.WriteState.Success -> {
Box {
Column {
Column {
Box(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
) {
Box(
Image(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
) {
Image(
modifier = Modifier
.size(125.dp)
.align(Alignment.Center),
painter = painterResource(R.drawable.ic_done),
contentDescription = null
)
}
Spacer(modifier = Modifier.height(16.dp))
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = "Успешно завершено"
.size(125.dp)
.align(Alignment.Center),
painter = painterResource(R.drawable.ic_done),
contentDescription = null
)
Spacer(modifier = Modifier.height(20.dp))
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
) {
Spacer(modifier = Modifier.height(16.dp))
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = "Успешно завершено"
)
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
}
Spacer(modifier = Modifier.height(20.dp))
PrimaryButton(
label = "Ok"
) {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
}
@ -245,60 +161,37 @@ fun Write(
}
BleTableEditContract.State.Display.WriteState.Failure -> {
Box {
Column {
Column {
Box(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
) {
Box(
Image(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
) {
Image(
modifier = Modifier
.size(125.dp)
.align(Alignment.Center),
painter = painterResource(R.drawable.ic_error),
contentDescription = null
)
}
Spacer(modifier = Modifier.height(16.dp))
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = "Ошибка записи"
.size(125.dp)
.align(Alignment.Center),
painter = painterResource(R.drawable.ic_error),
contentDescription = null
)
Spacer(modifier = Modifier.height(20.dp))
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
) {
Spacer(modifier = Modifier.height(16.dp))
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = "Ошибка записи"
)
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
}
Spacer(modifier = Modifier.height(20.dp))
PrimaryButton(
label = "Ok"
) {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
}

View File

@ -12,11 +12,11 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import llc.arma.ble.app.ui.common.TxLevelSelector
import llc.arma.ble.app.ui.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.DisplayState
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.IntervalEdit
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.LoadingState
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.PowerEdit
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.TemperatureHistory
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.Write
import llc.arma.ble.domain.model.Ble
@ -34,22 +34,6 @@ val Boolean.localizedName: String
}
}
val Ble.BleState.TX.localizedName: String
get() {
return when(this){
Ble.BleState.TX.MINUS_40 -> "-40"
Ble.BleState.TX.MINUS_20 -> "-20"
Ble.BleState.TX.MINUS_16 -> "-16"
Ble.BleState.TX.MINUS_12 -> "-12"
Ble.BleState.TX.MINUS_8 -> "-8"
Ble.BleState.TX.MINUS_4 -> "-4"
Ble.BleState.TX.ZERO -> "0"
Ble.BleState.TX.PLUS_3 -> "3"
Ble.BleState.TX.PLUS_4 -> "4"
}.toString()
}
@Composable
fun ThermometerScreen(
ble: Ble.Thermometer,
@ -74,9 +58,7 @@ fun ThermometerScreen(
if(currentState is ThermometerContract.State.Display) {
IntervalEdit(
state = currentState.thermometer,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}
@ -86,12 +68,13 @@ fun ThermometerScreen(
val currentState = viewModel.viewState.value
if(currentState is ThermometerContract.State.Display) {
PowerEdit(
state = currentState.thermometer,
onEvent = {
viewModel.setEvent(it)
}
)
TxLevelSelector(
tx = currentState.thermometer.state.tx
) {
viewModel.setEvent(ThermometerContract.Event.OnPowerChanged(it))
}
}
}
@ -115,9 +98,7 @@ fun ThermometerScreen(
Write(
state = it,
onEvent = {
viewModel.setEvent(it)
}
onEvent = viewModel::setEvent
)
}

View File

@ -1,15 +1,12 @@
package llc.arma.ble.app.ui.screen.inspection.thermometer.view
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
@ -17,14 +14,15 @@ import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowRight
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.BleInfoView
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
@ -37,11 +35,13 @@ fun DisplayState(
ble: BleView.Thermometer
) {
Column() {
val scrollState = rememberScrollState()
Column {
Column(
modifier = Modifier
.verticalScroll(rememberScrollState())
.verticalScroll(scrollState)
.weight(1f)
) {
@ -51,7 +51,10 @@ fun DisplayState(
horizontal = 8.dp
)
) {
BleInfoView(bleInfo = origin.info)
BleInfoView(
bleInfo = origin.info,
version = origin.state.version
)
}
Column(
@ -292,29 +295,17 @@ fun DisplayState(
}
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(ThermometerContract.Event.OnShowWriteBlePreview)
}
PrimaryButton(
modifier = Modifier.shadow(
if(scrollState.canScrollForward){
8.dp
} else {
0.dp
}
).background(MaterialTheme.colorScheme.background),
label = "Сохранить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Сохранить"
)
}
onEvent(ThermometerContract.Event.OnShowWriteBlePreview)
}
}

View File

@ -7,33 +7,29 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowUp
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
@ -44,7 +40,7 @@ fun IntervalEdit(
){
var value by remember(state.thermometerState.historyInterval) {
mutableStateOf((state.thermometerState.historyInterval / 1000 / 60 / 60).toInt())
mutableIntStateOf((state.thermometerState.historyInterval / 1000 / 60 / 60).toInt())
}
val maxInterval = 240
@ -75,7 +71,6 @@ fun IntervalEdit(
Spacer(modifier = Modifier.height(16.dp))
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.align(Alignment.CenterHorizontally)
@ -109,33 +104,14 @@ fun IntervalEdit(
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
ThermometerContract.Event.OnSaveIntervalChanged(
value.toLong() * 1000 * 60 * 60
)
)
}
PrimaryButton(
label = "Применить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
onEvent(
ThermometerContract.Event.OnSaveIntervalChanged(
value.toLong() * 1000 * 60 * 60
)
}
)
}
}

View File

@ -1,30 +1,21 @@
package llc.arma.ble.app.ui.screen.inspection.thermometer.view
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.model.BleView
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.SelectorItem
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
@Composable
@ -49,57 +40,27 @@ fun PowerEdit(
Spacer(modifier = Modifier.height(16.dp))
BleView.BleState.TX.values().forEach {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(8.dp))
.clickable { value = it }
.padding(4.dp)
) {
RadioButton(
selected = it == value,
onClick = { value = it }
)
Text(text = it.value.toString() + " dBb (${it.powerPercentage} %)")
BleView.BleState.TX.entries.forEach {
SelectorItem(
label = "${it.value} dBb (${it.powerPercentage} %)",
selected = it == value
){
value = it
}
}
Spacer(modifier = Modifier.height(16.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
ThermometerContract.Event.OnPowerChanged(
value
)
)
}
PrimaryButton(
label = "Применить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
onEvent(
ThermometerContract.Event.OnPowerChanged(
value
)
}
)
}
}

View File

@ -65,8 +65,6 @@ class TemperatureEntry(
}
val formatter = SimpleDateFormat("dd.MM HH:mm", Locale.getDefault())
@Composable

View File

@ -4,29 +4,27 @@ import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import llc.arma.ble.R
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
import llc.arma.ble.app.ui.screen.inspection.host.view.BleMenuItem
import llc.arma.ble.app.ui.screen.inspection.thermometer.ThermometerContract
import llc.arma.ble.app.ui.screen.inspection.thermometer.localizedName
import llc.arma.ble.app.ui.screen.locale.localizedName
@Composable
fun Write(
@ -52,168 +50,47 @@ fun Write(
if(state.writeRequest.tx != null || state.writeRequest.saveHistory != null || state.writeRequest.historyInterval != null) {
state.writeRequest.tx?.let {
Box(
modifier = Modifier.padding(
vertical = 0.dp,
horizontal = 8.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.padding(8.dp)
) {
BleMenuItem(
title = "Мощность",
subtitle = "${it.localizedName} db"
)
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Мощность"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = "${it.localizedName} db"
)
}
}
}
}
state.writeRequest.saveHistory?.let {
Box(
modifier = Modifier.padding(
vertical = 0.dp,
horizontal = 8.dp
)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
Text(
text = "Сохранять историю измерений"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = it.localizedName
)
}
}
}
BleMenuItem(
title = "Сохранять историю измерений",
subtitle = it.localizedName
)
}
state.writeRequest.historyInterval?.let {
Box(
modifier = Modifier.padding(
vertical = 0.dp,
horizontal = 8.dp
)
) {
val hours = it / 1000 / 60 / 60
val minutes = (it - ( hours * 1000 * 60 * 60 )) / 1000 / 60
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.clip(RoundedCornerShape(16.dp))
.padding(8.dp)
) {
Column(
modifier = Modifier.weight(1f)
) {
val hours = it / 1000 / 60 / 60
val minutes = (it - ( hours * 1000 * 60 * 60 )) / 1000 / 60
Text(
text = "Интервал измерений"
)
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
text = "$hours ч. $minutes мин."
)
}
}
}
BleMenuItem(
title = "Интервал измерений",
subtitle = "$hours ч. $minutes мин."
)
}
Spacer(modifier = Modifier.height(20.dp))
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(ThermometerContract.Event.OnWriteBle)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
PrimaryButton(
label = "Записать"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Записать"
)
}
onEvent(ThermometerContract.Event.OnWriteBle)
}
Surface(
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
SecondaryButton(
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
} else {
@ -228,29 +105,10 @@ fun Write(
Spacer(modifier = Modifier.height(64.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
}
@ -261,7 +119,7 @@ fun Write(
Box {
Column() {
Column {
Spacer(modifier = Modifier.height(28.dp))
@ -273,29 +131,10 @@ fun Write(
Spacer(modifier = Modifier.height(48.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
SecondaryButton(
label = "Отменить"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
}
@ -334,29 +173,10 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
}
@ -395,29 +215,10 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp))
Surface(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
PrimaryButton(
label = "Ок"
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
onEvent(ThermometerContract.Event.OnHideWriteBlePreview)
}
}

View File

@ -0,0 +1,147 @@
package llc.arma.ble.app.ui.screen.locale
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.Nfc
import androidx.compose.material.icons.rounded.Speed
import androidx.compose.material.icons.rounded.Thermostat
import androidx.compose.material.icons.rounded.Warning
import androidx.compose.ui.graphics.vector.ImageVector
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.RealtimeViewMode
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleFilter
import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.usecase.AccelScale
import llc.arma.ble.domain.usecase.AccelViewMode
import llc.arma.ble.domain.usecase.AccelViewMode.ACCELERATION
import llc.arma.ble.domain.usecase.AccelViewMode.ANGLE
import llc.arma.ble.domain.usecase.AccelViewMode.PEAK_ACCELERATION
import llc.arma.ble.domain.usecase.AccelViewMode.RMS
import llc.arma.ble.domain.usecase.AccelViewMode.ROTATIONS
import llc.arma.ble.domain.usecase.AccelViewMode.VIBRATION
import llc.arma.ble.domain.usecase.FftAxis
import llc.arma.ble.domain.usecase.FftFrequency
import llc.arma.ble.domain.usecase.FftViewMode
val Ble.BleState.TX.localizedName: String
get() {
return when(this){
Ble.BleState.TX.MINUS_40 -> "-40"
Ble.BleState.TX.MINUS_20 -> "-20"
Ble.BleState.TX.MINUS_16 -> "-16"
Ble.BleState.TX.MINUS_12 -> "-12"
Ble.BleState.TX.MINUS_8 -> "-8"
Ble.BleState.TX.MINUS_4 -> "-4"
Ble.BleState.TX.ZERO -> "0"
Ble.BleState.TX.PLUS_3 -> "3"
Ble.BleState.TX.PLUS_4 -> "4"
}
}
val BleFilter.Order.localized: String
get() {
return when(this){
BleFilter.Order.Asc -> "Прямой ↓"
BleFilter.Order.Desc -> "Обратный ↑"
}
}
val BleFilter.Field.localized: String
get() {
return when(this){
BleFilter.Field.Name -> "Имя"
BleFilter.Field.Mac -> "MAC"
BleFilter.Field.Distance -> "Расстояние"
BleFilter.Field.Dbm -> "dBm"
BleFilter.Field.Battery -> "Заряд"
}
}
val BleInfo.Type?.localized: String
get() {
return when(this){
BleInfo.Type.HOST -> "Хост"
BleInfo.Type.BEACON -> "Маяк"
BleInfo.Type.THERMOMETER -> "Термодатчик"
BleInfo.Type.ACCELEROMETER -> "Акселерометр"
null -> "Все"
}
}
val RealtimeViewMode.localized: String
get() {
return when(this){
is RealtimeViewMode.Accel -> this.accelViewMode.localized
RealtimeViewMode.Spectre -> "Спектр"
}
}
val FftFrequency.localized: String
get() {
return when(this){
FftFrequency.OFF -> "откл"
FftFrequency.F_1 -> "1 Гц"
FftFrequency.F_10 -> "10 Гц"
FftFrequency.F_25 -> "25 Гц"
FftFrequency.F_50 -> "50 Гц"
FftFrequency.F_100 -> "100 Гц"
FftFrequency.F_200 -> "200 Гц"
FftFrequency.F_400 -> "400 Гц"
FftFrequency.F_1620 -> "1620 Гц"
FftFrequency.F_1344 -> "1344 Гц"
}
}
val FftAxis.localized: String
get() {
return when(this){
FftAxis.AUTO -> "Авто"
FftAxis.X -> "Ось X"
FftAxis.Y -> "Ось Y"
FftAxis.Z -> "Ось Z"
}
}
val FftViewMode.localized: String
get() {
return when(this){
FftViewMode.SPECTRE -> "Спектр"
FftViewMode.X -> "Ось X"
FftViewMode.Y -> "Ось Y"
FftViewMode.Z -> "Ось Z"
}
}
val AccelScale.localized: String
get() {
return when(this){
AccelScale.S_2 -> "2g"
AccelScale.S_4 -> "4g"
AccelScale.S_8 -> "8g"
AccelScale.S_16 -> "16g"
}
}
val AccelViewMode.localized: String
get() {
return when(this){
ACCELERATION -> "Ускорение"
PEAK_ACCELERATION -> "Пиковое ускорение"
RMS -> "Среднеквадратичное ускорение"
VIBRATION -> "Вибрация"
ANGLE -> "Угол"
ROTATIONS -> "Обороты"
}
}
val BleInfo.Type?.icon: ImageVector
get() {
return when(this){
BleInfo.Type.BEACON -> Icons.Rounded.Nfc
BleInfo.Type.THERMOMETER -> Icons.Rounded.Thermostat
BleInfo.Type.ACCELEROMETER -> Icons.Rounded.Speed
BleInfo.Type.HOST -> Icons.Rounded.Info
else -> Icons.Rounded.Warning
}
}

View File

@ -1,5 +1,8 @@
package llc.arma.ble.app.ui.screen.main
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.window.DialogProperties
import androidx.navigation.compose.NavHost
@ -17,6 +20,7 @@ import llc.arma.ble.app.ui.screen.rotation.delete.RotationDeleteScreen
import llc.arma.ble.app.ui.screen.rotation.statistic.RotationStatisticContract
import llc.arma.ble.app.ui.screen.rotation.statistic.RotationStatisticScreen
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen() {

View File

@ -1,15 +1,12 @@
package llc.arma.ble.app.ui.screen.password
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
@ -27,7 +24,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
@ -38,6 +34,8 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
import llc.arma.ble.app.ui.screen.password.view.Loading
import llc.arma.ble.app.ui.screen.password.view.Result
@ -88,9 +86,7 @@ fun ChangePasswordScreen(
ChangePasswordContract.State.LoadingState.Failure,
ChangePasswordContract.State.LoadingState.Success -> {
Result(
onEvent = {
viewModel.setEvent(it)
},
onEvent = viewModel::setEvent,
state = state.loading
)
}
@ -213,66 +209,16 @@ fun ChangePasswordScreen(
Spacer(modifier = Modifier.height(20.dp))
Box(
modifier = Modifier
PrimaryButton(
label = "Применить"
) {
Surface(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
viewModel.setEvent(ChangePasswordContract.Event.OnChange)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimaryContainer,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
)
}
}
viewModel.setEvent(ChangePasswordContract.Event.OnChange)
}
Spacer(modifier = Modifier.height(12.dp))
Box(
modifier = Modifier
SecondaryButton(
label = "Отменить"
) {
Surface(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
viewModel.setEvent(ChangePasswordContract.Event.OnNavigateUp)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
}
viewModel.setEvent(ChangePasswordContract.Event.OnNavigateUp)
}
}

View File

@ -1,14 +1,11 @@
package llc.arma.ble.app.ui.screen.password.view
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Visibility
@ -16,7 +13,6 @@ import androidx.compose.material.icons.rounded.VisibilityOff
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
@ -24,13 +20,14 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
import llc.arma.ble.app.ui.screen.password.ChangePasswordContract
@Composable
@ -91,7 +88,7 @@ fun Display(
Text(text = "Пароль")
},
supportingText = {
Row() {
Row {
Spacer(modifier = Modifier.weight(1f))
Text(
@ -154,66 +151,18 @@ fun Display(
Spacer(modifier = Modifier.height(20.dp))
Box(
modifier = Modifier
PrimaryButton(
label = "Применить"
) {
Surface(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(ChangePasswordContract.Event.OnChange)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimaryContainer,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
)
}
}
onEvent(ChangePasswordContract.Event.OnChange)
}
Spacer(modifier = Modifier.height(12.dp))
Box(
modifier = Modifier
SecondaryButton(
label = "Отменить"
) {
Surface(
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(ChangePasswordContract.Event.OnNavigateUp)
}
) {
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
}
onEvent(ChangePasswordContract.Event.OnNavigateUp)
}
}

View File

@ -57,8 +57,9 @@ fun BleTheme(
?: throw Exception("Not in an activity - unable to get Window reference")
SideEffect {
currentWindow.statusBarColor = LightColorScheme.primary.copy(alpha = 0f).toArgb()
currentWindow.statusBarColor = Color.Transparent.toArgb()
WindowCompat.getInsetsController(currentWindow, view).isAppearanceLightStatusBars = true
WindowCompat.getInsetsController(currentWindow, view).isAppearanceLightNavigationBars = true
}
}

View File

@ -1,8 +1,10 @@
package llc.arma.ble.data.repository
import android.Manifest
import android.app.Application
import android.os.SystemClock
import android.util.Log
import androidx.annotation.RequiresPermission
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
@ -52,6 +54,9 @@ import kotlin.math.PI
import kotlin.math.atan
val versionServiceUUID: UUID = UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb")
val firmwareVersionUUID: UUID = UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb")
val serviceUUID: UUID = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002")
val accelerometerReadUUID: UUID = UUID.fromString("00002713-0000-1000-8000-00805f9b34fb")
@ -101,7 +106,6 @@ class BleRepositoryImpl @Inject constructor(
resultList[it.device.address] = it.info
}.launchIn(CoroutineScope(Dispatchers.IO))
val timer = Timer().apply {
schedule(object : TimerTask() {
override fun run() {
@ -129,6 +133,7 @@ class BleRepositoryImpl @Inject constructor(
}
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
override suspend fun getBleBySerial(
serial: String
): Result<Flow<Ble>, BleException> {
@ -141,244 +146,221 @@ class BleRepositoryImpl @Inject constructor(
} else {
fun BleInfo.updateBleInfo(): BleInfo {
return copy(
rssi = if((SystemClock.elapsedRealtime() - scanTime) > 15_000) {
null
} else { rssi }
)
}
val connection = ClientBleGatt.connect(app, serial, CoroutineScope(Dispatchers.IO))
fun BleInfo.updateState(): Ble.BleState {
return Ble.BleState(
tx = Ble.BleState.TX.fromByte(tx.toByte())
?: Ble.BleState.TX.ZERO
)
}
try {
val firstResult = when(initialBle.type){
BleInfo.Type.HOST -> {
val tState = readHostState(
initialBle.serial
).fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
Ble.Host(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
hostState = tState
)
}
BleInfo.Type.BEACON -> {
Ble.Beacon(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
fun BleInfo.updateBleInfo(): BleInfo {
return copy(
rssi = if ((SystemClock.elapsedRealtime() - scanTime) > 15_000) {
null
} else {
rssi
}
)
}
BleInfo.Type.THERMOMETER -> {
val tState = readThermometerState(
initialBle.serial,
initialBle.tableStatus
).fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
val version = connection.readVersion()
fun BleInfo.updateState(): Ble.BleState {
return Ble.BleState(
tx = Ble.BleState.TX.fromByte(tx.toByte())
?: Ble.BleState.TX.ZERO,
version = version
)
Ble.Thermometer(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
thermometerState = tState
)
}
BleInfo.Type.ACCELEROMETER -> {
val tState = readAccelState(
initialBle.serial,
initialBle.tableStatus
).fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
val firstResult =
when (initialBle.type) {
BleInfo.Type.HOST -> {
Ble.Accelerometer(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
accelerometerState = tState
)
val tState = connection.readHostState().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
}
}
Result.success(
flow {
while (true){
resultList[serial]?.let { ble ->
firstResult.state = ble.updateState()
firstResult.info = ble.updateBleInfo()
emit(when(firstResult){
is Ble.Accelerometer -> {
Ble.Accelerometer(
info = ble.updateBleInfo(),
state = ble.updateState(),
accelerometerState = firstResult.accelerometerState
)
}
is Ble.Beacon -> {
Ble.Beacon(
info = ble.updateBleInfo(),
state = ble.updateState()
)
}
is Ble.Host -> {
Ble.Host(
info = ble.updateBleInfo(),
state = ble.updateState(),
hostState = firstResult.hostState
)
}
is Ble.Thermometer -> {
Ble.Thermometer(
info = ble.updateBleInfo(),
state = ble.updateState(),
thermometerState = firstResult.thermometerState
)
}
})
Ble.Host(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
hostState = tState
)
}
delay(1_000)
BleInfo.Type.BEACON -> {
Ble.Beacon(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
)
}
BleInfo.Type.THERMOMETER -> {
val tState = connection.readThermometerState(
initialBle.tableStatus
).fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
Ble.Thermometer(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
thermometerState = tState
)
}
BleInfo.Type.ACCELEROMETER -> {
val tState = connection.readAccelState(
initialBle.tableStatus,
version
).fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
Ble.Accelerometer(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
accelerometerState = tState
)
}
}
}
)
Result.success(
flow {
while (true) {
resultList[serial]?.let { ble ->
firstResult.state = ble.updateState()
firstResult.info = ble.updateBleInfo()
emit(
when (firstResult) {
is Ble.Accelerometer -> {
Ble.Accelerometer(
info = ble.updateBleInfo(),
state = ble.updateState(),
accelerometerState = firstResult.accelerometerState
)
}
is Ble.Beacon -> {
Ble.Beacon(
info = ble.updateBleInfo(),
state = ble.updateState()
)
}
is Ble.Host -> {
Ble.Host(
info = ble.updateBleInfo(),
state = ble.updateState(),
hostState = firstResult.hostState
)
}
is Ble.Thermometer -> {
Ble.Thermometer(
info = ble.updateBleInfo(),
state = ble.updateState(),
thermometerState = firstResult.thermometerState
)
}
}
)
}
delay(1_000)
}
}
)
} catch (err: Throwable) {
err.printStackTrace()
return Result.failure(BleException.UnexpectedResponse)
} finally {
connection.close()
}
}
}
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
@OptIn(ExperimentalUnsignedTypes::class)
private suspend fun readThermometerState(
address: String,
private suspend fun ClientBleGatt.readThermometerState(
timer: BleInfo.HistoryTableStatus
): Result<Ble.Thermometer.ThermometerState, BleException> {
return if(app.checkPermission()) {
val service = discoverServices().findService(serviceUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val connection =
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.IO))
var characteristic = service.findCharacteristic(temperatureReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
try {
characteristic.write(DataByteArray.from(1, 1))
val service = connection.discoverServices().findService(serviceUUID)
?: return Result.failure(BleException.UnexpectedResponse)
delay(2_000)
var characteristic = service.findCharacteristic(temperatureReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val temperature = characteristic.read().value.toUByteArray().toTemperature()
characteristic.write(DataByteArray.from(1, 1))
characteristic = service.findCharacteristic(intervalReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
delay(2_000)
val interval = characteristic.readWriteInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
val temperature = characteristic.read().value.toUByteArray().toTemperature()
characteristic = service.findCharacteristic(intervalReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val interval = characteristic.readWriteInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
connection.close()
return Result.success(
Ble.Thermometer.ThermometerState(
temperature = temperature,
saveHistory = timer !== BleInfo.HistoryTableStatus.DISABLED,
historyInterval = interval
)
)
} catch (err: Throwable){
err.printStackTrace()
return Result.failure(BleException.UnexpectedResponse)
} finally {
connection.close()
}
} else {
Result.failure(BleException.PermissionDenied)
}
return Result.success(
Ble.Thermometer.ThermometerState(
temperature = temperature,
saveHistory = timer !== BleInfo.HistoryTableStatus.DISABLED,
historyInterval = interval
)
)
}
private suspend fun readHostState(
address: String
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
private suspend fun ClientBleGatt.readHostState(
): Result<Ble.Host.HostState, BleException> {
return if(app.checkPermission()) {
val service = discoverServices().findService(serviceUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val connection =
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.IO))
val characteristic = service.findCharacteristic(intervalReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
try {
val interval = characteristic.readWriteInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
val service = connection.discoverServices().findService(serviceUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val readTimeout = characteristic.readTimeoutInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
val characteristic = service.findCharacteristic(intervalReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val interval = characteristic.readWriteInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
//characteristic.write(DataByteArray.from(2, 0, 0, 0, 0))
//val readTimeout = characteristic.read().value.let {
// if(it.size == 4){
// it.get4byteUIntAt(0).toLong()
// } else {
// 0
// }
//}
return Result.success(
Ble.Host.HostState(
historyInterval = interval,
readInterval = interval
)
)
} catch (err: Throwable){
err.printStackTrace()
return Result.failure(BleException.UnexpectedResponse)
} finally {
connection.close()
}
} else {
Result.failure(BleException.PermissionDenied)
}
return Result.success(
Ble.Host.HostState(
historyInterval = interval,
readInterval = readTimeout
)
)
}
@ -394,6 +376,32 @@ class BleRepositoryImpl @Inject constructor(
write(DataByteArray.from(3, 0, 0, 0))
val readTimeout = read().value.let {
if(it.size == 4){
it.get4byteUIntAt(0).toLong()
} else {
0
}
}
Result.success(readTimeout)
}
}
private suspend fun ClientBleGattCharacteristic.readTimeoutInterval(
): Result<Long, BleException> {
return if(app.checkPermission().not()) {
Result.failure(BleException.PermissionDenied)