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"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" /> <bytecodeTargetLevel target="21" />
</component> </component>
</project> </project>

View File

@ -4,10 +4,10 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <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"> <Target type="DEFAULT_BOOT">
<handle> <handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=55381e0a" /> <DeviceId pluginId="PhysicalDevice" identifier="serial=BV5900DNS00004122" />
</handle> </handle>
</Target> </Target>
</DropdownSelection> </DropdownSelection>

View File

@ -1,6 +1,6 @@
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <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" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View File

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

View File

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

View File

@ -15,14 +15,17 @@ import android.view.SurfaceView
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.size 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.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ExperimentalMaterialApi
@ -43,6 +46,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
@ -99,140 +103,158 @@ class MainActivity : ComponentActivity() {
) )
) { ) {
ModalBottomSheetLayout( BoxWithConstraints {
sheetShape = RoundedCornerShape(
topStart = 25.dp,
topEnd = 25.dp
),
sheetElevation = 0.dp,
sheetState = modalState,
sheetContent = {
val scope = rememberCoroutineScope() val maxHeight = with(LocalDensity.current) {
this@BoxWithConstraints.constraints.maxHeight.toDp()
}
Column( ModalBottomSheetLayout(
horizontalAlignment = Alignment.CenterHorizontally modifier = Modifier,
) { sheetShape = RoundedCornerShape(
topStart = 25.dp,
topEnd = 25.dp
),
sheetElevation = 0.dp,
sheetState = modalState,
sheetContent = {
Surface( val statusBarHeight = with(LocalDensity.current) {
modifier = Modifier.fillMaxWidth() WindowInsets.statusBars.getTop(this).toDp()
}
val scope = rememberCoroutineScope()
Column(
modifier = Modifier.heightIn(max = maxHeight - statusBarHeight),
horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Column( Surface(
modifier = Modifier.statusBarsPadding().navigationBarsPadding() modifier = Modifier.fillMaxWidth()
) { ) {
Spacer(modifier = Modifier.height(14.dp)) Column(
modifier = Modifier.navigationBarsPadding()
) {
Surface( Spacer(modifier = Modifier.height(14.dp))
shape = CircleShape,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f),
modifier = Modifier
.align(Alignment.CenterHorizontally)
.size(
width = 54.dp,
height = 5.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) { BackHandler(modalState.isVisible) {
scope.launch { modalState.hide() } scope.launch { modalState.hide() }
} }
}, },
content = { content = {
Surface( Surface(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.navigationBarsPadding(), .navigationBarsPadding(),
color = MaterialTheme.colorScheme.background 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( rememberMultiplePermissionsState(
listOf( listOf(
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.READ_MEDIA_VIDEO,
Manifest.permission.READ_MEDIA_IMAGES,
Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_CONNECT Manifest.permission.BLUETOOTH_CONNECT
) )
) )
} else { } else {
rememberMultiplePermissionsState( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
listOf( rememberMultiplePermissionsState(
Manifest.permission.WRITE_EXTERNAL_STORAGE, listOf(
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.ACCESS_COARSE_LOCATION 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 { val lifecycleOwner = LocalLifecycleOwner.current
mutableStateOf(mBluetoothAdapter.isEnabled) val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState()
}
val lifecycleOwner = LocalLifecycleOwner.current LaunchedEffect(lifecycleState) {
val lifecycleState by lifecycleOwner.lifecycle.currentStateFlow.collectAsState() bleEnabled = mBluetoothAdapter.isEnabled
}
LaunchedEffect(lifecycleState){ if (multiplePermissionsState.allPermissionsGranted) {
bleEnabled = mBluetoothAdapter.isEnabled
}
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 { } else {
val context = LocalContext.current LaunchedEffect(multiplePermissionsState) {
multiplePermissionsState.launchMultiplePermissionRequest()
LaunchedEffect(mBluetoothAdapter.isEnabled){
val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
(context as Activity).startActivityForResult(intent, 1)
} }
}
} 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( BleView.Beacon(
info = input.info, info = input.info,
state = BleView.BleState( 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( BleView.Thermometer(
info = input.info, info = input.info,
state = BleView.BleState( state = BleView.BleState(
tx = txMapper.map(input.state.tx) tx = txMapper.map(input.state.tx),
version = input.state.version
), ),
thermometerState = BleView.Thermometer.ThermometerState( thermometerState = BleView.Thermometer.ThermometerState(
temperature = BleView.Thermometer.ThermometerState.TemperatureState(input.thermometerState.temperature, false), temperature = BleView.Thermometer.ThermometerState.TemperatureState(input.thermometerState.temperature, false),
@ -36,11 +38,13 @@ class BleMapper @Inject constructor(
BleView.Accelerometer( BleView.Accelerometer(
info = input.info, info = input.info,
state = BleView.BleState( state = BleView.BleState(
tx = txMapper.map(input.state.tx) tx = txMapper.map(input.state.tx),
version = input.state.version
), ),
accelerometerState = BleView.Accelerometer.AccelerometerState( accelerometerState = BleView.Accelerometer.AccelerometerState(
saveHistorySettings = input.accelerometerState.saveHistorySettings, 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( BleView.Host(
info = input.info, info = input.info,
state = BleView.BleState( state = BleView.BleState(
tx = txMapper.map(input.state.tx) tx = txMapper.map(input.state.tx),
version = input.state.version
), ),
hostState = BleView.Host.HostState( hostState = BleView.Host.HostState(
historyInterval = input.hostState.historyInterval, historyInterval = input.hostState.historyInterval,

View File

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

View File

@ -4,6 +4,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue 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.Ble
import llc.arma.ble.domain.model.BleInfo import llc.arma.ble.domain.model.BleInfo
@ -20,10 +21,11 @@ sealed class BleView(
class AccelerometerState( class AccelerometerState(
saveHistorySettings: Ble.Accelerometer.HistorySettings, saveHistorySettings: Ble.Accelerometer.HistorySettings,
historyInterval: Long, historyInterval: Long,
readInterval: Long
) { ) {
var saveHistory by mutableStateOf(saveHistorySettings) 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 temperature by mutableStateOf(temperature)
var saveHistory by mutableStateOf(saveHistory) var saveHistory by mutableStateOf(saveHistory)
var historyInterval by mutableStateOf(historyInterval) var historyInterval by mutableLongStateOf(historyInterval)
} }
@ -75,7 +77,8 @@ sealed class BleView(
} }
class BleState( class BleState(
tx: TX tx: TX,
val version: BleRepositoryImpl.Version
){ ){
var tx by mutableStateOf(tx) 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.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize 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.BatteryFull
import androidx.compose.material.icons.rounded.Key import androidx.compose.material.icons.rounded.Key
import androidx.compose.material.icons.rounded.NetworkCell import androidx.compose.material.icons.rounded.NetworkCell
import androidx.compose.material.icons.rounded.ShortText import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Divider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
@ -26,13 +24,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import llc.arma.ble.app.ui.screen.ble.icon import llc.arma.ble.app.ui.screen.locale.icon
import llc.arma.ble.app.ui.screen.ble.localized import llc.arma.ble.app.ui.screen.locale.localized
import llc.arma.ble.data.repository.BleRepositoryImpl
import llc.arma.ble.domain.model.BleInfo import llc.arma.ble.domain.model.BleInfo
@Composable @Composable
fun BleInfoView( fun BleInfoView(
bleInfo: BleInfo bleInfo: BleInfo,
version: BleRepositoryImpl.Version
) { ) {
Surface( Surface(
@ -45,7 +45,7 @@ fun BleInfoView(
modifier = Modifier.padding(8.dp) modifier = Modifier.padding(8.dp)
) { ) {
Column() { Column {
BleInfoItem( BleInfoItem(
icon = { icon = {
@ -54,21 +54,8 @@ fun BleInfoView(
contentDescription = null contentDescription = null
) )
}, },
title = "Тип метки", title = bleInfo.name,
subtitle = bleInfo.type.localized subtitle = "${bleInfo.type.localized} v${version}"
)
SpecDivider()
BleInfoItem(
icon = {
Icon(
imageVector = Icons.Rounded.ShortText,
contentDescription = null
)
},
title = "Наименование",
subtitle = bleInfo.name
) )
SpecDivider() SpecDivider()
@ -119,13 +106,13 @@ fun BleInfoView(
} }
@Composable @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.ViewEvent
import llc.arma.ble.app.ui.common.ViewSideEffect import llc.arma.ble.app.ui.common.ViewSideEffect
import llc.arma.ble.app.ui.common.ViewState 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.BleInfo
import llc.arma.ble.domain.model.ConnectedBleInfo import llc.arma.ble.domain.model.ConnectedBleInfo
import llc.arma.ble.domain.model.BleFilter
class BleListContract { class BleListContract {

View File

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

View File

@ -1,31 +1,23 @@
package llc.arma.ble.app.ui.screen.ble package llc.arma.ble.app.ui.screen.ble
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.BatteryFull import androidx.compose.material.icons.rounded.BatteryFull
import androidx.compose.material.icons.rounded.Bluetooth import androidx.compose.material.icons.rounded.Bluetooth
import androidx.compose.material.icons.rounded.Close 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.Search
import androidx.compose.material.icons.rounded.ShortText import androidx.compose.material.icons.rounded.ShortText
import androidx.compose.material.icons.rounded.SignalCellularAlt import androidx.compose.material.icons.rounded.SignalCellularAlt
import androidx.compose.material.icons.rounded.Sort import androidx.compose.material.icons.rounded.Sort
import androidx.compose.material.icons.rounded.SortByAlpha 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.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuBox
@ -36,7 +28,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.RangeSlider import androidx.compose.material3.RangeSlider
import androidx.compose.material3.SliderDefaults import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -45,52 +36,13 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp 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.BleFilter
import llc.arma.ble.domain.model.BleInfo 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) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun Filter( fun Filter(
@ -98,9 +50,7 @@ fun Filter(
onEvent: (BleListContract.Event) -> Unit onEvent: (BleListContract.Event) -> Unit
) { ) {
Column( Column {
) {
Text( Text(
modifier = Modifier.padding(horizontal = 12.dp), modifier = Modifier.padding(horizontal = 12.dp),
@ -112,6 +62,7 @@ fun Filter(
Column( Column(
modifier = Modifier modifier = Modifier
.weight(1f)
.padding(horizontal = 12.dp) .padding(horizontal = 12.dp)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
@ -500,71 +451,20 @@ fun Filter(
} }
Spacer(modifier = Modifier.height(20.dp)) }
Box( Spacer(modifier = Modifier.height(8.dp))
modifier = Modifier
) {
Surface( PrimaryButton(
modifier = Modifier label = "Применить"
.fillMaxWidth() ) {
.height(50.dp), onEvent(BleListContract.Event.OnHideFilter)
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))
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.fadeOut
import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.animation.with import androidx.compose.animation.with
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons 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.ArrowBack
import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
@ -41,6 +41,7 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach 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.AccelerometerScreen
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerHistory import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerHistory
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelerometerRealtime 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.app.ui.screen.inspection.thermometer.ThermometerScreen
import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.model.Ble
@OptIn(ExperimentalMaterial3Api::class, ExperimentalAnimationApi::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun ConnectionScreen( fun ConnectionScreen(
onNavigationEvent: (ConnectionContract.Effect.Navigation) -> Unit onNavigationEvent: (ConnectionContract.Effect.Navigation) -> Unit
@ -97,7 +98,7 @@ fun ConnectionScreen(
}, },
content = { content = {
Icon( Icon(
imageVector = Icons.Rounded.ArrowBack, imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null contentDescription = null
) )
} }
@ -112,8 +113,8 @@ fun ConnectionScreen(
is ConnectionContract.State.Loading -> "Соединение.." is ConnectionContract.State.Loading -> "Соединение.."
}, },
transitionSpec = { transitionSpec = {
(slideInVertically { height -> height } + fadeIn() with ((slideInVertically { height -> height } + fadeIn()).togetherWith(
slideOutVertically { height -> -height } + fadeOut()).using( slideOutVertically { height -> -height } + fadeOut())).using(
SizeTransform(clip = false) SizeTransform(clip = false)
) )
} }
@ -149,18 +150,16 @@ fun ConnectionScreen(
is Ble.Thermometer -> { is Ble.Thermometer -> {
Column(modifier = Modifier.weight(1f)) { ThermometerScreen(
ble = state.ble,
ThermometerScreen( onNavigationEvent = {
ble = state.ble, viewModel.setEvent(
onNavigationEvent = { ConnectionContract.Event.OnThermometerNavigationEvent(
viewModel.setEvent( it
ConnectionContract.Event.OnThermometerNavigationEvent(it)
) )
} )
) }
)
}
} }
@ -313,27 +312,10 @@ private fun DisplayException(
Spacer(modifier = Modifier.height(18.dp)) Spacer(modifier = Modifier.height(18.dp))
Surface( SmallPrimaryButton(
modifier = Modifier label = "Повторить"
.height(42.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(ConnectionContract.Event.RefreshBle)
}
) { ) {
onEvent(ConnectionContract.Event.RefreshBle)
Box(modifier = Modifier.padding(horizontal = 16.dp)) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimaryContainer,
style = MaterialTheme.typography.labelLarge,
text = "Повторить"
)
}
} }
} }

View File

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

View File

@ -16,6 +16,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch 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.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelEdit import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.AccelFftAxisEdit 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.HistoryEdit
import llc.arma.ble.app.ui.screen.inspection.accelerometer.view.IntervalEdit 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.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.app.ui.screen.inspection.accelerometer.view.Write
import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.model.Ble
enum class SheetPage { 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) @OptIn(ExperimentalMaterialApi::class)
@ -60,7 +61,7 @@ fun AccelerometerScreen(
key1 = bottomDialog.sheetState?.currentValue, key1 = bottomDialog.sheetState?.currentValue,
block = { block = {
if(bottomDialog.sheetState?.currentValue == ModalBottomSheetValue.Hidden) { if(bottomDialog.sheetState?.currentValue == ModalBottomSheetValue.Hidden) {
bottomDialog.setContent({}) bottomDialog.setContent {}
sheetPage = null sheetPage = null
} }
} }
@ -75,10 +76,10 @@ fun AccelerometerScreen(
val currentState = viewModel.viewState.value val currentState = viewModel.viewState.value
if(currentState is AccelerometerContract.State.Display) { if(currentState is AccelerometerContract.State.Display) {
PowerEdit( TxLevelSelector(
state = currentState.accelerometer, tx = currentState.accelerometer.state.tx,
onEvent = { onSelect = {
viewModel.setEvent(it) viewModel.setEvent(AccelerometerContract.Event.OnPowerChanged(it))
} }
) )
} }
@ -94,9 +95,7 @@ fun AccelerometerScreen(
Write( Write(
state = it, state = it,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -111,9 +110,7 @@ fun AccelerometerScreen(
AccelViewEdit( AccelViewEdit(
next = AccelerometerContract.Event.Next.ACCEL, next = AccelerometerContract.Event.Next.ACCEL,
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -126,9 +123,7 @@ fun AccelerometerScreen(
AccelViewEdit( AccelViewEdit(
next = AccelerometerContract.Event.Next.ACCEL, next = AccelerometerContract.Event.Next.ACCEL,
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -141,9 +136,7 @@ fun AccelerometerScreen(
AccelViewEdit( AccelViewEdit(
next = AccelerometerContract.Event.Next.HISTORY, next = AccelerometerContract.Event.Next.HISTORY,
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -155,9 +148,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) { if(currentState is AccelerometerContract.State.Display) {
AccelFrequencyEdit( AccelFrequencyEdit(
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -169,9 +160,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) { if(currentState is AccelerometerContract.State.Display) {
AccelFftAxisEdit( AccelFftAxisEdit(
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -183,9 +172,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) { if(currentState is AccelerometerContract.State.Display) {
AccelFftModeEdit( AccelFftModeEdit(
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -197,9 +184,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) { if(currentState is AccelerometerContract.State.Display) {
IntervalEdit( IntervalEdit(
state = currentState.accelerometer, state = currentState.accelerometer,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -212,9 +197,7 @@ fun AccelerometerScreen(
AccelScaleEdit( AccelScaleEdit(
next = AccelerometerContract.Event.Next.ACCEL, next = AccelerometerContract.Event.Next.ACCEL,
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -227,9 +210,7 @@ fun AccelerometerScreen(
AccelScaleEdit( AccelScaleEdit(
next = AccelerometerContract.Event.Next.ACCEL, next = AccelerometerContract.Event.Next.ACCEL,
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -242,9 +223,7 @@ fun AccelerometerScreen(
AccelScaleEdit( AccelScaleEdit(
next = AccelerometerContract.Event.Next.HISTORY, next = AccelerometerContract.Event.Next.HISTORY,
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -256,9 +235,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) { if(currentState is AccelerometerContract.State.Display) {
AccelEdit( AccelEdit(
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -270,9 +247,7 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) { if(currentState is AccelerometerContract.State.Display) {
HistoryEdit( HistoryEdit(
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -288,9 +263,20 @@ fun AccelerometerScreen(
if(currentState is AccelerometerContract.State.Display) { if(currentState is AccelerometerContract.State.Display) {
AccelRealtimeViewEdit( AccelRealtimeViewEdit(
state = currentState, state = currentState,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it) )
} }
}
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 sheetPage = null
delay(100) delay(100)
} }
AccelerometerContract.Effect.HideReadIntervalPicker -> {
sheetPage = null
delay(100)
}
AccelerometerContract.Effect.ShowReadIntervalPicker -> {
sheetPage = null
delay(100)
sheetPage = SheetPage.READ_INTERVAL_EDIT
}
} }
}.launchIn(this) }.launchIn(this)
} }
@ -406,9 +404,7 @@ fun AccelerometerScreen(
DisplayState( DisplayState(
origin = state.origin, origin = state.origin,
ble = state.accelerometer, ble = state.accelerometer,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
is AccelerometerContract.State.Loading -> LoadingState() 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.OnHistoryScaleChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnHistoryViewModeChanged -> reduce(viewState.value, event) is AccelerometerContract.Event.OnHistoryViewModeChanged -> reduce(viewState.value, event)
is AccelerometerContract.Event.OnHideHistoryEdit -> 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( private fun reduce(
state: AccelerometerContract.State, state: AccelerometerContract.State,
event: AccelerometerContract.Event.OnHideHistoryEdit 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, 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, 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, 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 { setState {
state.copy( 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.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer 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.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp 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.inspection.accelerometer.AccelerometerContract
import llc.arma.ble.domain.usecase.AccelScale import llc.arma.ble.app.ui.screen.locale.localized
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"
}
}
@Composable @Composable
fun AccelEdit( fun AccelEdit(
@ -313,29 +261,10 @@ fun AccelEdit(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Surface( PrimaryButton(
modifier = Modifier label = "Продолжить"
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnShowAccelerometerAccel)
}
) { ) {
onEvent(AccelerometerContract.Event.OnShowAccelerometerAccel)
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Продолжить"
)
}
} }
} }

View File

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

View File

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

View File

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

View File

@ -1,19 +1,15 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view package llc.arma.ble.app.ui.screen.inspection.accelerometer.view
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@ -24,17 +20,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp 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.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
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 { sealed class RealtimeViewMode {
@ -68,27 +57,13 @@ fun AccelRealtimeViewEdit(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
values().forEach { AccelViewMode.entries.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)
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)) Spacer(modifier = Modifier.height(16.dp))
Surface( PrimaryButton(
modifier = Modifier label = "Ок"
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(AccelerometerContract.Event.OnRealtimeViewModeChanged(value))
onEvent(AccelerometerContract.Event.OnAccelEdit)
}
) { ) {
onEvent(AccelerometerContract.Event.OnRealtimeViewModeChanged(value))
Box(modifier = Modifier.fillMaxSize()) { onEvent(AccelerometerContract.Event.OnAccelEdit)
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
} }
} }

View File

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

View File

@ -1,50 +1,22 @@
package llc.arma.ble.app.ui.screen.inspection.accelerometer.view 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.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer 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.height
import androidx.compose.foundation.layout.padding 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.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp 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.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
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 @Composable
fun AccelViewEdit( fun AccelViewEdit(
@ -69,66 +41,32 @@ fun AccelViewEdit(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
values().forEach { AccelViewMode.entries.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)
SelectorItem(
label = it.localized,
selected = it == value
){
value = it
} }
} }
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Surface( PrimaryButton(
modifier = Modifier label = "Ок"
.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)
}
}
}
) { ) {
Box(modifier = Modifier.fillMaxSize()) { when(next){
AccelerometerContract.Event.Next.ACCEL -> {
Text( onEvent(AccelerometerContract.Event.OnAccelViewModelChanged(value))
modifier = Modifier.align(Alignment.Center), onEvent(AccelerometerContract.Event.OnAccelEdit)
color = MaterialTheme.colorScheme.background, }
style = MaterialTheme.typography.labelLarge, AccelerometerContract.Event.Next.HISTORY -> {
text = "Ок" 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.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons 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.ArrowBack
import androidx.compose.material.icons.rounded.Refresh import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material3.CircularProgressIndicator 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.ViewEvent
import llc.arma.ble.app.ui.common.ViewSideEffect import llc.arma.ble.app.ui.common.ViewSideEffect
import llc.arma.ble.app.ui.common.ViewState 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.common.ProgressState
import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo import llc.arma.ble.domain.model.BleInfo
@ -112,7 +114,7 @@ fun AccelerometerSpectre(
IconButton(onClick = it) { IconButton(onClick = it) {
Icon( Icon(
imageVector = Icons.Rounded.ArrowBack, imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null contentDescription = null
) )
} }
@ -168,7 +170,7 @@ fun AccelerometerSpectre(
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
strokeWidth = 2.dp, strokeWidth = 2.dp,
strokeCap = StrokeCap.Round, strokeCap = StrokeCap.Round,
progress = progressAnimation, progress = { progressAnimation },
) )
} }
@ -318,7 +320,7 @@ fun Display(
CircularProgressIndicator( CircularProgressIndicator(
strokeCap = StrokeCap.Round, strokeCap = StrokeCap.Round,
progress = progressAnimation, progress = { progressAnimation },
modifier = Modifier.align(Alignment.Center) modifier = Modifier.align(Alignment.Center)
) )
@ -384,7 +386,7 @@ class AccelerometerSpectreContract {
val loadingHistoryState : ProgressState<List<Ble.Accelerometer.SpectrePoint>> val loadingHistoryState : ProgressState<List<Ble.Accelerometer.SpectrePoint>>
) : State() ) : State()
object Exception : State() data object Exception : State()
} }
@ -424,8 +426,6 @@ class AccelerometerSpectreViewModel @Inject constructor(
if(state is AccelerometerSpectreContract.State.Display) { if(state is AccelerometerSpectreContract.State.Display) {
//if(lastSerial != event.serial) {
lastSerial = event.serial lastSerial = event.serial
setState { setState {

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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

View File

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

View File

@ -1,31 +1,30 @@
package llc.arma.ble.app.ui.screen.inspection.host.view package llc.arma.ble.app.ui.screen.inspection.host.view
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row 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.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons 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.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowRight import androidx.compose.material.icons.rounded.KeyboardArrowRight
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.unit.dp 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.model.BleView
import llc.arma.ble.app.ui.screen.BleInfoView import llc.arma.ble.app.ui.screen.BleInfoView
import llc.arma.ble.app.ui.screen.inspection.host.HostContract import llc.arma.ble.app.ui.screen.inspection.host.HostContract
@ -38,11 +37,13 @@ fun DisplayState(
ble: BleView.Host ble: BleView.Host
) { ) {
val scrollState = rememberScrollState()
Column { Column {
Column( Column(
modifier = Modifier modifier = Modifier
.verticalScroll(rememberScrollState()) .verticalScroll(scrollState)
.weight(1f) .weight(1f)
) { ) {
@ -52,7 +53,10 @@ fun DisplayState(
horizontal = 8.dp horizontal = 8.dp
) )
) { ) {
BleInfoView(bleInfo = origin.info) BleInfoView(
bleInfo = origin.info,
version = origin.state.version
)
} }
Column( Column(
@ -98,21 +102,21 @@ fun DisplayState(
BleMenuItem( BleMenuItem(
title = "График измерений", title = "График измерений",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowRight) icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) { ) {
onEvent(HostContract.Event.OnShowHostHistory) onEvent(HostContract.Event.OnShowHostHistory)
} }
BleMenuItem( BleMenuItem(
title = "Таблица BLE ID", title = "Таблица BLE ID",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowRight) icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) { ) {
onEvent(HostContract.Event.OnShowHostBleTable) onEvent(HostContract.Event.OnShowHostBleTable)
} }
BleMenuItem( BleMenuItem(
title = "Изменить пароль", title = "Изменить пароль",
icon = rememberVectorPainter(Icons.Rounded.KeyboardArrowRight) icon = rememberVectorPainter(Icons.AutoMirrored.Rounded.KeyboardArrowRight)
) { ) {
onEvent(HostContract.Event.OnChangePassword) onEvent(HostContract.Event.OnChangePassword)
} }
@ -122,29 +126,17 @@ fun DisplayState(
} }
Surface( PrimaryButton(
modifier = Modifier modifier = Modifier.shadow(
.fillMaxWidth() if(scrollState.canScrollForward){
.padding(8.dp) 8.dp
.height(50.dp), } else {
shape = CircleShape, 0.dp
color = MaterialTheme.colorScheme.primaryContainer, }
onClick = { ).background(MaterialTheme.colorScheme.background),
onEvent(HostContract.Event.OnShowWriteBlePreview) label = "Сохранить"
}
) { ) {
onEvent(HostContract.Event.OnShowWriteBlePreview)
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Сохранить"
)
}
} }
} }
@ -155,8 +147,8 @@ fun DisplayState(
fun BleMenuItem( fun BleMenuItem(
title: String, title: String,
subtitle: String? = null, subtitle: String? = null,
icon: Painter, icon: Painter? = null,
onClick: () -> Unit onClick: (() -> Unit) = {}
){ ){
Box( Box(
@ -170,7 +162,7 @@ fun BleMenuItem(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(16.dp)) .clip(RoundedCornerShape(16.dp))
.clickable { onClick() } .clickable(onClick = onClick)
.padding(8.dp) .padding(8.dp)
) { ) {
@ -192,10 +184,12 @@ fun BleMenuItem(
} }
Icon( if (icon != null) {
painter = icon, Icon(
contentDescription = null 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.layout.size
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ContentAlpha import androidx.compose.material.ContentAlpha
import androidx.compose.material.icons.Icons 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.ArrowBack
import androidx.compose.material.icons.rounded.Refresh import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material.icons.rounded.Save 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.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewModelScope 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.axisLineComponent
import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis import com.patrykandpatrick.vico.compose.axis.horizontal.bottomAxis
import com.patrykandpatrick.vico.compose.axis.vertical.startAxis import com.patrykandpatrick.vico.compose.axis.vertical.startAxis
import com.patrykandpatrick.vico.compose.chart.Chart import com.patrykandpatrick.vico.compose.chart.Chart
import com.patrykandpatrick.vico.compose.chart.column.columnChart import com.patrykandpatrick.vico.compose.chart.column.columnChart
import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollSpec 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.shapeComponent
import com.patrykandpatrick.vico.compose.component.textComponent import com.patrykandpatrick.vico.compose.component.textComponent
import com.patrykandpatrick.vico.core.axis.AxisPosition import com.patrykandpatrick.vico.core.axis.AxisPosition
@ -122,13 +119,7 @@ fun HostHistory(
viewModel.setEvent(HostHistoryContract.Event.OnStart(ble.name, ble.serial)) viewModel.setEvent(HostHistoryContract.Event.OnStart(ble.name, ble.serial))
} }
/*DisposableEffect("ble") { Column {
onDispose {
viewModel.setEvent(AccelerometerHistoryContract.Event.StopMeasure)
}
}*/
Column() {
TopAppBar( TopAppBar(
navigationIcon = { navigationIcon = {
@ -136,7 +127,7 @@ fun HostHistory(
IconButton(onClick = it) { IconButton(onClick = it) {
Icon( Icon(
imageVector = Icons.Rounded.ArrowBack, imageVector = Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = null contentDescription = null
) )
} }
@ -217,6 +208,18 @@ val colorsStack = listOf(
Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c), Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c),
Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f), Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f),
Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee), 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 = val startAxisValueFormatter =
@ -413,7 +416,7 @@ fun Display(
modifier = Modifier.verticalScroll(rememberScrollState()) modifier = Modifier.verticalScroll(rememberScrollState())
) { ) {
allSerials.mapIndexed { index, s -> allSerials.mapIndexed { _, s ->
LegendItem(s = s) LegendItem(s = s)
} }
@ -433,7 +436,7 @@ fun Display(
modifier = Modifier.horizontalScroll(rememberScrollState()) modifier = Modifier.horizontalScroll(rememberScrollState())
) { ) {
allSerials.mapIndexed { index, s -> allSerials.mapIndexed { _, s ->
LegendItem(s = s) LegendItem(s = s)
} }
@ -490,7 +493,7 @@ fun Display(
CircularProgressIndicator( CircularProgressIndicator(
strokeCap = StrokeCap.Round, strokeCap = StrokeCap.Round,
progress = progressAnimation, progress = { progressAnimation },
modifier = Modifier.align(Alignment.Center) modifier = Modifier.align(Alignment.Center)
) )
@ -566,12 +569,11 @@ class HostHistoryContract {
@HiltViewModel @HiltViewModel
class HostHistoryViewModel @Inject constructor( class HostHistoryViewModel @Inject constructor(
private val getHostHistoryBySerial: GetHostHistoryBySerial, private val getHostHistoryBySerial: GetHostHistoryBySerial,
private val getBleBySerial: GetBleBySerial,
private val getBleNamesFlow: GetBleNamesFlow, private val getBleNamesFlow: GetBleNamesFlow,
private val exportToXlsx: ExportToXlsx private val exportToXlsx: ExportToXlsx
) : BaseViewModel<HostHistoryContract.State, HostHistoryContract.Event, HostHistoryContract.Effect>() { ) : BaseViewModel<HostHistoryContract.State, HostHistoryContract.Event, HostHistoryContract.Effect>() {
var measureJob: Job? = null private var measureJob: Job? = null
private var lastSerial: String? = 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.slideInVertically
import androidx.compose.animation.slideOutVertically import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer 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.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowUp import androidx.compose.material.icons.rounded.KeyboardArrowUp
import androidx.compose.material3.FilledIconButton import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@ -34,6 +29,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp 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.model.BleView
import llc.arma.ble.app.ui.screen.inspection.host.HostContract import llc.arma.ble.app.ui.screen.inspection.host.HostContract
@ -68,33 +64,14 @@ fun IntervalEdit(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Surface( PrimaryButton(
modifier = Modifier label = "Применить"
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(
HostContract.Event.OnSaveIntervalChanged(
value.toLong()
)
)
}
) { ) {
onEvent(
Box(modifier = Modifier.fillMaxSize()) { HostContract.Event.OnSaveIntervalChanged(
value.toLong()
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Применить"
) )
)
}
} }
} }

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

View File

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

View File

@ -5,17 +5,14 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -25,6 +22,8 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import llc.arma.ble.R import llc.arma.ble.R
import llc.arma.ble.app.ui.common.PrimaryButton
import llc.arma.ble.app.ui.common.SecondaryButton
@Composable @Composable
fun Write( fun Write(
@ -85,98 +84,38 @@ fun Write(
Spacer(modifier = Modifier.height(20.dp)) Spacer(modifier = Modifier.height(20.dp))
Surface( PrimaryButton(
shape = CircleShape, label = "Записать"
color = MaterialTheme.colorScheme.primaryContainer,
onClick = {
onEvent(BleTableEditContract.Event.OnWrite)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
) { ) {
onEvent(BleTableEditContract.Event.OnWrite)
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.background,
style = MaterialTheme.typography.labelLarge,
text = "Записать"
)
}
} }
Surface( SecondaryButton (
shape = CircleShape, label = "Отменить"
color = MaterialTheme.colorScheme.surfaceVariant,
onClick = {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
},
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
) { ) {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
Box(modifier = Modifier.fillMaxSize()) {
Text(
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.labelLarge,
text = "Отменить"
)
}
} }
} }
is BleTableEditContract.State.Display.WriteState.Writing -> { 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( Spacer(modifier = Modifier.height(48.dp))
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 = "Отменить"
)
}
}
SecondaryButton (
label = "Отменить"
) {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
} }
} }
@ -184,60 +123,37 @@ fun Write(
} }
BleTableEditContract.State.Display.WriteState.Success -> { BleTableEditContract.State.Display.WriteState.Success -> {
Box { Column {
Column { Box(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
) {
Box( Image(
modifier = Modifier modifier = Modifier
.padding(8.dp) .size(125.dp)
.fillMaxWidth() .align(Alignment.Center),
) { painter = painterResource(R.drawable.ic_done),
contentDescription = null
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 = "Успешно завершено"
) )
Spacer(modifier = Modifier.height(20.dp)) }
Surface( Spacer(modifier = Modifier.height(16.dp))
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
) {
Box(modifier = Modifier.fillMaxSize()) { Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = "Успешно завершено"
)
Text( Spacer(modifier = Modifier.height(20.dp))
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
}
PrimaryButton(
label = "Ok"
) {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
} }
} }
@ -245,60 +161,37 @@ fun Write(
} }
BleTableEditContract.State.Display.WriteState.Failure -> { BleTableEditContract.State.Display.WriteState.Failure -> {
Box { Column {
Column { Box(
modifier = Modifier
.padding(8.dp)
.fillMaxWidth()
) {
Box( Image(
modifier = Modifier modifier = Modifier
.padding(8.dp) .size(125.dp)
.fillMaxWidth() .align(Alignment.Center),
) { painter = painterResource(R.drawable.ic_error),
contentDescription = null
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 = "Ошибка записи"
) )
Spacer(modifier = Modifier.height(20.dp)) }
Surface( Spacer(modifier = Modifier.height(16.dp))
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.height(50.dp),
shape = CircleShape,
color = MaterialTheme.colorScheme.primary,
onClick = {
onEvent(BleTableEditContract.Event.OnHideWritePreview)
}
) {
Box(modifier = Modifier.fillMaxSize()) { Text(
modifier = Modifier.align(Alignment.CenterHorizontally),
text = "Ошибка записи"
)
Text( Spacer(modifier = Modifier.height(20.dp))
modifier = Modifier.align(Alignment.Center),
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.labelLarge,
text = "Ок"
)
}
}
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.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch 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.common.rememberBottomDialogState
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.DisplayState 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.IntervalEdit
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.LoadingState 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.TemperatureHistory
import llc.arma.ble.app.ui.screen.inspection.thermometer.view.Write import llc.arma.ble.app.ui.screen.inspection.thermometer.view.Write
import llc.arma.ble.domain.model.Ble 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 @Composable
fun ThermometerScreen( fun ThermometerScreen(
ble: Ble.Thermometer, ble: Ble.Thermometer,
@ -74,9 +58,7 @@ fun ThermometerScreen(
if(currentState is ThermometerContract.State.Display) { if(currentState is ThermometerContract.State.Display) {
IntervalEdit( IntervalEdit(
state = currentState.thermometer, state = currentState.thermometer,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }
@ -86,12 +68,13 @@ fun ThermometerScreen(
val currentState = viewModel.viewState.value val currentState = viewModel.viewState.value
if(currentState is ThermometerContract.State.Display) { if(currentState is ThermometerContract.State.Display) {
PowerEdit(
state = currentState.thermometer, TxLevelSelector(
onEvent = { tx = currentState.thermometer.state.tx
viewModel.setEvent(it) ) {
} viewModel.setEvent(ThermometerContract.Event.OnPowerChanged(it))
) }
} }
} }
@ -115,9 +98,7 @@ fun ThermometerScreen(
Write( Write(
state = it, state = it,
onEvent = { onEvent = viewModel::setEvent
viewModel.setEvent(it)
}
) )
} }

View File

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

View File

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

View File

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

View File

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

View File

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

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 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.runtime.Composable
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import androidx.navigation.compose.NavHost 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.RotationStatisticContract
import llc.arma.ble.app.ui.screen.rotation.statistic.RotationStatisticScreen import llc.arma.ble.app.ui.screen.rotation.statistic.RotationStatisticScreen
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun MainScreen() { fun MainScreen() {

View File

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

View File

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

View File

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

View File

@ -1,8 +1,10 @@
package llc.arma.ble.data.repository package llc.arma.ble.data.repository
import android.Manifest
import android.app.Application import android.app.Application
import android.os.SystemClock import android.os.SystemClock
import android.util.Log import android.util.Log
import androidx.annotation.RequiresPermission
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.awaitClose
@ -52,6 +54,9 @@ import kotlin.math.PI
import kotlin.math.atan 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 serviceUUID: UUID = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002")
val accelerometerReadUUID: UUID = UUID.fromString("00002713-0000-1000-8000-00805f9b34fb") val accelerometerReadUUID: UUID = UUID.fromString("00002713-0000-1000-8000-00805f9b34fb")
@ -101,7 +106,6 @@ class BleRepositoryImpl @Inject constructor(
resultList[it.device.address] = it.info resultList[it.device.address] = it.info
}.launchIn(CoroutineScope(Dispatchers.IO)) }.launchIn(CoroutineScope(Dispatchers.IO))
val timer = Timer().apply { val timer = Timer().apply {
schedule(object : TimerTask() { schedule(object : TimerTask() {
override fun run() { override fun run() {
@ -129,6 +133,7 @@ class BleRepositoryImpl @Inject constructor(
} }
@RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
override suspend fun getBleBySerial( override suspend fun getBleBySerial(
serial: String serial: String
): Result<Flow<Ble>, BleException> { ): Result<Flow<Ble>, BleException> {
@ -141,244 +146,221 @@ class BleRepositoryImpl @Inject constructor(
} else { } else {
fun BleInfo.updateBleInfo(): BleInfo { val connection = ClientBleGatt.connect(app, serial, CoroutineScope(Dispatchers.IO))
return copy(
rssi = if((SystemClock.elapsedRealtime() - scanTime) > 15_000) {
null
} else { rssi }
)
}
fun BleInfo.updateState(): Ble.BleState { try {
return Ble.BleState(
tx = Ble.BleState.TX.fromByte(tx.toByte())
?: Ble.BleState.TX.ZERO
)
}
val firstResult = when(initialBle.type){ fun BleInfo.updateBleInfo(): BleInfo {
BleInfo.Type.HOST -> { return copy(
rssi = if ((SystemClock.elapsedRealtime() - scanTime) > 15_000) {
val tState = readHostState( null
initialBle.serial } else {
).fold( rssi
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(),
) )
} }
BleInfo.Type.THERMOMETER -> {
val tState = readThermometerState( val version = connection.readVersion()
initialBle.serial,
initialBle.tableStatus fun BleInfo.updateState(): Ble.BleState {
).fold( return Ble.BleState(
onFailure = { return Result.failure(it) }, tx = Ble.BleState.TX.fromByte(tx.toByte())
onSuccess = { it } ?: Ble.BleState.TX.ZERO,
version = version
) )
Ble.Thermometer(
info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
thermometerState = tState
)
} }
BleInfo.Type.ACCELEROMETER -> {
val tState = readAccelState( val firstResult =
initialBle.serial, when (initialBle.type) {
initialBle.tableStatus BleInfo.Type.HOST -> {
).fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
Ble.Accelerometer( val tState = connection.readHostState().fold(
info = initialBle.updateBleInfo(), onFailure = { return Result.failure(it) },
state = initialBle.updateState(), onSuccess = { it }
accelerometerState = tState )
)
} Ble.Host(
} info = initialBle.updateBleInfo(),
state = initialBle.updateState(),
Result.success( hostState = tState
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) 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) @OptIn(ExperimentalUnsignedTypes::class)
private suspend fun readThermometerState( private suspend fun ClientBleGatt.readThermometerState(
address: String,
timer: BleInfo.HistoryTableStatus timer: BleInfo.HistoryTableStatus
): Result<Ble.Thermometer.ThermometerState, BleException> { ): Result<Ble.Thermometer.ThermometerState, BleException> {
return if(app.checkPermission()) { val service = discoverServices().findService(serviceUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val connection = var characteristic = service.findCharacteristic(temperatureReadUUID)
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.IO)) ?: return Result.failure(BleException.UnexpectedResponse)
try { characteristic.write(DataByteArray.from(1, 1))
val service = connection.discoverServices().findService(serviceUUID) delay(2_000)
?: return Result.failure(BleException.UnexpectedResponse)
var characteristic = service.findCharacteristic(temperatureReadUUID) val temperature = characteristic.read().value.toUByteArray().toTemperature()
?: return Result.failure(BleException.UnexpectedResponse)
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() return Result.success(
Ble.Thermometer.ThermometerState(
characteristic = service.findCharacteristic(intervalReadUUID) temperature = temperature,
?: return Result.failure(BleException.UnexpectedResponse) saveHistory = timer !== BleInfo.HistoryTableStatus.DISABLED,
historyInterval = interval
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)
}
} }
private suspend fun readHostState( @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
address: String private suspend fun ClientBleGatt.readHostState(
): Result<Ble.Host.HostState, BleException> { ): Result<Ble.Host.HostState, BleException> {
return if(app.checkPermission()) { val service = discoverServices().findService(serviceUUID)
?: return Result.failure(BleException.UnexpectedResponse)
val connection = val characteristic = service.findCharacteristic(intervalReadUUID)
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.IO)) ?: return Result.failure(BleException.UnexpectedResponse)
try { val interval = characteristic.readWriteInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
)
val service = connection.discoverServices().findService(serviceUUID) val readTimeout = characteristic.readTimeoutInterval().fold(
?: return Result.failure(BleException.UnexpectedResponse) onFailure = { return Result.failure(it) },
onSuccess = { it }
)
val characteristic = service.findCharacteristic(intervalReadUUID) return Result.success(
?: return Result.failure(BleException.UnexpectedResponse) Ble.Host.HostState(
historyInterval = interval,
val interval = characteristic.readWriteInterval().fold( readInterval = readTimeout
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)
}
} }
@ -394,6 +376,32 @@ class BleRepositoryImpl @Inject constructor(
write(DataByteArray.from(3, 0, 0, 0)) 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 { val interval = read().value.let {
if (it.size == 4) { if (it.size == 4) {
it.get4byteUIntAt(0).toLong() it.get4byteUIntAt(0).toLong()
@ -408,79 +416,137 @@ class BleRepositoryImpl @Inject constructor(
} }
private suspend fun readAccelState( data class Version(
address: String, val major: Int,
timer: BleInfo.HistoryTableStatus val minor: Int,
): Result<Ble.Accelerometer.AccelerometerState, BleException> { val patch: Int,
val release: Int
): Comparable<Version> {
return if(app.checkPermission()) { companion object {
val connection = fun fromString(
ClientBleGatt.connect(app, address, CoroutineScope(Dispatchers.IO)) version: String
): Version {
try { val splitArray = version.split('.', '-')
val service = connection.discoverServices() return Version(
.findService(serviceUUID) ?: return Result.failure(BleException.UnexpectedResponse) major = splitArray[0].toInt(),
minor = splitArray[1].toInt(),
var characteristic = service.findCharacteristic(intervalReadUUID) patch = splitArray[2].toInt(),
?: return Result.failure(BleException.UnexpectedResponse) release = splitArray.last().toInt()
val interval = characteristic.readWriteInterval().fold(
onFailure = { return Result.failure(it) },
onSuccess = { it }
) )
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( override suspend fun getAccelerometerSpectreBySerial(
@ -535,11 +601,6 @@ class BleRepositoryImpl @Inject constructor(
request: Ble.Thermometer.WriteRequest request: Ble.Thermometer.WriteRequest
): Result<Unit, BleException> { ): Result<Unit, BleException> {
fun UInt.to4ByteArrayInLittleEndian(): ByteArray =
(3 downTo 0).map {
(this shr (it * Byte.SIZE_BITS)).toByte()
}.toByteArray()
return if(app.checkPermission()) { return if(app.checkPermission()) {
val connection = 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( service.findCharacteristic(flashWriteUUID)!!.write(
DataByteArray.from(9) DataByteArray.from(9)
) )

View File

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

View File

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

View File

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

View File

@ -3,13 +3,7 @@ package llc.arma.ble.data.repository
import android.app.Application import android.app.Application
import android.icu.text.SimpleDateFormat import android.icu.text.SimpleDateFormat
import android.os.Environment 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.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.model.Ble
import llc.arma.ble.domain.repository.XlsxRepository import llc.arma.ble.domain.repository.XlsxRepository
import org.apache.poi.ss.usermodel.WorkbookFactory import org.apache.poi.ss.usermodel.WorkbookFactory

View File

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

View File

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

View File

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

View File

@ -16,9 +16,9 @@ class GetBleBySerial @Inject constructor(
sealed class GetBleException { 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. }// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id 'com.android.application' version '8.1.1' apply false id 'com.android.application' version '8.8.1' apply false
id 'com.android.library' version '8.1.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.android' version '1.9.22' apply false
id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.22' id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.22'
id("androidx.room") version "2.6.1" apply false 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 # thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true android.nonTransitiveRClass=true
android.defaults.buildfeatures.buildconfig=true android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false android.nonFinalResIds=true
org.gradle.unsafe.configuration-cache=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 distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionPath=wrapper/dists 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 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"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with 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 # See the License for the specific language governing permissions and
# limitations under the License. # 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 # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" # This is normally unused
APP_BASE_NAME=`basename "$0"` # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 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. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 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 [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 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." location of your Java installation."
fi fi
else else
JAVACMD="java" 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. 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 Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
MAX_FD="$MAX_FD_LIMIT" # shellcheck disable=SC2039,SC3045
fi MAX_FD=$( ulimit -H -n ) ||
ulimit -n $MAX_FD warn "Could not query maximum file descriptor limit"
if [ $? -ne 0 ] ; then esac
warn "Could not set maximum file descriptor limit: $MAX_FD" case $MAX_FD in #(
fi '' | soft) :;; #(
else *)
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
fi # shellcheck disable=SC2039,SC3045
fi ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
# 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" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --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 # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 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" "$@" exec "$JAVACMD" "$@"

37
gradlew.bat vendored
View File

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