xlsx export

This commit is contained in:
Vineyro 2024-08-06 17:18:20 +07:00
parent eca21cb3bf
commit 5293604ee4
7 changed files with 145 additions and 24 deletions

View File

@ -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 {

View File

@ -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<HostHistoryContract.State, HostHistoryContract.Event, HostHistoryContract.Effect>() {
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

View File

@ -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) {

View File

@ -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<Ble.Accelerometer.HistoryPoint>
): 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<Ble.Host.HistoryPoint>): 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
}
}

View File

@ -5,9 +5,14 @@ import java.io.File
interface XlsxRepository {
fun exportToXls(
fun exportAccelDataToXls(
bleName: String,
data: List<Ble.Accelerometer.HistoryPoint>
): File
fun exportHostDataToXls(
bleName: String,
data: List<Ble.Host.HistoryPoint>
): File
}

View File

@ -15,7 +15,18 @@ class ExportToXlsx @Inject constructor(
data: List<Ble.Accelerometer.HistoryPoint>
){
val file = xlsxRepository.exportToXls(bleName, data)
val file = xlsxRepository.exportAccelDataToXls(bleName, data)
emailRepository.sendFile(file)
}
@JvmName("invokeHost")
operator fun invoke(
bleName: String,
data: List<Ble.Host.HistoryPoint>
){
val file = xlsxRepository.exportHostDataToXls(bleName, data)
emailRepository.sendFile(file)
}

Binary file not shown.