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()
}
}
}
}
)
)
}
}
@ -243,22 +265,3 @@ 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)
} else {
write(DataByteArray.from(8, 0, 0, 0))
val interval = read().value.let {
if (it.size == 4) {
it.get4byteUIntAt(0).toLong()
@ -408,79 +416,137 @@ class BleRepositoryImpl @Inject constructor(
}
private suspend fun readAccelState(
address: String,
timer: BleInfo.HistoryTableStatus
): Result<Ble.Accelerometer.AccelerometerState, BleException> {
data class Version(
val major: Int,
val minor: Int,
val patch: Int,
val release: Int
): Comparable<Version> {
return if(app.checkPermission()) {
companion object {
val connection =
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.IO))
fun fromString(
version: String
): Version {
try {
val splitArray = version.split('.', '-')
val service = connection.discoverServices()
.findService(serviceUUID) ?: return Result.failure(BleException.UnexpectedResponse)
var characteristic = service.findCharacteristic(intervalReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val interval = characteristic.readWriteInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
return Version(
major = splitArray[0].toInt(),
minor = splitArray[1].toInt(),
patch = splitArray[2].toInt(),
release = splitArray.last().toInt()
)
val historySettingsParams = when(timer){
BleInfo.HistoryTableStatus.EMPTY,
BleInfo.HistoryTableStatus.NOT_EMPTY -> {
characteristic = service.findCharacteristic(accelerometerReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
characteristic.write(DataByteArray.from(4))
characteristic.read().let {
val data = it.value
val scale = AccelScale.fromByte(data[1]) ?: return Result.failure(BleException.UnexpectedResponse)
val mode = AccelViewMode.fromByte(data[0]) ?: return Result.failure(BleException.UnexpectedResponse)
Ble.Accelerometer.HistorySettings.Enabled(
scale = scale,
mode = mode,
detailed = false
)
}
}
BleInfo.HistoryTableStatus.DISABLED -> Ble.Accelerometer.HistorySettings.Disabled
}
connection.close()
return Result.success(
Ble.Accelerometer.AccelerometerState(
saveHistorySettings = historySettingsParams,
historyInterval = interval
)
)
} catch (err: Throwable){
return Result.failure(BleException.UnexpectedResponse)
} finally {
connection.close()
}
} else {
}
Result.failure(BleException.PermissionDenied)
override fun compareTo(
other: Version
): Int {
if(major != other.major){
return major - other.major
}
if(minor != other.minor){
return minor - other.minor
}
if(patch != other.patch){
return patch - other.patch
}
if(release != other.release){
return release - other.release
}
return 0
}
override fun toString(): String {
return "$major.$minor.$patch-$release"
}
}
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
private suspend fun ClientBleGatt.readVersion(): Version {
return discoverServices().findService(versionServiceUUID)
?.findCharacteristic(firmwareVersionUUID)?.read()?.value?.decodeToString()?.let {
Version.fromString(it)
} ?: Version.fromString("0.0.0-0")
}
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
private suspend fun ClientBleGatt.readAccelState(
timer: BleInfo.HistoryTableStatus,
version: Version
): Result<Ble.Accelerometer.AccelerometerState, BleException> {
val services = discoverServices()
val service = services.findService(serviceUUID)
?: return Result.failure(BleException.UnexpectedResponse)
var characteristic = service.findCharacteristic(intervalReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val interval = characteristic.readWriteInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
val readTimeout = if(version > Version.fromString("0.0.0-0")) {
characteristic.readTimeoutInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
} else {
0
}
val historySettingsParams = when (timer) {
BleInfo.HistoryTableStatus.EMPTY,
BleInfo.HistoryTableStatus.NOT_EMPTY -> {
characteristic = service.findCharacteristic(accelerometerReadUUID)
?: return Result.failure(BleException.UnexpectedResponse)
characteristic.write(DataByteArray.from(4))
characteristic.read().let {
val data = it.value
val scale = AccelScale.fromByte(data[1]) ?: return Result.failure(
BleException.UnexpectedResponse
)
val mode = AccelViewMode.fromByte(data[0]) ?: return Result.failure(
BleException.UnexpectedResponse
)
Ble.Accelerometer.HistorySettings.Enabled(
scale = scale,
mode = mode,
detailed = false
)
}
}
BleInfo.HistoryTableStatus.DISABLED -> Ble.Accelerometer.HistorySettings.Disabled
}
return Result.success(
Ble.Accelerometer.AccelerometerState(
saveHistorySettings = historySettingsParams,
historyInterval = interval,
readInterval = readTimeout
)
)
}
override suspend fun getAccelerometerSpectreBySerial(
@ -535,11 +601,6 @@ class BleRepositoryImpl @Inject constructor(
request: Ble.Thermometer.WriteRequest
): Result<Unit, BleException> {
fun UInt.to4ByteArrayInLittleEndian(): ByteArray =
(3 downTo 0).map {
(this shr (it * Byte.SIZE_BITS)).toByte()
}.toByteArray()
return if(app.checkPermission()) {
val connection =
@ -796,6 +857,20 @@ class BleRepositoryImpl @Inject constructor(
}
request.readInterval?.let {
service.findCharacteristic(intervalWriteUUID)!!.write(
DataByteArray.from(
*mutableListOf<Byte>(2).apply {
addAll(
(it).toUInt().to4ByteArrayInLittleEndian().reversed().toList()
)
}.toByteArray()
)
)
}
service.findCharacteristic(flashWriteUUID)!!.write(
DataByteArray.from(9)
)

View File

@ -82,7 +82,7 @@ fun getAccelerometerHistory(
0.toByte(),
0.toByte()
).apply {
addAll(value.toList())
addAll(value.toList().take(2))
}.toByteArray()
characteristic.write(DataByteArray(writeData))
@ -155,18 +155,20 @@ fun getAccelerometerHistory(
AccelViewMode.RMS -> {
resultPackage.chunked(3).withIndex().map {
Ble.Accelerometer.HistoryPoint.Angle(
date = lastMeasureSystemTime!! - (((resultPackage.size - 1) - it.index) * bleMeasureInterval!!),
date = lastMeasureSystemTime!! - (((resultPackage.size / 3 - 1) - it.index) * bleMeasureInterval!!),
x = (it.value[0] * scale.k) / Short.MAX_VALUE,
y = (it.value[1] * scale.k) / Short.MAX_VALUE,
z = (it.value[2] * scale.k) / Short.MAX_VALUE
)
}.apply {
Log.d("dataTable", "start with ${last().date}")
}
}
AccelViewMode.ANGLE -> {
resultPackage.chunked(3).withIndex().map {
Ble.Accelerometer.HistoryPoint.Angle(
date = lastMeasureSystemTime!! - (((resultPackage.size - 1) - it.index) * bleMeasureInterval!!),
date = lastMeasureSystemTime!! - (((resultPackage.size / 3 - 1) - it.index) * bleMeasureInterval!!),
x = calculateAngle(
it.value[2],
it.value[1]

View File

@ -1,12 +1,8 @@
package llc.arma.ble.data.repository
import android.Manifest
import android.annotation.SuppressLint
import android.app.Application
import android.content.pm.PackageManager
import android.util.Log
import androidx.annotation.RequiresPermission
import androidx.core.app.ActivityCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay

View File

@ -56,7 +56,7 @@ fun readThermometerHistory(
} else {
var nextPackageDataCount = value.get2byteUIntAt(2)
var nextPackageDataCount = value.get2byteUIntAt(0)
val writeData = mutableListOf(
1.toByte(),

View File

@ -3,13 +3,7 @@ package llc.arma.ble.data.repository
import android.app.Application
import android.icu.text.SimpleDateFormat
import android.os.Environment
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer
import llc.arma.ble.R
import llc.arma.ble.app.ui.screen.inspection.host.view.HostEntry
import llc.arma.ble.app.ui.screen.inspection.host.view.colorsStack
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.repository.XlsxRepository
import org.apache.poi.ss.usermodel.WorkbookFactory

View File

@ -29,8 +29,19 @@ val BleScanResult.info: BleInfo
val BleScanResult.batteryLevel: Int?
get() {
return data?.scanRecord?.manufacturerSpecificData?.get(89)?.getByte(1)
val level = data?.scanRecord?.manufacturerSpecificData?.get(89)?.getByte(1)
?.toUByte()?.toInt()
if(data?.scanRecord?.deviceName?.contains("N00051023") == true){
println(level)
println(data?.scanRecord?.manufacturerSpecificData?.get(89))
}
return level
}
val BleScanResult.type: BleInfo.Type

View File

@ -1,5 +1,6 @@
package llc.arma.ble.domain.model
import llc.arma.ble.data.repository.BleRepositoryImpl
import llc.arma.ble.domain.usecase.AccelScale
import llc.arma.ble.domain.usecase.AccelViewMode
@ -29,7 +30,8 @@ sealed class Ble(
data class WriteRequest(
val tx: BleState.TX?,
val saveHistorySettings: HistorySettings?,
val historyInterval: Long?
val historyInterval: Long?,
val readInterval: Long?,
)
sealed class HistoryPoint {
@ -93,7 +95,8 @@ sealed class Ble(
data class AccelerometerState(
val saveHistorySettings: HistorySettings,
val historyInterval: Long
val historyInterval: Long,
val readInterval: Long
)
}
@ -160,7 +163,8 @@ sealed class Ble(
}
data class BleState(
val tx: TX
val tx: TX,
val version: BleRepositoryImpl.Version
){
enum class TX {

View File

@ -2,6 +2,7 @@ package llc.arma.ble.domain.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import llc.arma.ble.data.repository.BleRepositoryImpl
@Parcelize
data class BleInfo(

View File

@ -16,9 +16,9 @@ class GetBleBySerial @Inject constructor(
sealed class GetBleException {
object TimeOut : GetBleException()
data object TimeOut : GetBleException()
object BlePermissionDenied : GetBleException()
data object BlePermissionDenied : GetBleException()
}

View File

@ -14,8 +14,8 @@ buildscript {
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '8.1.1' apply false
id 'com.android.library' version '8.1.1' apply false
id 'com.android.application' version '8.8.1' apply false
id 'com.android.library' version '8.8.1' apply false
id 'org.jetbrains.kotlin.android' version '1.9.22' apply false
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.22'
id("androidx.room") version "2.6.1" apply false

View File

@ -22,5 +22,5 @@ kotlin.code.style=official
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false
android.nonFinalResIds=true
org.gradle.unsafe.configuration-cache=true

Binary file not shown.

View File

@ -1,6 +1,7 @@
#Mon Mar 20 11:20:29 KRAT 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

297
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -15,69 +15,104 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

37
gradlew.bat vendored
View File

@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal