diff --git a/app/build.gradle b/app/build.gradle index 4a47d3b..b1d199d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,8 +17,8 @@ android { applicationId "llc.arma.ble" minSdk 26 targetSdk 34 - versionCode 35 - versionName "1.4.4" + versionCode 39 + versionName "1.4.9" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { diff --git a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/host/view/HostHistory.kt b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/host/view/HostHistory.kt index 87a89a0..a0e6988 100644 --- a/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/host/view/HostHistory.kt +++ b/app/src/main/java/llc/arma/ble/app/ui/screen/inspection/host/view/HostHistory.kt @@ -25,6 +25,7 @@ import androidx.compose.material.ContentAlpha import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.ArrowBack import androidx.compose.material.icons.rounded.Refresh +import androidx.compose.material.icons.rounded.Save import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FilterChip @@ -38,10 +39,12 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -75,6 +78,7 @@ 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.model.BleName +import llc.arma.ble.domain.usecase.ExportToXlsx import llc.arma.ble.domain.usecase.GetBleBySerial import llc.arma.ble.domain.usecase.GetBleNamesFlow import llc.arma.ble.domain.usecase.GetHostHistoryBySerial @@ -148,6 +152,21 @@ fun HostHistory( }, actions = { + IconButton( + onClick = { + viewModel.setEvent(HostHistoryContract.Event.OnExportHistory(ble.serial)) + }, + enabled = when(state){ + is HostHistoryContract.State.Display -> state.loadingHistoryState is ProgressState.Finished + HostHistoryContract.State.Exception -> true + } + ) { + Icon( + imageVector = Icons.Rounded.Save, + contentDescription = null + ) + } + IconButton( onClick = { viewModel.setEvent(HostHistoryContract.Event.OnRefreshHistory(ble.name, ble.serial)) @@ -183,11 +202,10 @@ val dateFormatter = SimpleDateFormat("dd.MM", Locale.getDefault()) val timeFormatter = SimpleDateFormat("HH:mm", Locale.getDefault()) val colorsStack = listOf( - -0x63d850, -0x98c549, -0xc0ae4b, -0xde690d, - -0xfc560c, -0xff432c, -0xff6978, -0xb350b0, - -0x743cb6, -0x3223c7, -0x14c5, -0x3ef9, - -0x6800, -0xa8de, -0x86aab8, -0x616162, - -0x9f8275, -0xcccccd, -0xbbcca + Color(0xffffd700), Color(0xff2f4f4f), Color(0xff7f0000), Color(0xFFFF0000), + Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c), + Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f), + Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee), ) val axisValueFormatter = @@ -246,8 +264,8 @@ fun Display( }.toMap() } - var selectedSerials by remember { - mutableStateOf(allSerials) + var selectedSerials by rememberSaveable { + mutableStateOf(allSerials.take(1)) } val serials = remember(selectedSerials) { allSerials.filter { selectedSerials.contains(it) } } @@ -274,7 +292,7 @@ fun Display( val chart = columnChart( innerSpacing = 2.dp, - columns = serials.map { LineComponent(color = colors[it]!!, thicknessDp = 7f, shape= pillShape) }, + columns = serials.map { LineComponent(color = colors[it]!!.toArgb(), thicknessDp = 7f, shape= pillShape) }, spacing = 8.dp, ) @@ -297,7 +315,7 @@ fun Display( leadingIcon = { Surface( shape = CircleShape, - color = Color(colors[s]!!), + color = colors[s]!!, modifier = Modifier.size(28.dp) ) {} }, @@ -464,7 +482,7 @@ class HostHistoryContract { sealed class Event : ViewEvent { - object StopMeasure : Event() + data object StopMeasure : Event() data class OnStart( val bleName: String, @@ -476,6 +494,10 @@ class HostHistoryContract { val serial: String, ) : Event() + data class OnExportHistory( + val serial: String, + ) : Event() + } sealed class State : ViewState { @@ -502,7 +524,8 @@ class HostHistoryContract { class HostHistoryViewModel @Inject constructor( private val getHostHistoryBySerial: GetHostHistoryBySerial, private val getBleBySerial: GetBleBySerial, - private val getBleNamesFlow: GetBleNamesFlow + private val getBleNamesFlow: GetBleNamesFlow, + private val exportToXlsx: ExportToXlsx ) : BaseViewModel() { var measureJob: Job? = null @@ -520,9 +543,27 @@ class HostHistoryViewModel @Inject constructor( is HostHistoryContract.Event.OnStart -> reduce(viewState.value, event) is HostHistoryContract.Event.OnRefreshHistory -> reduce(viewState.value, event) is HostHistoryContract.Event.StopMeasure -> reduce(viewState.value, event) + is HostHistoryContract.Event.OnExportHistory -> reduce(viewState.value, event) } } + private fun reduce( + state: HostHistoryContract.State, + event: HostHistoryContract.Event.OnExportHistory + ) { + + if(state is HostHistoryContract.State.Display) { + + if(state.loadingHistoryState is ProgressState.Finished) { + + exportToXlsx.invoke(event.serial, state.loadingHistoryState.data) + + } + + } + + } + private fun reduce( state: HostHistoryContract.State, event: HostHistoryContract.Event.StopMeasure diff --git a/app/src/main/java/llc/arma/ble/data/repository/ReadHostHistory.kt b/app/src/main/java/llc/arma/ble/data/repository/ReadHostHistory.kt index 6e245f4..c903029 100644 --- a/app/src/main/java/llc/arma/ble/data/repository/ReadHostHistory.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/ReadHostHistory.kt @@ -126,10 +126,6 @@ fun readHostHistory( fun getInnerIndex(byte: Byte): Int{ - if(byte != 0.toByte()){ - println(byte) - } - var bits = BitSet.valueOf(byteArrayOf(byte)) bits.clear(0, 4) bits = bits.get(4, 8) @@ -146,7 +142,7 @@ fun readHostHistory( fun getDevType(byte: Byte): Int{ var bits = BitSet.valueOf(byteArrayOf(byte)) - bits.clear(5, 8) + bits.clear(5, 9) val arr = bits.toByteArray() if(arr.isEmpty()){ @@ -161,7 +157,7 @@ fun readHostHistory( var bits = BitSet.valueOf(byteArrayOf(byte)) bits.clear(0, 5) - bits = bits.get(4, 8) + bits = bits.get(5, 8) val arr = bits.toByteArray() if(arr.isEmpty()){ @@ -204,8 +200,10 @@ fun readHostHistory( println("table serial $serial") val devType = getDevType(devTypeByte) + println("devType $devType") val devDataSize = getDevDataSize(devTypeByte) + println("payload $devDataSize") bleTableOffset += 2 if (devDataSize != 0) { diff --git a/app/src/main/java/llc/arma/ble/data/repository/XlsxRepositoryImpl.kt b/app/src/main/java/llc/arma/ble/data/repository/XlsxRepositoryImpl.kt index b413db5..d777f2d 100644 --- a/app/src/main/java/llc/arma/ble/data/repository/XlsxRepositoryImpl.kt +++ b/app/src/main/java/llc/arma/ble/data/repository/XlsxRepositoryImpl.kt @@ -3,7 +3,13 @@ package llc.arma.ble.data.repository import android.app.Application import android.icu.text.SimpleDateFormat import android.os.Environment +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer import llc.arma.ble.R +import llc.arma.ble.app.ui.screen.inspection.host.view.HostEntry +import llc.arma.ble.app.ui.screen.inspection.host.view.colorsStack import llc.arma.ble.domain.model.Ble import llc.arma.ble.domain.repository.XlsxRepository import org.apache.poi.ss.usermodel.WorkbookFactory @@ -20,13 +26,13 @@ class XlsxRepositoryImpl @Inject constructor( private val application: Application ) : XlsxRepository { - override fun exportToXls( + override fun exportAccelDataToXls( bleName: String, data: List ): File { - val fileNameDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm") - val fileName = "${fileNameDateFormat.format(Date(System.currentTimeMillis()))}.xlsx".replace(' ', '_') + val fileNameDateFormat = SimpleDateFormat("yyyy-MM-dd_HH-mm") + val fileName = "${fileNameDateFormat.format(Date(System.currentTimeMillis()))}.xlsx" val formatter = SimpleDateFormat("dd.MM.yyyy HH:mm") @@ -105,4 +111,64 @@ class XlsxRepositoryImpl @Inject constructor( return mailFile } + override fun exportHostDataToXls(bleName: String, data: List): File { + val fileNameDateFormat = SimpleDateFormat("yyyy-MM-dd_HH-mm") + val fileName = "${fileNameDateFormat.format(Date(System.currentTimeMillis()))}.xlsx" + + val formatter = SimpleDateFormat("dd.MM.yyyy HH:mm") + + File(application.filesDir.absolutePath).mkdirs() + val mailFile = File(application.filesDir, fileName) + + mailFile.createNewFile() + + IOUtils.copy(application.resources.openRawResource(R.raw.host_history), FileOutputStream(mailFile)) + + val fileIn = FileInputStream(mailFile) + val workbook = WorkbookFactory.create(fileIn) + val worksheet = workbook.getSheetAt(0) as XSSFSheet + + val row = worksheet.createRow(0) + row.createCell(0).setCellValue("Date") + + data.forEachIndexed { index, historyPoint -> + + row.createCell(index).setCellValue(formatter.format(Date(historyPoint.date))) + + } + + data.flatMap { it.value }.distinct().forEachIndexed { rowIndex, serial -> + + val row = worksheet.createRow(rowIndex + 1) + row.createCell(0).setCellValue(serial) + + data.forEachIndexed { index, historyPoint -> + + row.createCell(index + 1) + .setCellValue( + if(historyPoint.value.contains(serial)) 1.0 else 0.0 + ) + } + + } + + fileIn.close() + val saveFos = FileOutputStream(mailFile) + workbook.write(saveFos) + saveFos.close() + + println(fileName) + + val sharedFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName) + sharedFile.createNewFile() + + val sharedSaveFos = FileOutputStream(sharedFile) + workbook.write(sharedSaveFos) + sharedSaveFos.close() + + workbook.close() + + return mailFile + } + } \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/domain/repository/XlsxRepository.kt b/app/src/main/java/llc/arma/ble/domain/repository/XlsxRepository.kt index 5a148d7..72eefb2 100644 --- a/app/src/main/java/llc/arma/ble/domain/repository/XlsxRepository.kt +++ b/app/src/main/java/llc/arma/ble/domain/repository/XlsxRepository.kt @@ -5,9 +5,14 @@ import java.io.File interface XlsxRepository { - fun exportToXls( + fun exportAccelDataToXls( bleName: String, data: List ): File + fun exportHostDataToXls( + bleName: String, + data: List + ): File + } \ No newline at end of file diff --git a/app/src/main/java/llc/arma/ble/domain/usecase/ExportToXlsx.kt b/app/src/main/java/llc/arma/ble/domain/usecase/ExportToXlsx.kt index b986769..ebadbe9 100644 --- a/app/src/main/java/llc/arma/ble/domain/usecase/ExportToXlsx.kt +++ b/app/src/main/java/llc/arma/ble/domain/usecase/ExportToXlsx.kt @@ -15,7 +15,18 @@ class ExportToXlsx @Inject constructor( data: List ){ - val file = xlsxRepository.exportToXls(bleName, data) + val file = xlsxRepository.exportAccelDataToXls(bleName, data) + emailRepository.sendFile(file) + + } + + @JvmName("invokeHost") + operator fun invoke( + bleName: String, + data: List + ){ + + val file = xlsxRepository.exportHostDataToXls(bleName, data) emailRepository.sendFile(file) } diff --git a/app/src/main/res/raw/host_history.xlsx b/app/src/main/res/raw/host_history.xlsx new file mode 100644 index 0000000..2a63501 Binary files /dev/null and b/app/src/main/res/raw/host_history.xlsx differ