xlsx export
This commit is contained in:
parent
eca21cb3bf
commit
5293604ee4
|
|
@ -17,8 +17,8 @@ android {
|
||||||
applicationId "llc.arma.ble"
|
applicationId "llc.arma.ble"
|
||||||
minSdk 26
|
minSdk 26
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode 35
|
versionCode 39
|
||||||
versionName "1.4.4"
|
versionName "1.4.9"
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import androidx.compose.material.ContentAlpha
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.ArrowBack
|
import androidx.compose.material.icons.rounded.ArrowBack
|
||||||
import androidx.compose.material.icons.rounded.Refresh
|
import androidx.compose.material.icons.rounded.Refresh
|
||||||
|
import androidx.compose.material.icons.rounded.Save
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.FilterChip
|
import androidx.compose.material3.FilterChip
|
||||||
|
|
@ -38,10 +39,12 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.VerticalDivider
|
import androidx.compose.material3.VerticalDivider
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
import androidx.compose.ui.graphics.StrokeCap
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalConfiguration
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -75,6 +78,7 @@ import llc.arma.ble.domain.common.ProgressState
|
||||||
import llc.arma.ble.domain.model.Ble
|
import llc.arma.ble.domain.model.Ble
|
||||||
import llc.arma.ble.domain.model.BleInfo
|
import llc.arma.ble.domain.model.BleInfo
|
||||||
import llc.arma.ble.domain.model.BleName
|
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.GetBleBySerial
|
||||||
import llc.arma.ble.domain.usecase.GetBleNamesFlow
|
import llc.arma.ble.domain.usecase.GetBleNamesFlow
|
||||||
import llc.arma.ble.domain.usecase.GetHostHistoryBySerial
|
import llc.arma.ble.domain.usecase.GetHostHistoryBySerial
|
||||||
|
|
@ -148,6 +152,21 @@ fun HostHistory(
|
||||||
},
|
},
|
||||||
actions = {
|
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(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.setEvent(HostHistoryContract.Event.OnRefreshHistory(ble.name, ble.serial))
|
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 timeFormatter = SimpleDateFormat("HH:mm", Locale.getDefault())
|
||||||
|
|
||||||
val colorsStack = listOf(
|
val colorsStack = listOf(
|
||||||
-0x63d850, -0x98c549, -0xc0ae4b, -0xde690d,
|
Color(0xffffd700), Color(0xff2f4f4f), Color(0xff7f0000), Color(0xFFFF0000),
|
||||||
-0xfc560c, -0xff432c, -0xff6978, -0xb350b0,
|
Color(0xffa9a9a9), Color(0xff00fa9a), Color(0xff00ffff), Color(0xfff0e68c),
|
||||||
-0x743cb6, -0x3223c7, -0x14c5, -0x3ef9,
|
Color(0xff00bfff), Color(0xff0000ff), Color(0xfff08080), Color(0xffadff2f),
|
||||||
-0x6800, -0xa8de, -0x86aab8, -0x616162,
|
Color(0xffff00ff), Color(0xff4169e1), Color(0xffff1493), Color(0xffee82ee),
|
||||||
-0x9f8275, -0xcccccd, -0xbbcca
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val axisValueFormatter =
|
val axisValueFormatter =
|
||||||
|
|
@ -246,8 +264,8 @@ fun Display(
|
||||||
}.toMap()
|
}.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectedSerials by remember {
|
var selectedSerials by rememberSaveable {
|
||||||
mutableStateOf(allSerials)
|
mutableStateOf(allSerials.take(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
val serials = remember(selectedSerials) { allSerials.filter { selectedSerials.contains(it) } }
|
val serials = remember(selectedSerials) { allSerials.filter { selectedSerials.contains(it) } }
|
||||||
|
|
@ -274,7 +292,7 @@ fun Display(
|
||||||
|
|
||||||
val chart = columnChart(
|
val chart = columnChart(
|
||||||
innerSpacing = 2.dp,
|
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,
|
spacing = 8.dp,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -297,7 +315,7 @@ fun Display(
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
Surface(
|
Surface(
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
color = Color(colors[s]!!),
|
color = colors[s]!!,
|
||||||
modifier = Modifier.size(28.dp)
|
modifier = Modifier.size(28.dp)
|
||||||
) {}
|
) {}
|
||||||
},
|
},
|
||||||
|
|
@ -464,7 +482,7 @@ class HostHistoryContract {
|
||||||
|
|
||||||
sealed class Event : ViewEvent {
|
sealed class Event : ViewEvent {
|
||||||
|
|
||||||
object StopMeasure : Event()
|
data object StopMeasure : Event()
|
||||||
|
|
||||||
data class OnStart(
|
data class OnStart(
|
||||||
val bleName: String,
|
val bleName: String,
|
||||||
|
|
@ -476,6 +494,10 @@ class HostHistoryContract {
|
||||||
val serial: String,
|
val serial: String,
|
||||||
) : Event()
|
) : Event()
|
||||||
|
|
||||||
|
data class OnExportHistory(
|
||||||
|
val serial: String,
|
||||||
|
) : Event()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class State : ViewState {
|
sealed class State : ViewState {
|
||||||
|
|
@ -502,7 +524,8 @@ class HostHistoryContract {
|
||||||
class HostHistoryViewModel @Inject constructor(
|
class HostHistoryViewModel @Inject constructor(
|
||||||
private val getHostHistoryBySerial: GetHostHistoryBySerial,
|
private val getHostHistoryBySerial: GetHostHistoryBySerial,
|
||||||
private val getBleBySerial: GetBleBySerial,
|
private val getBleBySerial: GetBleBySerial,
|
||||||
private val getBleNamesFlow: GetBleNamesFlow
|
private val getBleNamesFlow: GetBleNamesFlow,
|
||||||
|
private val exportToXlsx: ExportToXlsx
|
||||||
) : BaseViewModel<HostHistoryContract.State, HostHistoryContract.Event, HostHistoryContract.Effect>() {
|
) : BaseViewModel<HostHistoryContract.State, HostHistoryContract.Event, HostHistoryContract.Effect>() {
|
||||||
|
|
||||||
var measureJob: Job? = null
|
var measureJob: Job? = null
|
||||||
|
|
@ -520,9 +543,27 @@ class HostHistoryViewModel @Inject constructor(
|
||||||
is HostHistoryContract.Event.OnStart -> reduce(viewState.value, event)
|
is HostHistoryContract.Event.OnStart -> reduce(viewState.value, event)
|
||||||
is HostHistoryContract.Event.OnRefreshHistory -> reduce(viewState.value, event)
|
is HostHistoryContract.Event.OnRefreshHistory -> reduce(viewState.value, event)
|
||||||
is HostHistoryContract.Event.StopMeasure -> 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(
|
private fun reduce(
|
||||||
state: HostHistoryContract.State,
|
state: HostHistoryContract.State,
|
||||||
event: HostHistoryContract.Event.StopMeasure
|
event: HostHistoryContract.Event.StopMeasure
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,6 @@ fun readHostHistory(
|
||||||
|
|
||||||
fun getInnerIndex(byte: Byte): Int{
|
fun getInnerIndex(byte: Byte): Int{
|
||||||
|
|
||||||
if(byte != 0.toByte()){
|
|
||||||
println(byte)
|
|
||||||
}
|
|
||||||
|
|
||||||
var bits = BitSet.valueOf(byteArrayOf(byte))
|
var bits = BitSet.valueOf(byteArrayOf(byte))
|
||||||
bits.clear(0, 4)
|
bits.clear(0, 4)
|
||||||
bits = bits.get(4, 8)
|
bits = bits.get(4, 8)
|
||||||
|
|
@ -146,7 +142,7 @@ fun readHostHistory(
|
||||||
fun getDevType(byte: Byte): Int{
|
fun getDevType(byte: Byte): Int{
|
||||||
|
|
||||||
var bits = BitSet.valueOf(byteArrayOf(byte))
|
var bits = BitSet.valueOf(byteArrayOf(byte))
|
||||||
bits.clear(5, 8)
|
bits.clear(5, 9)
|
||||||
val arr = bits.toByteArray()
|
val arr = bits.toByteArray()
|
||||||
|
|
||||||
if(arr.isEmpty()){
|
if(arr.isEmpty()){
|
||||||
|
|
@ -161,7 +157,7 @@ fun readHostHistory(
|
||||||
|
|
||||||
var bits = BitSet.valueOf(byteArrayOf(byte))
|
var bits = BitSet.valueOf(byteArrayOf(byte))
|
||||||
bits.clear(0, 5)
|
bits.clear(0, 5)
|
||||||
bits = bits.get(4, 8)
|
bits = bits.get(5, 8)
|
||||||
val arr = bits.toByteArray()
|
val arr = bits.toByteArray()
|
||||||
|
|
||||||
if(arr.isEmpty()){
|
if(arr.isEmpty()){
|
||||||
|
|
@ -204,8 +200,10 @@ fun readHostHistory(
|
||||||
println("table serial $serial")
|
println("table serial $serial")
|
||||||
|
|
||||||
val devType = getDevType(devTypeByte)
|
val devType = getDevType(devTypeByte)
|
||||||
|
println("devType $devType")
|
||||||
val devDataSize = getDevDataSize(devTypeByte)
|
val devDataSize = getDevDataSize(devTypeByte)
|
||||||
|
|
||||||
|
println("payload $devDataSize")
|
||||||
bleTableOffset += 2
|
bleTableOffset += 2
|
||||||
|
|
||||||
if (devDataSize != 0) {
|
if (devDataSize != 0) {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,13 @@ package llc.arma.ble.data.repository
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.icu.text.SimpleDateFormat
|
import android.icu.text.SimpleDateFormat
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import com.patrykandpatrick.vico.core.entry.ChartEntryModelProducer
|
||||||
import llc.arma.ble.R
|
import llc.arma.ble.R
|
||||||
|
import llc.arma.ble.app.ui.screen.inspection.host.view.HostEntry
|
||||||
|
import llc.arma.ble.app.ui.screen.inspection.host.view.colorsStack
|
||||||
import llc.arma.ble.domain.model.Ble
|
import llc.arma.ble.domain.model.Ble
|
||||||
import llc.arma.ble.domain.repository.XlsxRepository
|
import llc.arma.ble.domain.repository.XlsxRepository
|
||||||
import org.apache.poi.ss.usermodel.WorkbookFactory
|
import org.apache.poi.ss.usermodel.WorkbookFactory
|
||||||
|
|
@ -20,13 +26,13 @@ class XlsxRepositoryImpl @Inject constructor(
|
||||||
private val application: Application
|
private val application: Application
|
||||||
) : XlsxRepository {
|
) : XlsxRepository {
|
||||||
|
|
||||||
override fun exportToXls(
|
override fun exportAccelDataToXls(
|
||||||
bleName: String,
|
bleName: String,
|
||||||
data: List<Ble.Accelerometer.HistoryPoint>
|
data: List<Ble.Accelerometer.HistoryPoint>
|
||||||
): File {
|
): File {
|
||||||
|
|
||||||
val fileNameDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm")
|
val fileNameDateFormat = SimpleDateFormat("yyyy-MM-dd_HH-mm")
|
||||||
val fileName = "${fileNameDateFormat.format(Date(System.currentTimeMillis()))}.xlsx".replace(' ', '_')
|
val fileName = "${fileNameDateFormat.format(Date(System.currentTimeMillis()))}.xlsx"
|
||||||
|
|
||||||
val formatter = SimpleDateFormat("dd.MM.yyyy HH:mm")
|
val formatter = SimpleDateFormat("dd.MM.yyyy HH:mm")
|
||||||
|
|
||||||
|
|
@ -105,4 +111,64 @@ class XlsxRepositoryImpl @Inject constructor(
|
||||||
return mailFile
|
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
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -5,9 +5,14 @@ import java.io.File
|
||||||
|
|
||||||
interface XlsxRepository {
|
interface XlsxRepository {
|
||||||
|
|
||||||
fun exportToXls(
|
fun exportAccelDataToXls(
|
||||||
bleName: String,
|
bleName: String,
|
||||||
data: List<Ble.Accelerometer.HistoryPoint>
|
data: List<Ble.Accelerometer.HistoryPoint>
|
||||||
): File
|
): File
|
||||||
|
|
||||||
|
fun exportHostDataToXls(
|
||||||
|
bleName: String,
|
||||||
|
data: List<Ble.Host.HistoryPoint>
|
||||||
|
): File
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -15,7 +15,18 @@ class ExportToXlsx @Inject constructor(
|
||||||
data: List<Ble.Accelerometer.HistoryPoint>
|
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)
|
emailRepository.sendFile(file)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue