diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
deleted file mode 100644
index 9a31328..0000000
--- a/.idea/deploymentTargetDropDown.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 726a9f9..e3fed92 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,11 +2,18 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
= Build.VERSION_CODES.S) {
+ rememberMultiplePermissionsState(
+ listOf(
+ android.Manifest.permission.BLUETOOTH_SCAN,
+ android.Manifest.permission.BLUETOOTH_CONNECT
+ )
+ )
+ } else {
+ rememberMultiplePermissionsState(
+ listOf()
+ )
+ }
+
+ if(multiplePermissionsState.allPermissionsGranted) {
+
+ MainScreen()
+
+ } else {
+
+ LaunchedEffect(multiplePermissionsState){
+ multiplePermissionsState.launchMultiplePermissionRequest()
+ }
+
+ }
+
}
+
}
+
}
+
}
+
}
\ No newline at end of file
diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListScreen.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListScreen.kt
index 50c61d9..404422f 100644
--- a/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListScreen.kt
+++ b/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListScreen.kt
@@ -18,6 +18,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.flow.launchIn
@@ -49,6 +50,13 @@ fun BleListScreen(
}
)
+ if(state.bleList.isEmpty()){
+ LinearProgressIndicator(
+ strokeCap = StrokeCap.Round,
+ modifier = Modifier.fillMaxWidth().height(3.dp)
+ )
+ }
+
LazyColumn(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.fillMaxSize()
diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListViewModel.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListViewModel.kt
index d082ddc..61b7b53 100644
--- a/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListViewModel.kt
+++ b/app/src/main/java/llc/arma/ble/app/ui/screen/ble/BleListViewModel.kt
@@ -18,9 +18,17 @@ class BleListViewModel @Inject constructor(
init {
getBleAroundFlow().onEach {
- setState {
- BleListContract.State(it)
- }
+ it.fold(
+ onSuccess = {
+ setState {
+ BleListContract.State(it)
+ }
+ },
+ onFailure = {
+
+ }
+ )
+
}.launchIn(viewModelScope)
}
diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/connection/ConnectionScreen.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/connection/ConnectionScreen.kt
index b9cb9e7..3f294fd 100644
--- a/app/src/main/java/llc/arma/ble/app/ui/screen/connection/ConnectionScreen.kt
+++ b/app/src/main/java/llc/arma/ble/app/ui/screen/connection/ConnectionScreen.kt
@@ -12,6 +12,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import kotlinx.coroutines.flow.launchIn
@@ -123,7 +124,11 @@ fun ConnectionScreen(
private fun LoadingState(){
Column {
Box(modifier = Modifier.fillMaxSize()) {
- CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
+ CircularProgressIndicator(
+ strokeCap = StrokeCap.Round,
+ modifier = Modifier.align(Alignment.Center
+ )
+ )
}
}
}
diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/ThermometerScreen.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/ThermometerScreen.kt
index 2694001..b4e53fc 100644
--- a/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/ThermometerScreen.kt
+++ b/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/ThermometerScreen.kt
@@ -26,6 +26,31 @@ enum class SheetPage {
INTERVAL, POWER, TEMPERATURE_HISTORY
}
+private val Boolean.localizedName: String
+ get() {
+ return if(this){
+ "Включено"
+ } else {
+ "Выключено"
+ }
+ }
+
+private 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()
+
+ }
+
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ThermometerScreen(
@@ -140,8 +165,6 @@ fun ThermometerScreen(
)
-
-
}
}
@@ -197,7 +220,7 @@ fun ThermometerScreen(
Text(
color = MaterialTheme.colorScheme.secondary,
style = MaterialTheme.typography.bodyMedium,
- text = "${it} db"
+ text = "${state.origin.state.tx.localizedName} db -> ${it.localizedName} db"
)
}
@@ -209,6 +232,39 @@ fun ThermometerScreen(
it.writeRequest.saveHistory?.let {
+ Box(
+ modifier = Modifier.padding(
+ vertical = 8.dp,
+ horizontal = 8.dp
+ )
+ ) {
+
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .clip(RoundedCornerShape(16.dp))
+ .padding(8.dp)
+ ) {
+
+ Column(
+ modifier = Modifier.weight(1f)
+ ) {
+
+ Text(
+ text = "Сохранять историю измерений"
+ )
+ Text(
+ color = MaterialTheme.colorScheme.secondary,
+ style = MaterialTheme.typography.bodyMedium,
+ text = "${state.origin.thermometerState.saveHistory.localizedName} -> ${it.localizedName}"
+ )
+
+ }
+
+ }
+
+ }
+
}
it.writeRequest.historyInterval?.let {
diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/view/DisplayState.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/view/DisplayState.kt
index f4a5a2d..96f3502 100644
--- a/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/view/DisplayState.kt
+++ b/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/view/DisplayState.kt
@@ -119,19 +119,6 @@ fun DisplayState(
}
- if (ble.thermometerState.temperature.loading) {
-
- CircularProgressIndicator()
-
- } else {
-
- Icon(
- imageVector = Icons.Rounded.Refresh,
- contentDescription = null
- )
-
- }
-
}
}
@@ -194,7 +181,7 @@ fun DisplayState(
) {
Text(
- text = "Интервал измерний"
+ text = "Интервал измерений"
)
Text(
color = MaterialTheme.colorScheme.secondary,
diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/view/TemperatureHistory.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/view/TemperatureHistory.kt
index 21cea30..815172c 100644
--- a/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/view/TemperatureHistory.kt
+++ b/app/src/main/java/llc/arma/ble/app/ui/screen/thermometer/view/TemperatureHistory.kt
@@ -1,5 +1,9 @@
package llc.arma.ble.app.ui.screen.thermometer.view
+import androidx.compose.animation.core.FastOutSlowInEasing
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
@@ -32,9 +36,15 @@ import kotlin.random.Random
import kotlin.random.nextInt
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Refresh
+import androidx.compose.ui.graphics.StrokeCap
+import com.patrykandpatrick.vico.compose.chart.scroll.rememberChartScrollState
import com.patrykandpatrick.vico.core.axis.AxisPosition
import com.patrykandpatrick.vico.core.axis.formatter.AxisValueFormatter
+import com.patrykandpatrick.vico.core.chart.scale.AutoScaleUp
import com.patrykandpatrick.vico.core.entry.ChartEntry
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import llc.arma.ble.domain.common.ProgressState
import llc.arma.ble.domain.model.Ble
import java.text.SimpleDateFormat
import java.util.*
@@ -80,7 +90,7 @@ fun TemperatureHistory(
onClick = {
viewModel.setEvent(TemperatureHistoryContract.Event.LoadHistory(ble.serial))
},
- enabled = state is TemperatureHistoryContract.State.Display
+ enabled = state.loadingHistoryState is ProgressState.Finished
) {
Icon(
imageVector = Icons.Rounded.Refresh,
@@ -92,12 +102,14 @@ fun TemperatureHistory(
Spacer(modifier = Modifier.height(16.dp))
- when (state) {
- is TemperatureHistoryContract.State.Display -> {
-
- val producer = state.history.mapIndexed { index, measurePoint ->
+ when (state.loadingHistoryState) {
+ is ProgressState.Finished -> {
+
+ Text(text = "${state.loadingHistoryState.data.size}")
+
+ val producer = state.loadingHistoryState.data.mapIndexed { index, measurePoint ->
TemperatureEntry(measurePoint.date, index.toFloat(), measurePoint.value) }.let {
- ChartEntryModelProducer(it)
+ ChartEntryModelProducer(it)
}
val axisValueFormatter = AxisValueFormatter { value, chartValues ->
@@ -107,14 +119,20 @@ fun TemperatureHistory(
.orEmpty()
}
- val lineChart = lineChart()
+ val lineChart = lineChart(
+ spacing = 110.dp
+ )
Box(modifier = Modifier.padding(8.dp)) {
+ val scrollState = rememberChartScrollState()
+
+ LaunchedEffect(scrollState.maxValue){
+ scrollState.scrollBy(scrollState.maxValue)
+ }
+
Chart(
- modifier = Modifier
- .fillMaxWidth()
- .aspectRatio(1.5f),
+ chartScrollState = scrollState,
chart = lineChart,
chartModelProducer = producer,
startAxis = startAxis(),
@@ -122,13 +140,15 @@ fun TemperatureHistory(
valueFormatter = axisValueFormatter,
labelRotationDegrees = 0f,
),
+ modifier = Modifier
+ .fillMaxWidth()
+ .aspectRatio(1.5f),
)
}
-
}
- is TemperatureHistoryContract.State.Loading -> {
-
+ is ProgressState.Indeterminate -> {
+
Box(modifier = Modifier.padding(8.dp)) {
Box(
@@ -138,15 +158,37 @@ fun TemperatureHistory(
){
CircularProgressIndicator(
+ strokeCap = StrokeCap.Round,
modifier = Modifier.align(Alignment.Center)
)
}
}
+ }
+ is ProgressState.Progress -> Box(modifier = Modifier.padding(8.dp)) {
+
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .aspectRatio(2f),
+ ){
+
+ val progressAnimDuration = 1500
+ val progressAnimation by animateFloatAsState(
+ targetValue = state.loadingHistoryState.value,
+ animationSpec = tween(durationMillis = progressAnimDuration, easing = FastOutSlowInEasing)
+ )
+
+ CircularProgressIndicator(
+ strokeCap = StrokeCap.Round,
+ progress = progressAnimation,
+ modifier = Modifier.align(Alignment.Center)
+ )
+
+ }
}
-
}
}
@@ -163,15 +205,9 @@ class TemperatureHistoryContract {
}
- sealed class State : ViewState {
-
- object Loading : State()
-
- data class Display(
- var history : List
- ) : State()
-
- }
+ class State(
+ val loadingHistoryState : ProgressState>
+ ) : ViewState
sealed class Effect : ViewSideEffect {
@@ -186,7 +222,9 @@ class TemperatureHistoryViewModel @Inject constructor(
private val getTemperatureHistoryBySerial: GetTemperatureHistoryBySerial
) : BaseViewModel() {
- override fun setInitialState() = TemperatureHistoryContract.State.Loading
+ override fun setInitialState() = TemperatureHistoryContract.State(
+ ProgressState.Indeterminate
+ )
override fun handleEvents(event: TemperatureHistoryContract.Event) {
when(event){
@@ -201,14 +239,21 @@ class TemperatureHistoryViewModel @Inject constructor(
viewModelScope.launch {
setState {
- TemperatureHistoryContract.State.Loading
+ TemperatureHistoryContract.State(ProgressState.Indeterminate)
}
- val history = getTemperatureHistoryBySerial(event.serial)
+ getTemperatureHistoryBySerial(event.serial).onEach {
+ it.fold(
+ onSuccess = {
+ setState {
+ TemperatureHistoryContract.State(it)
+ }
+ },
+ onFailure = {
- setState {
- TemperatureHistoryContract.State.Display(history)
- }
+ }
+ )
+ }.launchIn(this)
}
}
diff --git a/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt b/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt
index 05d0528..a05c74d 100644
--- a/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt
+++ b/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt
@@ -8,24 +8,23 @@ import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.content.pm.PackageManager
import android.os.Build
-import android.os.ParcelUuid
-import android.util.Log
import androidx.core.app.ActivityCompat
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flow
import llc.arma.ble.domain.Result
+import llc.arma.ble.domain.common.BleException
+import llc.arma.ble.domain.common.ProgressState
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.repository.BleRepository
import llc.arma.ble.domain.usecase.GetBleBySerial
-import java.nio.ByteBuffer
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.resume
-import kotlin.coroutines.suspendCoroutine
@Singleton
class BleRepositoryImpl @Inject constructor(
@@ -69,67 +68,86 @@ class BleRepositoryImpl @Inject constructor(
(this[idx].toUInt() and 0xFFu)
private val deviceCache = mutableMapOf()
+ val resultList = mutableMapOf()
- override fun getBleAroundFlow(): Flow> {
+ override fun getBleAroundFlow(): Flow, BleException>> {
- val resultList = mutableMapOf()
+ return if (ActivityCompat.checkSelfPermission(
+ app,
+ Manifest.permission.BLUETOOTH_SCAN
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
- return callbackFlow {
+ flow { emit(Result.failure(BleException.PermissionDenied)) }
- val bleCallback = object : ScanCallback() {
+ } else {
- override fun onScanResult(
- callbackType: Int,
- result: ScanResult
- ) {
+ callbackFlow {
- super.onScanResult(callbackType, result)
+ val bleCallback = object : ScanCallback() {
- if (ActivityCompat.checkSelfPermission(
- app,
- Manifest.permission.BLUETOOTH_CONNECT
- ) == PackageManager.PERMISSION_GRANTED
+ override fun onScanResult(
+ callbackType: Int,
+ result: ScanResult
) {
- if(result.scanRecord?.deviceName?.contains("ArmA") == true) {
+ super.onScanResult(callbackType, result)
- resultList[result.device.address] = result.info
+ if (ActivityCompat.checkSelfPermission(
+ app,
+ Manifest.permission.BLUETOOTH_CONNECT
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
- deviceCache[result.device.address] = result
+ if (result.scanRecord?.deviceName?.contains("ArmA") == true) {
+ resultList[result.device.address] = result.info
+
+ deviceCache[result.device.address] = result
+
+ }
+
+ } else {
+ CoroutineScope(Dispatchers.IO).launch {
+ send(
+ Result.failure(BleException.PermissionDenied)
+ )
+ }
}
}
}
- }
+ val bleScanner =
+ app.getSystemService(BluetoothManager::class.java).adapter.bluetoothLeScanner
- val bleScanner = app.getSystemService(BluetoothManager::class.java).adapter.bluetoothLeScanner
- bleScanner.startScan(
- listOf(),
- ScanSettings.Builder()
- .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
- .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
- .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
- .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
- .setReportDelay(0L)
- .build(),
- bleCallback)
+ bleScanner.startScan(
+ listOf(),
+ ScanSettings.Builder()
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
+ .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
+ .setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
+ .setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
+ .setReportDelay(0L)
+ .build(),
+ bleCallback)
- val timer = Timer().apply {
- schedule(object : TimerTask() {
- override fun run() {
- CoroutineScope(Dispatchers.IO).launch {
- send(resultList.values.toList())
+ val timer = Timer().apply {
+ schedule(object : TimerTask() {
+ override fun run() {
+ CoroutineScope(Dispatchers.IO).launch {
+ send(Result.success(resultList.values.toList()))
+ }
}
- }
- }, 100, 500)
- }
+ }, 100, 500)
+ }
+
+ awaitClose {
+ bleScanner.stopScan(bleCallback)
+ timer.cancel()
+ }
- awaitClose {
- bleScanner.stopScan(bleCallback)
- timer.cancel()
}
}
@@ -178,10 +196,17 @@ class BleRepositoryImpl @Inject constructor(
BleInfo.Type.THERMOMETER -> {
+ val thermometer = readThermometerState(result).fold(
+ onFailure = { _ ->
+ return@launch it.resume(Result.failure(GetBleBySerial.GetBleException.BlePermissionDenied))
+ },
+ onSuccess = { return@fold it }
+ )
+
Ble.Thermometer(
info = info,
state = state,
- thermometerState = readThermometerState(result)
+ thermometerState = thermometer
)
}
@@ -204,33 +229,54 @@ class BleRepositoryImpl @Inject constructor(
private suspend fun readThermometerState(
record: ScanResult
- ): Ble.Thermometer.ThermometerState {
+ ): Result {
- return Ble.Thermometer.ThermometerState(
- temperature = readTemperature(record),
- saveHistory = record.timerEnabled,
- historyInterval = readHistoryInterval(record)
+ val temperature = readTemperature(record).fold(
+ onFailure = {
+ return Result.failure(it)
+ },
+ onSuccess = { return@fold it }
+ )
+
+ val history = readHistoryInterval(record).fold(
+ onFailure = {
+ return Result.failure(it)
+ },
+ onSuccess = { return@fold it }
+ )
+
+ return Result.success(
+ Ble.Thermometer.ThermometerState(
+ temperature = temperature,
+ saveHistory = record.timerEnabled,
+ historyInterval = history
+ )
)
}
private suspend fun readTemperature(
record: ScanResult
- ): Float {
+ ): Result {
val dataResult = readCharacteristic(
device = record.device,
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
characteristicId = UUID.fromString("00002a6e-0000-1000-8000-00805f9b34fb")
+ ).fold(
+ onFailure = {
+ return Result.failure(it)
+ },
+ onSuccess = { return@fold it }
)
- return (dataResult[0] + dataResult[1] * 256).toFloat() / 100f
+ return Result.success((dataResult[0] + dataResult[1] * 256).toFloat() / 100f)
}
private suspend fun readHistoryInterval(
record: ScanResult
- ): Long {
+ ): Result {
writeCharacteristic(
device = record.device,
@@ -243,19 +289,26 @@ class BleRepositoryImpl @Inject constructor(
device = record.device,
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb")
+ ).fold(
+ onFailure = {
+ return Result.failure(it)
+ },
+ onSuccess = { return@fold it }
)
- return if(dataResult.size == 4){
- dataResult.getUIntAt(0).toLong()
- }else{
- 0
- }
+ return Result.success(
+ if(dataResult.size == 4){
+ dataResult.getUIntAt(0).toLong()
+ }else{
+ 0
+ }
+ )
}
override suspend fun getTemperatureHistoryBySerial(
serial: String
- ): List {
+ ): Flow>, BleException>> = flow {
fun ByteArray.getUIntAt(idx: Int) =
((this[idx + 3].toUInt() and 0xFFu) shl 24) or
@@ -265,6 +318,8 @@ class BleRepositoryImpl @Inject constructor(
deviceCache[serial]?.device?.let { device ->
+ emit(Result.success(ProgressState.Indeterminate))
+
writeCharacteristic(
device = device,
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
@@ -276,6 +331,12 @@ class BleRepositoryImpl @Inject constructor(
device = device,
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb"),
+ ).fold(
+ onFailure = {
+ emit(Result.failure(it))
+ return@flow
+ },
+ onSuccess = { return@fold it }
)
writeCharacteristic(
@@ -295,6 +356,12 @@ class BleRepositoryImpl @Inject constructor(
device = device,
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb"),
+ ).fold(
+ onFailure = {
+ emit(Result.failure(it))
+ return@flow
+ },
+ onSuccess = { return@fold it }
)
if(firstPackageResponse[0] == 250.toByte()){
@@ -311,11 +378,14 @@ class BleRepositoryImpl @Inject constructor(
(it[0] + it[1] * 256).toFloat() / 100f
}.toMutableList()
- Log.d("read", temperaturePackage.size.toString())
+ var dataCount = firstPackageResponse[1].toUByte()
+ val totalDataSize = dataCount.toInt() + temperaturePackage.size
- var dataCount = firstPackageResponse[1]
+ emit(Result.success(ProgressState.Progress(0f / totalDataSize.toFloat())))
+ delay(100)
+ emit(Result.success(ProgressState.Progress(dataCount.toFloat() / totalDataSize.toFloat())))
- while(dataCount != 0.toByte()){
+ while(dataCount != 0.toUByte()){
writeCharacteristic(
device = device,
@@ -328,9 +398,15 @@ class BleRepositoryImpl @Inject constructor(
device = device,
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
characteristicId = UUID.fromString("0000b2d8-0000-1000-8000-00805f9b34fb"),
+ ).fold(
+ onFailure = {
+ emit(Result.failure(it))
+ return@flow
+ },
+ onSuccess = { return@fold it }
)
- dataCount = readResponse.get(1)
+ dataCount = readResponse[1].toUByte()
temperatureDataArray = readResponse.toList().subList(2, readResponse.size)
@@ -340,25 +416,27 @@ class BleRepositoryImpl @Inject constructor(
}
)
- Log.d("read",(temperatureDataArray.size / 2).toString())
+ emit(Result.success(ProgressState.Progress(totalDataSize.toFloat() / temperaturePackage.size.toFloat())))
}
- Log.d("metadata", interval.toString() + " " + lastMeasureSystemTime.toString())
-
- return temperaturePackage.withIndex().map {
- Ble.Thermometer.MeasurePoint(
- date = lastMeasureSystemTime - (((temperaturePackage.size - 1) - it.index) * interval),
- value = it.value
+ emit(
+ Result.success(
+ ProgressState.Finished(
+ temperaturePackage.withIndex().map {
+ Ble.Thermometer.MeasurePoint(
+ date = lastMeasureSystemTime - (((temperaturePackage.size - 1) - it.index) * interval),
+ value = it.value
+ )
+ }
+ )
)
- }
+ )
}
}
- return emptyList()
-
}
override suspend fun writeBle(ble: Ble) {
@@ -381,6 +459,9 @@ class BleRepositoryImpl @Inject constructor(
request.saveHistory?.let { writeSaveEnabled(result.device, it) }
+ deviceCache.remove(serial)
+ resultList.remove(serial)
+
}
}
@@ -457,24 +538,26 @@ class BleRepositoryImpl @Inject constructor(
private suspend fun writeSaveEnabled(
device: BluetoothDevice,
enabled: Boolean
- ) {
+ ): Result {
writeCharacteristic(
device = device,
serviceId = UUID.fromString("a77db03a-9bc4-11ed-a8fc-0242ac120002"),
characteristicId = UUID.fromString("0000b6f2-0000-1000-8000-00805f9b34fb"),
- writeData = mutableListOf(3).apply {
+ writeData = mutableListOf(4).apply {
add(if(enabled) 1 else 0)
}.toByteArray()
)
+ return Result.success(Unit)
+
}
private suspend fun readCharacteristic(
device: BluetoothDevice,
serviceId: UUID,
characteristicId: UUID
- ): ByteArray = suspendCoroutine {
+ ): Result = suspendCancellableCoroutine {
val callback = object : BluetoothGattCallback() {
@@ -492,10 +575,10 @@ class BleRepositoryImpl @Inject constructor(
) == PackageManager.PERMISSION_GRANTED
) {
gatt?.discoverServices()
+ } else {
+ it.resume(Result.failure(BleException.PermissionDenied))
}
- } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
-
}
}
@@ -512,16 +595,16 @@ class BleRepositoryImpl @Inject constructor(
service.uuid == serviceId
}?.characteristics?.firstOrNull { characteristic ->
characteristic.uuid == characteristicId
- }?.let {
+ }?.let { char ->
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || ActivityCompat.checkSelfPermission(
app,
Manifest.permission.BLUETOOTH_CONNECT
) == PackageManager.PERMISSION_GRANTED
) {
-
- gatt.readCharacteristic(it)
-
+ gatt.readCharacteristic(char)
+ } else {
+ it.resume(Result.failure(BleException.PermissionDenied))
}
}
@@ -537,14 +620,29 @@ class BleRepositoryImpl @Inject constructor(
status: Int
) {
super.onCharacteristicRead(gatt, characteristic, value, status)
-
- it.resume(value)
-
+ if (ActivityCompat.checkSelfPermission(
+ app,
+ Manifest.permission.BLUETOOTH_CONNECT
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ it.resume(Result.failure(BleException.PermissionDenied))
+ }else {
+ gatt.disconnect()
+ it.resume(Result.success(value))
+ }
}
}
- device.connectGatt(app, true, callback)
+ if (ActivityCompat.checkSelfPermission(
+ app,
+ Manifest.permission.BLUETOOTH_CONNECT
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ it.resume(Result.failure(BleException.PermissionDenied))
+ } else {
+ device.connectGatt(app, true, callback)
+ }
}
@@ -553,7 +651,7 @@ class BleRepositoryImpl @Inject constructor(
serviceId: UUID,
characteristicId: UUID,
writeData: ByteArray
- ) = suspendCoroutine {
+ ) = suspendCancellableCoroutine {
val callback = object : BluetoothGattCallback() {
@@ -573,8 +671,6 @@ class BleRepositoryImpl @Inject constructor(
gatt?.discoverServices()
}
- } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
-
}
}
@@ -591,7 +687,7 @@ class BleRepositoryImpl @Inject constructor(
service.uuid == serviceId
}?.characteristics?.firstOrNull { characteristic ->
characteristic.uuid == characteristicId
- }?.let {
+ }?.let { char ->
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S || ActivityCompat.checkSelfPermission(
app,
@@ -600,10 +696,10 @@ class BleRepositoryImpl @Inject constructor(
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- gatt.writeCharacteristic(it, writeData, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
+ gatt.writeCharacteristic(char, writeData, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT)
}else{
- it.value = writeData
- gatt.writeCharacteristic(it)
+ char.value = writeData
+ gatt.writeCharacteristic(char)
}
}
@@ -620,7 +716,17 @@ class BleRepositoryImpl @Inject constructor(
status: Int
) {
super.onCharacteristicWrite(gatt, characteristic, status)
- it.resume(Unit)
+ if (ActivityCompat.checkSelfPermission(
+ app,
+ Manifest.permission.BLUETOOTH_CONNECT
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ return
+ } else {
+ gatt.disconnect()
+ it.resume(Unit)
+ }
+
}
}
diff --git a/app/src/main/java/llc/arma/ble/domain/common/BleException.kt b/app/src/main/java/llc/arma/ble/domain/common/BleException.kt
new file mode 100644
index 0000000..07bf6da
--- /dev/null
+++ b/app/src/main/java/llc/arma/ble/domain/common/BleException.kt
@@ -0,0 +1,7 @@
+package llc.arma.ble.domain.common
+
+sealed class BleException {
+
+ object PermissionDenied : BleException()
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/llc/arma/ble/domain/common/ProgressState.kt b/app/src/main/java/llc/arma/ble/domain/common/ProgressState.kt
new file mode 100644
index 0000000..d9bc9e3
--- /dev/null
+++ b/app/src/main/java/llc/arma/ble/domain/common/ProgressState.kt
@@ -0,0 +1,15 @@
+package llc.arma.ble.domain.common
+
+sealed class ProgressState {
+
+ object Indeterminate : ProgressState()
+
+ data class Progress(
+ val value: Float
+ ) : ProgressState()
+
+ data class Finished(
+ val data: T
+ ) : ProgressState()
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/llc/arma/ble/domain/repository/BleRepository.kt b/app/src/main/java/llc/arma/ble/domain/repository/BleRepository.kt
index 9fff913..eb24680 100644
--- a/app/src/main/java/llc/arma/ble/domain/repository/BleRepository.kt
+++ b/app/src/main/java/llc/arma/ble/domain/repository/BleRepository.kt
@@ -2,17 +2,19 @@ package llc.arma.ble.domain.repository
import kotlinx.coroutines.flow.Flow
import llc.arma.ble.domain.Result
+import llc.arma.ble.domain.common.BleException
+import llc.arma.ble.domain.common.ProgressState
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.usecase.GetBleBySerial
interface BleRepository {
- fun getBleAroundFlow(): Flow>
+ fun getBleAroundFlow(): Flow, BleException>>
suspend fun getBleBySerial(serial: String): Result
- suspend fun getTemperatureHistoryBySerial(serial: String): List
+ suspend fun getTemperatureHistoryBySerial(serial: String): Flow>, BleException>>
suspend fun writeBle(ble: Ble)
diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/GetBleAroundFlow.kt b/app/src/main/java/llc/arma/ble/domain/usecase/GetBleAroundFlow.kt
index a25a75b..a594369 100644
--- a/app/src/main/java/llc/arma/ble/domain/usecase/GetBleAroundFlow.kt
+++ b/app/src/main/java/llc/arma/ble/domain/usecase/GetBleAroundFlow.kt
@@ -1,6 +1,8 @@
package llc.arma.ble.domain.usecase
import kotlinx.coroutines.flow.Flow
+import llc.arma.ble.domain.Result
+import llc.arma.ble.domain.common.BleException
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.model.BleInfo
import llc.arma.ble.domain.repository.BleRepository
@@ -10,6 +12,6 @@ class GetBleAroundFlow @Inject constructor(
private val bleRepository: BleRepository
) {
- operator fun invoke(): Flow> = bleRepository.getBleAroundFlow()
+ operator fun invoke(): Flow, BleException>> = bleRepository.getBleAroundFlow()
}
\ No newline at end of file
diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/GetTemperatureHistoryBySerial.kt b/app/src/main/java/llc/arma/ble/domain/usecase/GetTemperatureHistoryBySerial.kt
index af8899a..8979043 100644
--- a/app/src/main/java/llc/arma/ble/domain/usecase/GetTemperatureHistoryBySerial.kt
+++ b/app/src/main/java/llc/arma/ble/domain/usecase/GetTemperatureHistoryBySerial.kt
@@ -1,5 +1,9 @@
package llc.arma.ble.domain.usecase
+import kotlinx.coroutines.flow.Flow
+import llc.arma.ble.domain.Result
+import llc.arma.ble.domain.common.BleException
+import llc.arma.ble.domain.common.ProgressState
import llc.arma.ble.domain.model.Ble
import llc.arma.ble.domain.repository.BleRepository
import javax.inject.Inject
@@ -8,7 +12,7 @@ class GetTemperatureHistoryBySerial @Inject constructor(
private val bleRepository: BleRepository
) {
- suspend operator fun invoke(serial: String): List {
+ suspend operator fun invoke(serial: String): Flow>, BleException>> {
return bleRepository.getTemperatureHistoryBySerial(serial)
diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/WriteBle.kt b/app/src/main/java/llc/arma/ble/domain/usecase/WriteBle.kt
index 7497509..8e876f3 100644
--- a/app/src/main/java/llc/arma/ble/domain/usecase/WriteBle.kt
+++ b/app/src/main/java/llc/arma/ble/domain/usecase/WriteBle.kt
@@ -13,7 +13,10 @@ class WriteBle @Inject constructor(
bleRepository.writeBle(ble)
}
- suspend operator fun invoke(serial: String, request: Ble.Thermometer.WriteRequest){
+ suspend operator fun invoke(
+ serial: String,
+ request: Ble.Thermometer.WriteRequest
+ ){
bleRepository.writeBle(serial, request)
}