From 549b62582089a30a7bb0571819d9a86529b34aa5 Mon Sep 17 00:00:00 2001 From: Vineyro Date: Fri, 5 Jul 2024 17:00:32 +0700 Subject: [PATCH] rotations save --- app/build.gradle | 4 + .../ble/app/framework/di/DatabaseModule.kt | 30 ++ .../ble/app/framework/di/RepositoryBinding.kt | 11 +- .../java/llc/arma/ble/app/ui/MainActivity.kt | 34 +- .../screen/connection/ConnectionContract.kt | 4 + .../ui/screen/connection/ConnectionScreen.kt | 4 +- .../accelerometer/view/AcceleromterHistory.kt | 126 +++-- .../arma/ble/app/ui/screen/main/MainScreen.kt | 39 +- .../delete/RotationStatisticContract.kt | 30 ++ .../delete/RotationStatisticScreen.kt | 118 +++++ .../delete/RotationStatisticViewModel.kt | 67 +++ .../statistic/RotationStatisticContract.kt | 69 +++ .../statistic/RotationStatisticScreen.kt | 496 ++++++++++++++++++ .../statistic/RotationStatisticViewModel.kt | 256 +++++++++ .../java/llc/arma/ble/data/db/AppDatabase.kt | 16 + .../java/llc/arma/ble/data/db/RotationsDao.kt | 31 ++ .../llc/arma/ble/data/model/RotationEntity.kt | 19 + .../llc/arma/ble/data/model/WheelEntity.kt | 18 + .../{ => repository}/BleRepositoryImpl.kt | 28 +- .../{ => repository}/EmailRepositoryImpl.kt | 2 +- .../GetAccelerometerHistory.kt | 12 +- .../GetAccelerometerRealtimeData.kt | 9 +- .../ReadAccelerometerSpectreCallback.kt | 19 +- .../ReadTemperatureHistoryCallback.kt | 15 +- .../repository/RotationsRepositoryImpl.kt | 49 ++ .../{ => repository}/XlsxRepositoryImpl.kt | 3 +- .../extensions/ApplicationExtension.kt | 2 +- .../extensions/BleEnumExtensions.kt | 2 +- .../extensions/BleScanResultExtensions.kt | 2 +- .../extensions/ByteArrayExtensions.kt | 2 +- .../llc/arma/ble/domain/model/Rotation.kt | 14 + .../domain/repository/RotationsRepository.kt | 17 + .../domain/usecase/DeleteRotationsBySerial.kt | 17 + .../GetAccelerometerHistoryBySerial.kt | 33 +- .../domain/usecase/GetRotationsBySerial.kt | 17 + .../domain/usecase/GetWheelRadiusBySerial.kt | 14 + .../arma/ble/domain/usecase/SetWheelRadius.kt | 14 + 37 files changed, 1514 insertions(+), 129 deletions(-) create mode 100644 app/src/main/java/llc/arma/ble/app/framework/di/DatabaseModule.kt create mode 100644 app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticContract.kt create mode 100644 app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticScreen.kt create mode 100644 app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticViewModel.kt create mode 100644 app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticContract.kt create mode 100644 app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticScreen.kt create mode 100644 app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticViewModel.kt create mode 100644 app/src/main/java/llc/arma/ble/data/db/AppDatabase.kt create mode 100644 app/src/main/java/llc/arma/ble/data/db/RotationsDao.kt create mode 100644 app/src/main/java/llc/arma/ble/data/model/RotationEntity.kt create mode 100644 app/src/main/java/llc/arma/ble/data/model/WheelEntity.kt rename app/src/main/java/llc/arma/ble/data/{ => repository}/BleRepositoryImpl.kt (96%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/EmailRepositoryImpl.kt (96%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/GetAccelerometerHistory.kt (96%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/GetAccelerometerRealtimeData.kt (95%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/ReadAccelerometerSpectreCallback.kt (92%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/ReadTemperatureHistoryCallback.kt (91%) create mode 100644 app/src/main/java/llc/arma/ble/data/repository/RotationsRepositoryImpl.kt rename app/src/main/java/llc/arma/ble/data/{ => repository}/XlsxRepositoryImpl.kt (98%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/extensions/ApplicationExtension.kt (94%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/extensions/BleEnumExtensions.kt (97%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/extensions/BleScanResultExtensions.kt (96%) rename app/src/main/java/llc/arma/ble/data/{ => repository}/extensions/ByteArrayExtensions.kt (95%) create mode 100644 app/src/main/java/llc/arma/ble/domain/model/Rotation.kt create mode 100644 app/src/main/java/llc/arma/ble/domain/repository/RotationsRepository.kt create mode 100644 app/src/main/java/llc/arma/ble/domain/usecase/DeleteRotationsBySerial.kt create mode 100644 app/src/main/java/llc/arma/ble/domain/usecase/GetRotationsBySerial.kt create mode 100644 app/src/main/java/llc/arma/ble/domain/usecase/GetWheelRadiusBySerial.kt create mode 100644 app/src/main/java/llc/arma/ble/domain/usecase/SetWheelRadius.kt diff --git a/app/build.gradle b/app/build.gradle index 63bd607..a1a22f4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -96,6 +96,10 @@ dependencies { implementation "com.patrykandpatrick.vico:compose:1.7.1" implementation "com.patrykandpatrick.vico:compose-m3:1.7.1" + implementation "androidx.room:room-runtime:2.6.1" + kapt("androidx.room:room-compiler:2.6.1") + implementation("androidx.room:room-ktx:2.6.1") + implementation files('libs/poishadow-all.jar') } \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/app/framework/di/DatabaseModule.kt b/app/src/main/java/llc/arma/ble/app/framework/di/DatabaseModule.kt new file mode 100644 index 0000000..2a56b67 --- /dev/null +++ b/app/src/main/java/llc/arma/ble/app/framework/di/DatabaseModule.kt @@ -0,0 +1,30 @@ +package llc.arma.ble.app.framework.di + +import android.app.Application +import androidx.room.Room +import androidx.room.RoomDatabase +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import llc.arma.ble.data.db.AppDatabase +import llc.arma.ble.data.db.RotationsDao +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class DatabaseModule { + + @Provides + @Singleton + fun provideDatabase(app: Application): AppDatabase { + return Room.databaseBuilder(app, AppDatabase::class.java, "app-database").build() + } + + @Provides + @Singleton + fun provideRotationsDao(db: AppDatabase): RotationsDao { + return db.getRotationsDao() + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/app/framework/di/RepositoryBinding.kt b/app/src/main/java/llc/arma/ble/app/framework/di/RepositoryBinding.kt index 024e35f..a779882 100644 --- a/app/src/main/java/llc/arma/ble/app/framework/di/RepositoryBinding.kt +++ b/app/src/main/java/llc/arma/ble/app/framework/di/RepositoryBinding.kt @@ -4,11 +4,13 @@ import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import llc.arma.ble.data.BleRepositoryImpl -import llc.arma.ble.data.EmailRepositoryImpl -import llc.arma.ble.data.XlsxRepositoryImpl +import llc.arma.ble.data.repository.BleRepositoryImpl +import llc.arma.ble.data.repository.EmailRepositoryImpl +import llc.arma.ble.data.repository.RotationsRepositoryImpl +import llc.arma.ble.data.repository.XlsxRepositoryImpl import llc.arma.ble.domain.repository.BleRepository import llc.arma.ble.domain.repository.EmailRepository +import llc.arma.ble.domain.repository.RotationsRepository import llc.arma.ble.domain.repository.XlsxRepository @Module @@ -21,6 +23,9 @@ interface RepositoryBinding { @Binds fun bindEmailRepository(repository: EmailRepositoryImpl): EmailRepository + @Binds + fun bindRotationsRepository(repository: RotationsRepositoryImpl): RotationsRepository + @Binds fun bindXlsxRepository(repository: XlsxRepositoryImpl): XlsxRepository diff --git a/app/src/main/java/llc/arma/ble/app/ui/MainActivity.kt b/app/src/main/java/llc/arma/ble/app/ui/MainActivity.kt index 29ce8a1..7953b55 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/MainActivity.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/MainActivity.kt @@ -7,15 +7,19 @@ import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothManager import android.content.Context import android.content.Intent -import android.content.pm.PackageManager +import android.hardware.camera2.CameraCharacteristics +import android.hardware.camera2.CameraManager import android.os.Build import android.os.Bundle +import android.view.SurfaceView +import android.view.View import androidx.activity.ComponentActivity import androidx.activity.compose.BackHandler import androidx.activity.compose.setContent import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ModalBottomSheetLayout import androidx.compose.material.ModalBottomSheetValue @@ -28,8 +32,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.unit.dp -import androidx.core.app.ActivityCompat -import androidx.core.app.ActivityCompat.startActivityForResult +import androidx.compose.ui.viewinterop.AndroidView import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowCompat import androidx.lifecycle.Lifecycle @@ -231,19 +234,20 @@ class MainActivity : ComponentActivity() { } @Composable -fun OnLifecycleEvent(onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit) { - val eventHandler = rememberUpdatedState(onEvent) - val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) +fun Camera(){ - DisposableEffect(lifecycleOwner.value) { - val lifecycle = lifecycleOwner.value.lifecycle - val observer = LifecycleEventObserver { owner, event -> - eventHandler.value(owner, event) - } + AndroidView( + factory = { + val cameraManager = it.getSystemService(CameraManager::class.java) - lifecycle.addObserver(observer) - onDispose { - lifecycle.removeObserver(observer) + cameraManager.cameraIdList.forEach { + + println("$it is front: ${cameraManager.getCameraCharacteristics(it).get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT}") + + } + + return@AndroidView SurfaceView(it) } - } + ) + } \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/connection/ConnectionContract.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/connection/ConnectionContract.kt index 3592198..2a84526 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/connection/ConnectionContract.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/connection/ConnectionContract.kt @@ -66,6 +66,10 @@ class ConnectionContract { val serial: String ) : Navigation() + data class NavigateToRotationsStatistic( + val serial: String + ) : Navigation() + } sealed class InnerNavigation : Effect() { 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 ef1abca..f86040e 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 @@ -184,7 +184,9 @@ fun ConnectionScreen( onDismiss = { innerScreen = null } - ) + ){ + onNavigationEvent(ConnectionContract.Effect.Navigation.NavigateToRotationsStatistic(it.ble.serial)) + } } diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterHistory.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterHistory.kt index 294f468..8511887 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterHistory.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/accelerometer/view/AcceleromterHistory.kt @@ -26,6 +26,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.ArrowBack import androidx.compose.material.icons.rounded.CloudUpload import androidx.compose.material.icons.rounded.Refresh +import androidx.compose.material.icons.rounded.TableView import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.text.style.TextAlign import com.patrykandpatrick.vico.compose.axis.axisGuidelineComponent @@ -71,6 +72,7 @@ class AccelEntry( } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun AccelerometerHistory( ble: BleInfo, @@ -79,7 +81,8 @@ fun AccelerometerHistory( fftAxis: FftAxis, fftMode: FftViewMode, frequency: FftFrequency, - onDismiss: (() -> Unit)? = null + onDismiss: (() -> Unit)? = null, + onShowStatistic: () -> Unit, ) { val viewModel = hiltViewModel() @@ -95,74 +98,85 @@ fun AccelerometerHistory( } }*/ - Column( - modifier = Modifier.fillMaxHeight(0.9f) - ) { + Column() { - Row( - modifier = Modifier.padding(horizontal = 12.dp), - verticalAlignment = Alignment.CenterVertically - ) { + TopAppBar( + navigationIcon = { + onDismiss?.let { - onDismiss?.let { + IconButton(onClick = it) { + Icon( + imageVector = Icons.Rounded.ArrowBack, + contentDescription = null + ) + } - IconButton(onClick = it) { + } + }, + title = { + val title = when(state){ + is AccelerometerHistoryContract.State.Display -> { + when (state.loadingHistoryState) { + is ProgressState.Finished -> "${accelMode.localized} (${state.loadingHistoryState.data.size})" + is ProgressState.Indeterminate -> accelMode.localized + is ProgressState.Progress -> accelMode.localized + } + } + AccelerometerHistoryContract.State.Exception -> accelMode.localized + } + + Text( + modifier = Modifier.weight(1f), + text = title, + style = MaterialTheme.typography.titleLarge + ) + }, + actions = { + + IconButton( + onClick = onShowStatistic, + enabled = when(state){ + is AccelerometerHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished + AccelerometerHistoryContract.State.Exception -> false + } + ) { Icon( - imageVector = Icons.Rounded.ArrowBack, + imageVector = Icons.Rounded.TableView, contentDescription = null ) } - } - - val title = when(state){ - is AccelerometerHistoryContract.State.Display -> { - when (state.loadingHistoryState) { - is ProgressState.Finished -> "${accelMode.localized} (${state.loadingHistoryState.data.size})" - is ProgressState.Indeterminate -> accelMode.localized - is ProgressState.Progress -> accelMode.localized + IconButton( + onClick = { + viewModel.setEvent(AccelerometerHistoryContract.Event.OnExport) + }, + enabled = when(state){ + is AccelerometerHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished + AccelerometerHistoryContract.State.Exception -> false } + ) { + Icon( + imageVector = Icons.Rounded.CloudUpload, + contentDescription = null + ) } - AccelerometerHistoryContract.State.Exception -> accelMode.localized - } - Text( - modifier = Modifier.weight(1f), - text = title, - style = MaterialTheme.typography.titleLarge - ) - - IconButton( - onClick = { - viewModel.setEvent(AccelerometerHistoryContract.Event.OnExport) - }, - enabled = when(state){ - is AccelerometerHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished - AccelerometerHistoryContract.State.Exception -> false + IconButton( + onClick = { + viewModel.setEvent(AccelerometerHistoryContract.Event.OnRefreshHistory(ble.name, ble.serial, accelScale, accelMode, fftAxis, fftMode, frequency)) + }, + enabled = when(state){ + is AccelerometerHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished + AccelerometerHistoryContract.State.Exception -> true + } + ) { + Icon( + imageVector = Icons.Rounded.Refresh, + contentDescription = null + ) } - ) { - Icon( - imageVector = Icons.Rounded.CloudUpload, - contentDescription = null - ) } - - IconButton( - onClick = { - viewModel.setEvent(AccelerometerHistoryContract.Event.OnRefreshHistory(ble.name, ble.serial, accelScale, accelMode, fftAxis, fftMode, frequency)) - }, - enabled = when(state){ - is AccelerometerHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished - AccelerometerHistoryContract.State.Exception -> true - } - ) { - Icon( - imageVector = Icons.Rounded.Refresh, - contentDescription = null - ) - } - - } + ) Spacer(modifier = Modifier.height(16.dp)) diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/main/MainScreen.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/main/MainScreen.kt index eff2554..fdd4568 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/main/MainScreen.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/main/MainScreen.kt @@ -15,6 +15,10 @@ import llc.arma.ble.app.ui.screen.connection.ConnectionContract import llc.arma.ble.app.ui.screen.connection.ConnectionScreen import llc.arma.ble.app.ui.screen.password.ChangePasswordContract import llc.arma.ble.app.ui.screen.password.ChangePasswordScreen +import llc.arma.ble.app.ui.screen.rotation.delete.RotationDeleteContract +import llc.arma.ble.app.ui.screen.rotation.delete.RotationDeleteScreen +import llc.arma.ble.app.ui.screen.rotation.statistic.RotationStatisticContract +import llc.arma.ble.app.ui.screen.rotation.statistic.RotationStatisticScreen @Composable fun MainScreen() { @@ -49,7 +53,10 @@ fun MainScreen() { onNavigationEvent = { when(it){ ConnectionContract.Effect.Navigation.NavigateUp -> controller.navigateUp() - is ConnectionContract.Effect.Navigation.NavigateToChangePassword -> controller.navigate("change_password/${it.serial}") + is ConnectionContract.Effect.Navigation.NavigateToChangePassword -> + controller.navigate("change_password/${it.serial}") + is ConnectionContract.Effect.Navigation.NavigateToRotationsStatistic -> + controller.navigate("rotation_statistic/${it.serial}") } } ) @@ -57,6 +64,36 @@ fun MainScreen() { } ) + composable( + route = "rotation_statistic/{serial}", + content = { + + RotationStatisticScreen { + when(it){ + is RotationStatisticContract.Effect.Navigation.NavigateToDelete -> { + controller.navigate("rotation_delete/${it.serial}") + } + RotationStatisticContract.Effect.Navigation.NavigateUp -> { + controller.navigateUp() + } + } + } + + } + ) + + dialog( + route = "rotation_delete/{serial}", + dialogProperties = DialogProperties(usePlatformDefaultWidth = false), + content = { + RotationDeleteScreen { + when(it){ + RotationDeleteContract.Effect.Navigation.NavigateUp -> controller.navigateUp() + } + } + } + ) + dialog( route = "change_password/{serial}", dialogProperties = DialogProperties(usePlatformDefaultWidth = false), diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticContract.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticContract.kt new file mode 100644 index 0000000..a42c416 --- /dev/null +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticContract.kt @@ -0,0 +1,30 @@ +package llc.arma.ble.app.ui.screen.rotation.delete + +import llc.arma.ble.app.ui.common.ViewEvent +import llc.arma.ble.app.ui.common.ViewSideEffect +import llc.arma.ble.app.ui.common.ViewState +import llc.arma.ble.domain.model.Rotation + +class RotationDeleteContract { + + sealed class Event : ViewEvent { + + object OnNavigateUp : Event() + + object OnDelete : Event() + + } + + object State : ViewState + + sealed class Effect : ViewSideEffect { + + sealed class Navigation : Effect(){ + + object NavigateUp : Navigation() + + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticScreen.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticScreen.kt new file mode 100644 index 0000000..1c8979d --- /dev/null +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticScreen.kt @@ -0,0 +1,118 @@ +package llc.arma.ble.app.ui.screen.rotation.delete + +import android.icu.text.SimpleDateFormat +import androidx.compose.foundation.clickable +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.ArrowBack +import androidx.compose.material.icons.rounded.Delete +import androidx.compose.material3.Card +import androidx.compose.material3.DatePicker +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextField +import androidx.compose.material3.rememberDatePickerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import androidx.hilt.navigation.compose.hiltViewModel +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import llc.arma.ble.app.ui.screen.rotation.statistic.RotationStatisticContract +import java.util.Date +import java.util.concurrent.TimeUnit +import kotlin.math.absoluteValue +import kotlin.math.pow +import kotlin.math.roundToInt + +@Composable +fun RotationDeleteScreen( + onNavigation: (RotationDeleteContract.Effect.Navigation) -> Unit +) { + + val viewModel = hiltViewModel() + + LaunchedEffect(Unit) { + viewModel.effect.onEach { + when(it){ + is RotationDeleteContract.Effect.Navigation -> onNavigation(it) + } + }.launchIn(this) + } + + Surface( + shape = RoundedCornerShape(16.dp) + ) { + + Column( + modifier = Modifier.padding(16.dp) + ) { + + Text( + style = MaterialTheme.typography.titleLarge, + text = "Удалить сохраненные записи?" + ) + + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End), + modifier = Modifier + .align(Alignment.End) + ) { + + TextButton( + onClick = { + viewModel.setEvent( + RotationDeleteContract.Event.OnNavigateUp + ) + } + ) { + Text(text = "Отмена") + } + + Button( + onClick = { + viewModel.setEvent( + RotationDeleteContract.Event.OnDelete + ) + } + ) { + Text(text = "Удалить") + } + + } + + } + + } + +} diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticViewModel.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticViewModel.kt new file mode 100644 index 0000000..144dceb --- /dev/null +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/delete/RotationStatisticViewModel.kt @@ -0,0 +1,67 @@ +package llc.arma.ble.app.ui.screen.rotation.delete + +import android.icu.util.GregorianCalendar +import android.util.Log +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import llc.arma.ble.app.ui.common.BaseViewModel +import llc.arma.ble.domain.usecase.DeleteRotationsBySerial +import llc.arma.ble.domain.usecase.GetRotationsBySerial +import llc.arma.ble.domain.usecase.GetWheelRadiusBySerial +import llc.arma.ble.domain.usecase.SetWheelRadius +import java.util.concurrent.TimeUnit +import javax.inject.Inject +import kotlin.math.absoluteValue + + +@HiltViewModel +class RotationDeleteViewModel @Inject constructor( + private val savedStateHandle: SavedStateHandle, + private val deleteRotationsBySerial: DeleteRotationsBySerial +) : BaseViewModel() { + + override fun setInitialState() = RotationDeleteContract.State + + override fun handleEvents(event: RotationDeleteContract.Event) { + when(event){ + is RotationDeleteContract.Event.OnDelete -> reduce(viewState.value, event) + is RotationDeleteContract.Event.OnNavigateUp -> reduce(viewState.value, event) + } + } + + + private fun reduce( + state: RotationDeleteContract.State, + event: RotationDeleteContract.Event.OnNavigateUp + ) { + + setEffect { + + RotationDeleteContract.Effect.Navigation.NavigateUp + + } + + } + + private fun reduce( + state: RotationDeleteContract.State, + event: RotationDeleteContract.Event.OnDelete + ) { + + viewModelScope.launch { + + deleteRotationsBySerial(savedStateHandle.get("serial")!!) + + } + + setEffect { + + RotationDeleteContract.Effect.Navigation.NavigateUp + + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticContract.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticContract.kt new file mode 100644 index 0000000..b890e4c --- /dev/null +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticContract.kt @@ -0,0 +1,69 @@ +package llc.arma.ble.app.ui.screen.rotation.statistic + +import llc.arma.ble.app.ui.common.ViewEvent +import llc.arma.ble.app.ui.common.ViewSideEffect +import llc.arma.ble.app.ui.common.ViewState +import llc.arma.ble.domain.model.Rotation + +class RotationStatisticContract { + + sealed class Event : ViewEvent { + + object OnNavigateUp : Event() + + object OnNavigateToDelete : Event() + + data class OnRadiusChanged( + val radius: Long? + ): Event() + + data class OnStartDateChanged( + val start: Long? + ): Event() + + data class OnStopDateChanged( + val stop: Long? + ): Event() + + } + + sealed class State : ViewState { + + object Loading : State() + + data class Display( + val rotations: List, + val ranges: List, + val radius: Long?, + val startDate: Long?, + val endDate: Long? + ) : State() { + + data class RotationRange( + val distance: Double, + val startDate: Long, + val endDate: Long, + val maxSpeed: Double, + val avgSpeed: Double, + val rotations: Float, + ) + + } + + } + + sealed class Effect : ViewSideEffect { + + sealed class Navigation : Effect(){ + + object NavigateUp : Navigation() + + data class NavigateToDelete( + val serial: String + ) : Navigation() + + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticScreen.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticScreen.kt new file mode 100644 index 0000000..ff95f16 --- /dev/null +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticScreen.kt @@ -0,0 +1,496 @@ +package llc.arma.ble.app.ui.screen.rotation.statistic + +import android.icu.text.SimpleDateFormat +import androidx.compose.foundation.clickable +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Button +import androidx.compose.material3.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.ArrowBack +import androidx.compose.material.icons.rounded.ArrowForward +import androidx.compose.material.icons.rounded.Delete +import androidx.compose.material3.Card +import androidx.compose.material3.DatePicker +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.TextField +import androidx.compose.material3.rememberDatePickerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +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.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import androidx.hilt.navigation.compose.hiltViewModel +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import java.util.Date +import java.util.concurrent.TimeUnit +import kotlin.math.absoluteValue +import kotlin.math.pow +import kotlin.math.roundToInt + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun RotationStatisticScreen( + onNavigation: (RotationStatisticContract.Effect.Navigation) -> Unit +) { + + val viewModel = hiltViewModel() + val state = viewModel.viewState.value + + LaunchedEffect(Unit) { + viewModel.effect.onEach { + when(it){ + is RotationStatisticContract.Effect.Navigation -> onNavigation(it) + } + }.launchIn(this) + } + + Column( + + modifier = Modifier.fillMaxSize() + ) { + + TopAppBar( + navigationIcon = { + IconButton( + onClick = { + viewModel.setEvent(RotationStatisticContract.Event.OnNavigateUp) + } + ) { + Icon( + imageVector = Icons.Rounded.ArrowBack, + contentDescription = null + ) + } + }, + title = { + Text( + modifier = Modifier.weight(1f), + text = "Обороты", + style = MaterialTheme.typography.titleLarge + ) + }, + actions = { + IconButton( + onClick = { + viewModel.setEvent(RotationStatisticContract.Event.OnNavigateToDelete) + } + ) { + Icon( + imageVector = Icons.Rounded.Delete, + contentDescription = null + ) + } + } + ) + + Column( + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.padding(12.dp) + ) { + + if(state is RotationStatisticContract.State.Display){ + + var showStartDateSelector by remember { + mutableStateOf(false) + } + + var showEndDateSelector by remember { + mutableStateOf(false) + } + + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + + Box( + modifier = Modifier + .weight(1f) + .width(IntrinsicSize.Max) + .height(IntrinsicSize.Max) + ) { + + TextField( + readOnly = true, + value = dateFormat.format(Date(state.startDate ?: state.ranges.minOfOrNull { it.startDate } ?: 0)), + onValueChange = {}, + label = { + Text(text = "Начало") + }, + + ) + + Box( + modifier = Modifier + .fillMaxSize() + .clickable { showStartDateSelector = true } + ) {} + + } + + Box( + modifier = Modifier + .weight(1f) + .width(IntrinsicSize.Max) + .height(IntrinsicSize.Max) + ) { + + TextField( + readOnly = true, + value = dateFormat.format(Date(state.endDate ?: state.ranges.maxOfOrNull { it.endDate } ?: 0)), + onValueChange = {}, + label = { + Text(text = "Завершение") + } + ) + + Box( + modifier = Modifier + .fillMaxSize() + .clickable { showEndDateSelector = true } + ) {} + + } + + } + + TextField( + singleLine = true, + value = state.radius?.toString() ?: "", + onValueChange = { + viewModel.setEvent( + RotationStatisticContract.Event.OnRadiusChanged( + it.filter { it.isDigit() }.toLongOrNull() + ) + ) + }, + label = { + Text(text = "Радиус колеса (мм.)") + }, + modifier = Modifier.fillMaxWidth() + ) + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + + Column { + + Text(text = "Пройденное расстояние") + Text(text = "Движение вперед") + Text(text = "Движение назад") + Text(text = "Стоянка") + + } + + Column { + + val duration = state.ranges.filter { it.distance == 0.0 }.sumOf { it.endDate - it.startDate } + val hours = duration / TimeUnit.HOURS.toMillis(1) + val minutes = (duration - (hours * TimeUnit.HOURS.toMillis(1))) / TimeUnit.MINUTES.toMillis(1) + val seconds = (duration - (hours * TimeUnit.HOURS.toMillis(1)) - (minutes * TimeUnit.MINUTES.toMillis(1))) / TimeUnit.SECONDS.toMillis(1) + + Text(text = state.ranges.sumOf { it.distance.absoluteValue }.roundTo().toString() + " м.") + Text(text = state.ranges.filter { it.distance > 0 }.sumOf { it.distance.absoluteValue }.roundTo().toString() + " м.") + Text(text = state.ranges.filter { it.distance < 0 }.sumOf { it.distance.absoluteValue }.roundTo().toString() + " м.") + Text(text = "${hours}ч ${minutes}м. ${seconds}с.") + + } + + } + + var reversed by remember { + mutableStateOf(true) + } + + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + modifier = Modifier.fillMaxWidth() + ) { + + Text(text = "Порядок") + + IconButton( + onClick = { reversed = reversed.not() } + ) { + + Icon( + imageVector = if (reversed) Icons.Rounded.ArrowBack else Icons.Rounded.ArrowForward, + contentDescription = null + ) + + } + + } + + LazyRow( + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + + items(items = state.ranges.let { if (reversed) it.reversed() else it}){ + DataRange(range = it) + } + + } + + if(showStartDateSelector) { + + Dialog( + properties = DialogProperties(usePlatformDefaultWidth = false), + onDismissRequest = { + showEndDateSelector = false + } + ) { + + Surface( + shape = RoundedCornerShape(16.dp) + ) { + + val datePickerState = rememberDatePickerState( + initialSelectedDateMillis = state.startDate + ) + + Column{ + + DatePicker(state = datePickerState) + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End), + modifier = Modifier + .align(Alignment.End) + .padding(12.dp) + ) { + + TextButton( + onClick = { + showStartDateSelector = false + } + ) { + Text(text = "Отмена") + } + + Button( + onClick = { + viewModel.setEvent( + RotationStatisticContract.Event.OnStartDateChanged( + datePickerState.selectedDateMillis ?: state.startDate + ) + ) + showStartDateSelector = false + } + ) { + Text(text = "ок") + } + + } + + } + + } + + } + + } + + if(showEndDateSelector) { + + Dialog( + properties = DialogProperties(usePlatformDefaultWidth = false), + onDismissRequest = { + showEndDateSelector = false + } + ) { + + Surface( + shape = RoundedCornerShape(16.dp) + ) { + + val datePickerState = rememberDatePickerState( + initialSelectedDateMillis = state.endDate + ) + + Column { + + DatePicker(state = datePickerState) + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End), + modifier = Modifier + .align(Alignment.End) + .padding(12.dp) + ) { + + TextButton( + onClick = { + showEndDateSelector = false + } + ) { + Text(text = "Отмена") + } + + Button( + onClick = { + viewModel.setEvent( + RotationStatisticContract.Event.OnStopDateChanged( + datePickerState.selectedDateMillis ?: state.endDate + ) + ) + showEndDateSelector = false + } + ) { + Text(text = "ок") + } + + } + + } + + } + + } + + } + + } + + } + + } + +} + +fun Double.roundTo(numFractionDigits: Int = 2): Double { + val factor = 10.0.pow(numFractionDigits.toDouble()) + return (this * factor).roundToInt() / factor +} + +private fun Double.round(decimals: Int = 2): Double = "%.${decimals}f".format(this).toDouble() + +private val dateTimeFormat = SimpleDateFormat("dd.MM HH:mm:ss") +private val dateFormat = SimpleDateFormat("dd.MM HH:mm:ss") + +@Composable +private fun DataRange(range: RotationStatisticContract.State.Display.RotationRange){ + + Card { + + Column( + modifier = Modifier + .padding(12.dp) + .width(IntrinsicSize.Max) + ) { + + val duration = range.endDate - range.startDate + val hours = duration / TimeUnit.HOURS.toMillis(1) + val minutes = (duration - (hours * TimeUnit.HOURS.toMillis(1))) / TimeUnit.MINUTES.toMillis(1) + val seconds = (duration - (hours * TimeUnit.HOURS.toMillis(1)) - (minutes * TimeUnit.MINUTES.toMillis(1))) / TimeUnit.SECONDS.toMillis(1) + + val directionText = if(range.distance > 0){ + "-->" + }else{ + if(range.distance < 0) { + "<--" + } else { + "<

>" + } + } + + + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + + Column { + + Text(text = "Начало") + Text(text = "Конец") + + } + + Column { + + Text(text = dateTimeFormat.format(Date(range.startDate))) + Text(text = dateTimeFormat.format(Date(range.endDate))) + + + } + + } + + Text(text = "Направление: " + directionText) + + HorizontalDivider() + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + + Column { + + Text(text = "Время") + + if(range.distance != 0.0) { + + Text(text = "Расстояние") + Text(text = "Vmax.") + Text(text = "Vср.") + Text(text = "Обороты") + + } + + } + + Column { + + Text(text = "${hours}ч ${minutes}м. ${seconds}с.") + + if(range.distance != 0.0) { + + Text(text = range.distance.absoluteValue.roundTo().toString() + " м.") + Text(text = range.maxSpeed.roundTo().toString() + " Км/ч") + Text(text = range.avgSpeed.roundTo().toString() + " Км/ч") + Text(text = range.rotations.absoluteValue.toDouble().roundTo().toString()) + + } + + } + + } + + + + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticViewModel.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticViewModel.kt new file mode 100644 index 0000000..307f526 --- /dev/null +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/rotation/statistic/RotationStatisticViewModel.kt @@ -0,0 +1,256 @@ +package llc.arma.ble.app.ui.screen.rotation.statistic + +import android.icu.util.GregorianCalendar +import android.util.Log +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import com.patrykandpatrick.vico.core.extension.sumOf +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import llc.arma.ble.app.ui.common.BaseViewModel +import llc.arma.ble.domain.usecase.GetRotationsBySerial +import llc.arma.ble.domain.usecase.GetWheelRadiusBySerial +import llc.arma.ble.domain.usecase.SetWheelRadius +import java.util.concurrent.TimeUnit +import javax.inject.Inject +import kotlin.math.absoluteValue + +fun Collection.splitBy(separator: (T) -> Any?): List> { + + val result = mutableListOf>() + + var newSublist = true + for (item in this) { + newSublist = (separator(item) != result.lastOrNull()?.lastOrNull()?.let { separator(it) }) + if (newSublist || result.lastOrNull() == null) + result += mutableListOf() + result.last() += item + } + + return result +} + +@HiltViewModel +class RotationStatisticViewModel @Inject constructor( + private val setWheelRadius: SetWheelRadius, + private val getWheelRadius: GetWheelRadiusBySerial, + private val getRotationsBySerial: GetRotationsBySerial, + private val savedStateHandle: SavedStateHandle +) : BaseViewModel() { + + init { + + viewModelScope.launch { + + load() + + } + + } + + override fun setInitialState() = RotationStatisticContract.State.Loading + + override fun handleEvents(event: RotationStatisticContract.Event) { + when(event){ + is RotationStatisticContract.Event.OnRadiusChanged -> reduce(viewState.value, event) + is RotationStatisticContract.Event.OnStartDateChanged -> reduce(viewState.value, event) + is RotationStatisticContract.Event.OnStopDateChanged -> reduce(viewState.value, event) + is RotationStatisticContract.Event.OnNavigateToDelete -> reduce(viewState.value, event) + is RotationStatisticContract.Event.OnNavigateUp -> reduce(viewState.value, event) + } + } + + private suspend fun load(){ + savedStateHandle.get("serial")?.let { + + val state = viewState.value + + val r = getWheelRadius(it)?.toFloat() ?: 500f + val rCm = r / 10f + val circumference = 2 * Math.PI * rCm + Log.d("circumference", circumference.toString()) + + var rotations = getRotationsBySerial(it) + + if(state is RotationStatisticContract.State.Display){ + rotations = rotations.filter { + it.date >= (state.startDate ?: 0) && it.date <= (state.endDate ?: Long.MAX_VALUE) + } + } + + val split: List = if(rotations.size < 2) { + emptyList() + }else { + + val pointDuration = rotations[1].date - rotations[0].date + + rotations.splitBy { + Log.d("rDate", it.date.toString()) + if (it.rotations > 0) { + true + } else { + if (it.rotations < 0) { + false + } else { + null + } + } + }.map { range -> + + val start = range.minOf { it.date } - pointDuration + val end = range.maxOf { it.date } + + val speeds = range.map { + val km = ((it.rotations.absoluteValue / 8f) * circumference) / 100_000f + km / (pointDuration.toFloat() / TimeUnit.HOURS.toMillis(1).toFloat()) + } + + RotationStatisticContract.State.Display.RotationRange( + distance = ((range.sumOf { it.rotations.toFloat() } / 8f) * circumference) / 100f, + startDate = start, + endDate = end, + maxSpeed = speeds.max(), + avgSpeed = speeds.average(), + rotations = range.sumOf { it.rotations.toFloat() } / 8f + ) + + } + + } + + setState { + + when(this){ + is RotationStatisticContract.State.Display -> { + copy( + rotations = rotations, + ranges = split + ) + } + RotationStatisticContract.State.Loading -> { + RotationStatisticContract.State.Display( + rotations = rotations, + ranges = split, + radius = r.toLong(), + startDate = null, + endDate = null + ) + } + } + + } + + + } ?: throw IllegalArgumentException() + } + + private fun reduce( + state: RotationStatisticContract.State, + event: RotationStatisticContract.Event.OnRadiusChanged + ) { + + if(state is RotationStatisticContract.State.Display){ + + setState { + state.copy(radius = event.radius) + } + + viewModelScope.launch { + + setWheelRadius(savedStateHandle.get("serial")!!, event.radius ?: 100L) + + load() + + } + + } + + } + + private fun reduce( + state: RotationStatisticContract.State, + event: RotationStatisticContract.Event.OnStartDateChanged + ) { + + if(state is RotationStatisticContract.State.Display){ + + val mCalendar = GregorianCalendar() + val mTimeZone = mCalendar.timeZone + val mGMTOffset: Int = mTimeZone.rawOffset + + val start = event.start?.let { + TimeUnit.DAYS.toMillis(TimeUnit.MILLISECONDS.toDays(event.start)) - mGMTOffset + } + + Log.d("date", start.toString() + " " + event.start) + + setState { + state.copy(startDate = start) + } + + viewModelScope.launch { + + load() + + } + + } + + } + + private fun reduce( + state: RotationStatisticContract.State, + event: RotationStatisticContract.Event.OnStopDateChanged + ) { + + if(state is RotationStatisticContract.State.Display){ + + val mCalendar = GregorianCalendar() + val mTimeZone = mCalendar.timeZone + val mGMTOffset: Int = mTimeZone.rawOffset + + val stop = event.stop?.let { + TimeUnit.DAYS.toMillis(TimeUnit.MILLISECONDS.toDays(event.stop) + 1) - mGMTOffset - 1_000 + } + + setState { + state.copy(endDate = stop) + } + + viewModelScope.launch { + + load() + + } + + } + + } + + private fun reduce( + state: RotationStatisticContract.State, + event: RotationStatisticContract.Event.OnNavigateUp + ) { + + setEffect { + + RotationStatisticContract.Effect.Navigation.NavigateUp + + } + + } + + private fun reduce( + state: RotationStatisticContract.State, + event: RotationStatisticContract.Event.OnNavigateToDelete + ) { + + setEffect { + + RotationStatisticContract.Effect.Navigation.NavigateToDelete(savedStateHandle.get("serial")!!) + + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/data/db/AppDatabase.kt b/app/src/main/java/llc/arma/ble/data/db/AppDatabase.kt new file mode 100644 index 0000000..4b4d947 --- /dev/null +++ b/app/src/main/java/llc/arma/ble/data/db/AppDatabase.kt @@ -0,0 +1,16 @@ +package llc.arma.ble.data.db + +import androidx.room.Database +import androidx.room.RoomDatabase +import llc.arma.ble.data.model.RotationEntity +import llc.arma.ble.data.model.WheelEntity + +@Database( + entities = [RotationEntity::class, WheelEntity::class], + version = 1 +) +abstract class AppDatabase : RoomDatabase() { + + abstract fun getRotationsDao(): RotationsDao + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/data/db/RotationsDao.kt b/app/src/main/java/llc/arma/ble/data/db/RotationsDao.kt new file mode 100644 index 0000000..01f552a --- /dev/null +++ b/app/src/main/java/llc/arma/ble/data/db/RotationsDao.kt @@ -0,0 +1,31 @@ +package llc.arma.ble.data.db + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import llc.arma.ble.data.model.RotationEntity +import llc.arma.ble.data.model.WheelEntity + +@Dao +interface RotationsDao { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun save(rotations: WheelEntity) + + @Query("select * from wheel where bleId = :serial") + suspend fun getWheelBySerial(serial: String): WheelEntity? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun save(rotations: List) + + @Query("delete from rotation where bleId = :serial") + suspend fun deleteBySerial(serial: String) + + @Query("delete from rotation where bleId = :serial and date > :date") + suspend fun deleteBySerialAndDateMoreThan(serial: String, date: Long) + + @Query("select * from rotation where bleId = :serial order by date asc") + suspend fun getBySerialSortedByDate(serial: String): List + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/data/model/RotationEntity.kt b/app/src/main/java/llc/arma/ble/data/model/RotationEntity.kt new file mode 100644 index 0000000..3d737e1 --- /dev/null +++ b/app/src/main/java/llc/arma/ble/data/model/RotationEntity.kt @@ -0,0 +1,19 @@ +package llc.arma.ble.data.model + +import androidx.room.Entity +import androidx.room.Index + +@Entity( + tableName = "rotation", + indices = [Index(unique = true, value = ["bleId", "date"])], + primaryKeys = ["bleId", "date"] +) +class RotationEntity( + + val bleId: String, + + val date: Long, + + val rotations: Long + +) \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/data/model/WheelEntity.kt b/app/src/main/java/llc/arma/ble/data/model/WheelEntity.kt new file mode 100644 index 0000000..be40e42 --- /dev/null +++ b/app/src/main/java/llc/arma/ble/data/model/WheelEntity.kt @@ -0,0 +1,18 @@ +package llc.arma.ble.data.model + +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity( + tableName = "wheel", + indices = [Index(unique = true, value = ["bleId"])] +) +class WheelEntity( + + @PrimaryKey + val bleId: String, + + val radius: Long + +) \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt b/app/src/main/java/llc/arma/ble/data/repository/BleRepositoryImpl.kt similarity index 96% rename from app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt rename to app/src/main/java/llc/arma/ble/data/repository/BleRepositoryImpl.kt index 0e23e89..32e40d9 100644 --- a/app/src/main/java/llc/arma/ble/data/BleRepositoryImpl.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/BleRepositoryImpl.kt @@ -1,4 +1,4 @@ -package llc.arma.ble.data +package llc.arma.ble.data.repository import android.app.Application import android.os.SystemClock @@ -14,12 +14,13 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import llc.arma.ble.data.extensions.checkPermission -import llc.arma.ble.data.extensions.fromByte -import llc.arma.ble.data.extensions.get4byteUIntAt -import llc.arma.ble.data.extensions.info -import llc.arma.ble.data.extensions.sendData -import llc.arma.ble.data.extensions.toTemperature +import llc.arma.ble.data.db.RotationsDao +import llc.arma.ble.data.repository.extensions.checkPermission +import llc.arma.ble.data.repository.extensions.fromByte +import llc.arma.ble.data.repository.extensions.get4byteUIntAt +import llc.arma.ble.data.repository.extensions.info +import llc.arma.ble.data.repository.extensions.sendData +import llc.arma.ble.data.repository.extensions.toTemperature import llc.arma.ble.domain.Result import llc.arma.ble.domain.common.BleException import llc.arma.ble.domain.common.ProgressState @@ -67,7 +68,8 @@ val flashWriteUUID: UUID = UUID.fromString("a77db6f2-9bc4-11ed-a8fc-0242ac120002 @Singleton class BleRepositoryImpl @Inject constructor( - private val app: Application + private val app: Application, + private val rotationsDao: RotationsDao ) : BleRepository { val resultList: MutableMap = Collections.synchronizedMap(mutableMapOf()) @@ -536,13 +538,17 @@ class BleRepositoryImpl @Inject constructor( request.tx?.let { - connection.discoverServices().findService(serviceUUID)?.findCharacteristic(txWriteUUID)?.write( + connection.discoverServices().findService(serviceUUID)?.findCharacteristic( + txWriteUUID + )?.write( DataByteArray.from(it.sendData) ) ?: return Result.failure(BleException.UnexpectedResponse) } - connection.discoverServices().findService(serviceUUID)?.findCharacteristic(flashWriteUUID)!!.write( + connection.discoverServices().findService(serviceUUID)?.findCharacteristic( + flashWriteUUID + )!!.write( DataByteArray.from(9) ) @@ -579,6 +585,8 @@ class BleRepositoryImpl @Inject constructor( (this shr (it * Byte.SIZE_BITS)).toByte() }.toByteArray() + rotationsDao.deleteBySerial(serial) + return if(app.checkPermission()) { val connection = diff --git a/app/src/main/java/llc/arma/ble/data/EmailRepositoryImpl.kt b/app/src/main/java/llc/arma/ble/data/repository/EmailRepositoryImpl.kt similarity index 96% rename from app/src/main/java/llc/arma/ble/data/EmailRepositoryImpl.kt rename to app/src/main/java/llc/arma/ble/data/repository/EmailRepositoryImpl.kt index 6da8e60..5a8701f 100644 --- a/app/src/main/java/llc/arma/ble/data/EmailRepositoryImpl.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/EmailRepositoryImpl.kt @@ -1,4 +1,4 @@ -package llc.arma.ble.data +package llc.arma.ble.data.repository import android.app.Application import android.content.Intent diff --git a/app/src/main/java/llc/arma/ble/data/GetAccelerometerHistory.kt b/app/src/main/java/llc/arma/ble/data/repository/GetAccelerometerHistory.kt similarity index 96% rename from app/src/main/java/llc/arma/ble/data/GetAccelerometerHistory.kt rename to app/src/main/java/llc/arma/ble/data/repository/GetAccelerometerHistory.kt index 0599025..8763a5a 100644 --- a/app/src/main/java/llc/arma/ble/data/GetAccelerometerHistory.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/GetAccelerometerHistory.kt @@ -1,4 +1,4 @@ -package llc.arma.ble.data +package llc.arma.ble.data.repository import android.app.Application import android.util.Log @@ -6,11 +6,11 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow -import llc.arma.ble.data.extensions.checkPermission -import llc.arma.ble.data.extensions.fromByte -import llc.arma.ble.data.extensions.get2byteShortAt -import llc.arma.ble.data.extensions.get2byteUIntAt -import llc.arma.ble.data.extensions.get4byteUIntAt +import llc.arma.ble.data.repository.extensions.checkPermission +import llc.arma.ble.data.repository.extensions.fromByte +import llc.arma.ble.data.repository.extensions.get2byteShortAt +import llc.arma.ble.data.repository.extensions.get2byteUIntAt +import llc.arma.ble.data.repository.extensions.get4byteUIntAt import llc.arma.ble.domain.Result import llc.arma.ble.domain.common.BleException import llc.arma.ble.domain.common.ProgressState diff --git a/app/src/main/java/llc/arma/ble/data/GetAccelerometerRealtimeData.kt b/app/src/main/java/llc/arma/ble/data/repository/GetAccelerometerRealtimeData.kt similarity index 95% rename from app/src/main/java/llc/arma/ble/data/GetAccelerometerRealtimeData.kt rename to app/src/main/java/llc/arma/ble/data/repository/GetAccelerometerRealtimeData.kt index 0e0ca8c..c38a128 100644 --- a/app/src/main/java/llc/arma/ble/data/GetAccelerometerRealtimeData.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/GetAccelerometerRealtimeData.kt @@ -1,14 +1,13 @@ -package llc.arma.ble.data +package llc.arma.ble.data.repository import android.app.Application -import android.util.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow -import llc.arma.ble.data.extensions.checkPermission -import llc.arma.ble.data.extensions.get2byteShortAt -import llc.arma.ble.data.extensions.sendData +import llc.arma.ble.data.repository.extensions.checkPermission +import llc.arma.ble.data.repository.extensions.get2byteShortAt +import llc.arma.ble.data.repository.extensions.sendData import llc.arma.ble.domain.Result import llc.arma.ble.domain.common.BleException import llc.arma.ble.domain.model.Ble diff --git a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt b/app/src/main/java/llc/arma/ble/data/repository/ReadAccelerometerSpectreCallback.kt similarity index 92% rename from app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt rename to app/src/main/java/llc/arma/ble/data/repository/ReadAccelerometerSpectreCallback.kt index 4047aa8..f0def63 100644 --- a/app/src/main/java/llc/arma/ble/data/ReadAccelerometerSpectreCallback.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/ReadAccelerometerSpectreCallback.kt @@ -1,21 +1,16 @@ -package llc.arma.ble.data +package llc.arma.ble.data.repository import android.app.Application -import android.bluetooth.BluetoothGatt -import android.bluetooth.BluetoothGattCallback -import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothGattDescriptor -import android.os.Build -import android.util.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow -import llc.arma.ble.data.extensions.checkPermission -import llc.arma.ble.data.extensions.get2byteShortAt -import llc.arma.ble.data.extensions.get2byteUIntAt -import llc.arma.ble.data.extensions.get4byteUIntAt -import llc.arma.ble.data.extensions.sendData +import llc.arma.ble.data.repository.extensions.checkPermission +import llc.arma.ble.data.repository.extensions.get2byteShortAt +import llc.arma.ble.data.repository.extensions.get2byteUIntAt +import llc.arma.ble.data.repository.extensions.get4byteUIntAt +import llc.arma.ble.data.repository.extensions.sendData import llc.arma.ble.domain.Result import llc.arma.ble.domain.common.BleException import llc.arma.ble.domain.common.ProgressState @@ -27,8 +22,6 @@ import llc.arma.ble.domain.usecase.FftFrequency import llc.arma.ble.domain.usecase.FftViewMode import no.nordicsemi.android.common.core.DataByteArray import no.nordicsemi.android.kotlin.ble.client.main.callback.ClientBleGatt -import java.nio.ByteBuffer -import java.nio.ByteOrder.LITTLE_ENDIAN import java.util.UUID diff --git a/app/src/main/java/llc/arma/ble/data/ReadTemperatureHistoryCallback.kt b/app/src/main/java/llc/arma/ble/data/repository/ReadTemperatureHistoryCallback.kt similarity index 91% rename from app/src/main/java/llc/arma/ble/data/ReadTemperatureHistoryCallback.kt rename to app/src/main/java/llc/arma/ble/data/repository/ReadTemperatureHistoryCallback.kt index e712436..d50a0b8 100644 --- a/app/src/main/java/llc/arma/ble/data/ReadTemperatureHistoryCallback.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/ReadTemperatureHistoryCallback.kt @@ -1,19 +1,14 @@ -package llc.arma.ble.data +package llc.arma.ble.data.repository import android.app.Application -import android.bluetooth.BluetoothGatt -import android.bluetooth.BluetoothGattCallback -import android.bluetooth.BluetoothGattCharacteristic -import android.os.Build -import android.util.Log import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow -import llc.arma.ble.data.extensions.checkPermission -import llc.arma.ble.data.extensions.get2byteUIntAt -import llc.arma.ble.data.extensions.get4byteUIntAt -import llc.arma.ble.data.extensions.toTemperature +import llc.arma.ble.data.repository.extensions.checkPermission +import llc.arma.ble.data.repository.extensions.get2byteUIntAt +import llc.arma.ble.data.repository.extensions.get4byteUIntAt +import llc.arma.ble.data.repository.extensions.toTemperature import llc.arma.ble.domain.Result import llc.arma.ble.domain.common.BleException import llc.arma.ble.domain.common.ProgressState diff --git a/app/src/main/java/llc/arma/ble/data/repository/RotationsRepositoryImpl.kt b/app/src/main/java/llc/arma/ble/data/repository/RotationsRepositoryImpl.kt new file mode 100644 index 0000000..2b5c39e --- /dev/null +++ b/app/src/main/java/llc/arma/ble/data/repository/RotationsRepositoryImpl.kt @@ -0,0 +1,49 @@ +package llc.arma.ble.data.repository + +import llc.arma.ble.data.db.RotationsDao +import llc.arma.ble.data.model.RotationEntity +import llc.arma.ble.data.model.WheelEntity +import llc.arma.ble.domain.model.Rotation +import llc.arma.ble.domain.repository.RotationsRepository +import javax.inject.Inject + +class RotationsRepositoryImpl @Inject constructor( + private val dao: RotationsDao +) : RotationsRepository { + + override suspend fun saveRotations(rotations: List) { + dao.deleteBySerialAndDateMoreThan(rotations.first().bleId, rotations.minOf { it.date } - 8) + dao.save( + rotations.map { + RotationEntity( + bleId = it.bleId, + rotations = it.rotations, + date = it.date + ) + } + ) + } + + override suspend fun getRotationsBySerial(serial: String): List { + return dao.getBySerialSortedByDate(serial).map { + Rotation( + bleId = it.bleId, + rotations = it.rotations, + date = it.date + ) + } + } + + override suspend fun deleteRotationsBySerial(serial: String) { + dao.deleteBySerial(serial) + } + + override suspend fun getWheelRadiusBySerial(serial: String): Long? { + return dao.getWheelBySerial(serial)?.radius + } + + override suspend fun setWheelRadius(serial: String, radius: Long) { + dao.save(WheelEntity(serial, radius)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/data/XlsxRepositoryImpl.kt b/app/src/main/java/llc/arma/ble/data/repository/XlsxRepositoryImpl.kt similarity index 98% rename from app/src/main/java/llc/arma/ble/data/XlsxRepositoryImpl.kt rename to app/src/main/java/llc/arma/ble/data/repository/XlsxRepositoryImpl.kt index 616d892..b413db5 100644 --- a/app/src/main/java/llc/arma/ble/data/XlsxRepositoryImpl.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/XlsxRepositoryImpl.kt @@ -1,9 +1,8 @@ -package llc.arma.ble.data +package llc.arma.ble.data.repository import android.app.Application import android.icu.text.SimpleDateFormat import android.os.Environment -import android.util.Log import llc.arma.ble.R import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.repository.XlsxRepository diff --git a/app/src/main/java/llc/arma/ble/data/extensions/ApplicationExtension.kt b/app/src/main/java/llc/arma/ble/data/repository/extensions/ApplicationExtension.kt similarity index 94% rename from app/src/main/java/llc/arma/ble/data/extensions/ApplicationExtension.kt rename to app/src/main/java/llc/arma/ble/data/repository/extensions/ApplicationExtension.kt index 3ad29b7..1a4ac80 100644 --- a/app/src/main/java/llc/arma/ble/data/extensions/ApplicationExtension.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/extensions/ApplicationExtension.kt @@ -1,4 +1,4 @@ -package llc.arma.ble.data.extensions +package llc.arma.ble.data.repository.extensions import android.Manifest import android.app.Application diff --git a/app/src/main/java/llc/arma/ble/data/extensions/BleEnumExtensions.kt b/app/src/main/java/llc/arma/ble/data/repository/extensions/BleEnumExtensions.kt similarity index 97% rename from app/src/main/java/llc/arma/ble/data/extensions/BleEnumExtensions.kt rename to app/src/main/java/llc/arma/ble/data/repository/extensions/BleEnumExtensions.kt index 3c965e2..8650e60 100644 --- a/app/src/main/java/llc/arma/ble/data/extensions/BleEnumExtensions.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/extensions/BleEnumExtensions.kt @@ -1,4 +1,4 @@ -package llc.arma.ble.data.extensions +package llc.arma.ble.data.repository.extensions import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.usecase.AccelScale diff --git a/app/src/main/java/llc/arma/ble/data/extensions/BleScanResultExtensions.kt b/app/src/main/java/llc/arma/ble/data/repository/extensions/BleScanResultExtensions.kt similarity index 96% rename from app/src/main/java/llc/arma/ble/data/extensions/BleScanResultExtensions.kt rename to app/src/main/java/llc/arma/ble/data/repository/extensions/BleScanResultExtensions.kt index 75053bd..35fdf1e 100644 --- a/app/src/main/java/llc/arma/ble/data/extensions/BleScanResultExtensions.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/extensions/BleScanResultExtensions.kt @@ -1,4 +1,4 @@ -package llc.arma.ble.data.extensions +package llc.arma.ble.data.repository.extensions import llc.arma.ble.domain.model.BleInfo import no.nordicsemi.android.kotlin.ble.core.scanner.BleScanResult diff --git a/app/src/main/java/llc/arma/ble/data/extensions/ByteArrayExtensions.kt b/app/src/main/java/llc/arma/ble/data/repository/extensions/ByteArrayExtensions.kt similarity index 95% rename from app/src/main/java/llc/arma/ble/data/extensions/ByteArrayExtensions.kt rename to app/src/main/java/llc/arma/ble/data/repository/extensions/ByteArrayExtensions.kt index a5269f4..434c076 100644 --- a/app/src/main/java/llc/arma/ble/data/extensions/ByteArrayExtensions.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/extensions/ByteArrayExtensions.kt @@ -1,4 +1,4 @@ -package llc.arma.ble.data.extensions +package llc.arma.ble.data.repository.extensions import java.nio.ByteBuffer import java.nio.ByteOrder diff --git a/app/src/main/java/llc/arma/ble/domain/model/Rotation.kt b/app/src/main/java/llc/arma/ble/domain/model/Rotation.kt new file mode 100644 index 0000000..669da9e --- /dev/null +++ b/app/src/main/java/llc/arma/ble/domain/model/Rotation.kt @@ -0,0 +1,14 @@ +package llc.arma.ble.domain.model + +import androidx.room.Entity +import androidx.room.Index + +data class Rotation( + + val bleId: String, + + val date: Long, + + val rotations: Long + +) \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/domain/repository/RotationsRepository.kt b/app/src/main/java/llc/arma/ble/domain/repository/RotationsRepository.kt new file mode 100644 index 0000000..ce2aa99 --- /dev/null +++ b/app/src/main/java/llc/arma/ble/domain/repository/RotationsRepository.kt @@ -0,0 +1,17 @@ +package llc.arma.ble.domain.repository + +import llc.arma.ble.domain.model.Rotation + +interface RotationsRepository { + + suspend fun saveRotations(rotations: List) + + suspend fun getRotationsBySerial(serial: String): List + + suspend fun deleteRotationsBySerial(serial: String) + + suspend fun getWheelRadiusBySerial(serial: String): Long? + + suspend fun setWheelRadius(serial: String, radius: Long) + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/DeleteRotationsBySerial.kt b/app/src/main/java/llc/arma/ble/domain/usecase/DeleteRotationsBySerial.kt new file mode 100644 index 0000000..4d733ec --- /dev/null +++ b/app/src/main/java/llc/arma/ble/domain/usecase/DeleteRotationsBySerial.kt @@ -0,0 +1,17 @@ +package llc.arma.ble.domain.usecase + +import llc.arma.ble.domain.model.Rotation +import llc.arma.ble.domain.repository.RotationsRepository +import javax.inject.Inject + +class DeleteRotationsBySerial @Inject constructor ( + private val rotationsRepository: RotationsRepository +) { + + suspend operator fun invoke(serial: String) { + + rotationsRepository.deleteRotationsBySerial(serial) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/GetAccelerometerHistoryBySerial.kt b/app/src/main/java/llc/arma/ble/domain/usecase/GetAccelerometerHistoryBySerial.kt index a3b0f56..8a4233c 100644 --- a/app/src/main/java/llc/arma/ble/domain/usecase/GetAccelerometerHistoryBySerial.kt +++ b/app/src/main/java/llc/arma/ble/domain/usecase/GetAccelerometerHistoryBySerial.kt @@ -1,20 +1,49 @@ package llc.arma.ble.domain.usecase import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.onEach 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.Rotation import llc.arma.ble.domain.repository.BleRepository +import llc.arma.ble.domain.repository.RotationsRepository +import java.time.LocalDateTime +import java.util.Date +import java.util.concurrent.TimeUnit import javax.inject.Inject class GetAccelerometerHistoryBySerial @Inject constructor( - private val bleRepository: BleRepository + private val bleRepository: BleRepository, + private val rotationsRepository: RotationsRepository ) { suspend operator fun invoke(serial: String): Flow>, BleException>> { - return bleRepository.getAccelerometerHistoryBySerial(serial) + return bleRepository.getAccelerometerHistoryBySerial(serial).onEach { + it.onSuccess { progress -> + if(progress is ProgressState.Finished){ + val rotations = progress.data.mapNotNull { point -> + if(point is Ble.Accelerometer.HistoryPoint.Rotation){ + Rotation( + bleId = serial, + date = TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(point.date)), + rotations = point.value + ) + }else{ + null + } + + } + if(rotations.isNotEmpty()){ + + rotationsRepository.saveRotations(rotations) + + } + } + } + } } diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/GetRotationsBySerial.kt b/app/src/main/java/llc/arma/ble/domain/usecase/GetRotationsBySerial.kt new file mode 100644 index 0000000..5c33b9a --- /dev/null +++ b/app/src/main/java/llc/arma/ble/domain/usecase/GetRotationsBySerial.kt @@ -0,0 +1,17 @@ +package llc.arma.ble.domain.usecase + +import llc.arma.ble.domain.model.Rotation +import llc.arma.ble.domain.repository.RotationsRepository +import javax.inject.Inject + +class GetRotationsBySerial @Inject constructor ( + private val rotationsRepository: RotationsRepository +) { + + suspend operator fun invoke(serial: String): List { + + return rotationsRepository.getRotationsBySerial(serial) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/GetWheelRadiusBySerial.kt b/app/src/main/java/llc/arma/ble/domain/usecase/GetWheelRadiusBySerial.kt new file mode 100644 index 0000000..11a481e --- /dev/null +++ b/app/src/main/java/llc/arma/ble/domain/usecase/GetWheelRadiusBySerial.kt @@ -0,0 +1,14 @@ +package llc.arma.ble.domain.usecase + +import llc.arma.ble.domain.repository.RotationsRepository +import javax.inject.Inject + +class GetWheelRadiusBySerial @Inject constructor( + private val rotationsRepository: RotationsRepository +) { + + suspend operator fun invoke(serial: String): Long? { + return rotationsRepository.getWheelRadiusBySerial(serial) + } + +} \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/SetWheelRadius.kt b/app/src/main/java/llc/arma/ble/domain/usecase/SetWheelRadius.kt new file mode 100644 index 0000000..61b705f --- /dev/null +++ b/app/src/main/java/llc/arma/ble/domain/usecase/SetWheelRadius.kt @@ -0,0 +1,14 @@ +package llc.arma.ble.domain.usecase + +import llc.arma.ble.domain.repository.RotationsRepository +import javax.inject.Inject + +class SetWheelRadius @Inject constructor( + private val rotationsRepository: RotationsRepository +) { + + suspend operator fun invoke(serial: String, radius: Long){ + rotationsRepository.setWheelRadius(serial, radius) + } + +} \ No newline at end of file