feat: add BLM/INT heatmap table with RPM/MAP bands
This commit is contained in:
@@ -2,6 +2,7 @@ package com.example.esp32aldldashboard
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import com.example.esp32aldldashboard.bluetooth.BluetoothService
|
import com.example.esp32aldldashboard.bluetooth.BluetoothService
|
||||||
|
import com.example.esp32aldldashboard.repository.BLMTableRepository
|
||||||
import com.example.esp32aldldashboard.repository.ChartPreferencesRepository
|
import com.example.esp32aldldashboard.repository.ChartPreferencesRepository
|
||||||
import com.example.esp32aldldashboard.repository.SettingsRepository
|
import com.example.esp32aldldashboard.repository.SettingsRepository
|
||||||
import com.example.esp32aldldashboard.repository.TelemetryRepository
|
import com.example.esp32aldldashboard.repository.TelemetryRepository
|
||||||
@@ -17,12 +18,14 @@ class AldlApplication : Application() {
|
|||||||
lateinit var csvLogger: CsvLogger
|
lateinit var csvLogger: CsvLogger
|
||||||
lateinit var rawStreamLogger: RawStreamLogger
|
lateinit var rawStreamLogger: RawStreamLogger
|
||||||
lateinit var chartPreferencesRepository: ChartPreferencesRepository
|
lateinit var chartPreferencesRepository: ChartPreferencesRepository
|
||||||
|
lateinit var blmTableRepository: BLMTableRepository
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
val database = TelemetryDatabase.getDatabase(this)
|
val database = TelemetryDatabase.getDatabase(this)
|
||||||
settingsRepository = SettingsRepository(this)
|
settingsRepository = SettingsRepository(this)
|
||||||
chartPreferencesRepository = ChartPreferencesRepository(this)
|
chartPreferencesRepository = ChartPreferencesRepository(this)
|
||||||
|
blmTableRepository = BLMTableRepository()
|
||||||
csvLogger = CsvLogger(this)
|
csvLogger = CsvLogger(this)
|
||||||
rawStreamLogger = RawStreamLogger(this)
|
rawStreamLogger = RawStreamLogger(this)
|
||||||
bluetoothService = BluetoothService(this, rawStreamLogger, settingsRepository)
|
bluetoothService = BluetoothService(this, rawStreamLogger, settingsRepository)
|
||||||
@@ -31,7 +34,8 @@ class AldlApplication : Application() {
|
|||||||
bluetoothService,
|
bluetoothService,
|
||||||
database.telemetryDao(),
|
database.telemetryDao(),
|
||||||
csvLogger,
|
csvLogger,
|
||||||
settingsRepository
|
settingsRepository,
|
||||||
|
blmTableRepository
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,122 @@
|
|||||||
|
package com.example.esp32aldldashboard.repository
|
||||||
|
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
|
data class BLMCellData(
|
||||||
|
val blm: Int = 128,
|
||||||
|
val intValue: Int = 128,
|
||||||
|
val updateCount: Int = 0,
|
||||||
|
val lastUpdateTime: Long = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
class BLMTableRepository {
|
||||||
|
|
||||||
|
// RPM bands as specified by ECM
|
||||||
|
val rpmBands = listOf(600, 800, 1000, 1200, 1400, 1600, 2000, 2400, 2800, 3200, 3600, 4000, 4400, 4800)
|
||||||
|
|
||||||
|
// MAP bands as specified by ECM
|
||||||
|
val mapBands = listOf(20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100)
|
||||||
|
|
||||||
|
private val rowCount = rpmBands.size
|
||||||
|
private val colCount = mapBands.size
|
||||||
|
|
||||||
|
// 2D array [RPM bands × MAP bands]
|
||||||
|
private val _tableData = MutableStateFlow(
|
||||||
|
Array(rowCount) { Array(colCount) { BLMCellData() } }
|
||||||
|
)
|
||||||
|
val tableData: StateFlow<Array<Array<BLMCellData>>> = _tableData
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the cell corresponding to the nearest RPM and MAP bands.
|
||||||
|
* Values are retained until replaced by new updates.
|
||||||
|
*/
|
||||||
|
fun updateCell(rpm: Int, mapKpa: Float, blm: Int, intValue: Int) {
|
||||||
|
val rpmIndex = findNearestBandIndex(rpm, rpmBands)
|
||||||
|
val mapIndex = findNearestBandIndex(mapKpa.toInt(), mapBands)
|
||||||
|
|
||||||
|
if (rpmIndex >= 0 && rpmIndex < rowCount && mapIndex >= 0 && mapIndex < colCount) {
|
||||||
|
val currentData = _tableData.value
|
||||||
|
val newData = currentData.map { row -> row.map { it }.toTypedArray() }.toTypedArray()
|
||||||
|
|
||||||
|
val existing = newData[rpmIndex][mapIndex]
|
||||||
|
newData[rpmIndex][mapIndex] = BLMCellData(
|
||||||
|
blm = blm,
|
||||||
|
intValue = intValue,
|
||||||
|
updateCount = existing.updateCount + 1,
|
||||||
|
lastUpdateTime = System.currentTimeMillis()
|
||||||
|
)
|
||||||
|
|
||||||
|
_tableData.value = newData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all table data, resetting to default values.
|
||||||
|
*/
|
||||||
|
fun clearTable() {
|
||||||
|
_tableData.value = Array(rowCount) { Array(colCount) { BLMCellData() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the color for a BLM value.
|
||||||
|
* Blue at 128 (center), Green at 120 (lean), Red at 150 (rich)
|
||||||
|
* Returns ARGB color value
|
||||||
|
*/
|
||||||
|
fun getBLMColor(blm: Int): Long {
|
||||||
|
return when {
|
||||||
|
blm <= 120 -> {
|
||||||
|
// Green (120 and below)
|
||||||
|
0xFF00E676
|
||||||
|
}
|
||||||
|
blm >= 150 -> {
|
||||||
|
// Red (150 and above)
|
||||||
|
0xFFFF3D00
|
||||||
|
}
|
||||||
|
blm <= 128 -> {
|
||||||
|
// Interpolate between Green (120) and Blue (128)
|
||||||
|
val fraction = (blm - 120) / 8f
|
||||||
|
interpolateColor(0xFF00E676, 0xFF2196F3, fraction)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// Interpolate between Blue (128) and Red (150)
|
||||||
|
val fraction = (blm - 128) / 22f
|
||||||
|
interpolateColor(0xFF2196F3, 0xFFFF3D00, fraction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun interpolateColor(color1: Long, color2: Long, fraction: Float): Long {
|
||||||
|
val r1 = (color1 shr 16) and 0xFF
|
||||||
|
val g1 = (color1 shr 8) and 0xFF
|
||||||
|
val b1 = color1 and 0xFF
|
||||||
|
|
||||||
|
val r2 = (color2 shr 16) and 0xFF
|
||||||
|
val g2 = (color2 shr 8) and 0xFF
|
||||||
|
val b2 = color2 and 0xFF
|
||||||
|
|
||||||
|
val r = (r1 + (r2 - r1) * fraction).toInt()
|
||||||
|
val g = (g1 + (g2 - g1) * fraction).toInt()
|
||||||
|
val b = (b1 + (b2 - b1) * fraction).toInt()
|
||||||
|
|
||||||
|
return 0xFF000000 or (r.toLong() shl 16) or (g.toLong() shl 8) or b.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findNearestBandIndex(value: Int, bands: List<Int>): Int {
|
||||||
|
if (bands.isEmpty()) return -1
|
||||||
|
|
||||||
|
var nearestIndex = 0
|
||||||
|
var minDiff = abs(value - bands[0])
|
||||||
|
|
||||||
|
for (i in 1 until bands.size) {
|
||||||
|
val diff = abs(value - bands[i])
|
||||||
|
if (diff < minDiff) {
|
||||||
|
minDiff = diff
|
||||||
|
nearestIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nearestIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
-10
@@ -23,7 +23,8 @@ class TelemetryRepository(
|
|||||||
private val bluetoothService: BluetoothService,
|
private val bluetoothService: BluetoothService,
|
||||||
private val telemetryDao: TelemetryDao,
|
private val telemetryDao: TelemetryDao,
|
||||||
private val csvLogger: CsvLogger,
|
private val csvLogger: CsvLogger,
|
||||||
private val settingsRepository: SettingsRepository
|
private val settingsRepository: SettingsRepository,
|
||||||
|
private val blmTableRepository: BLMTableRepository
|
||||||
) {
|
) {
|
||||||
private val repoScope = CoroutineScope(Dispatchers.IO + Job())
|
private val repoScope = CoroutineScope(Dispatchers.IO + Job())
|
||||||
private var currentSessionId: Long? = null
|
private var currentSessionId: Long? = null
|
||||||
@@ -65,15 +66,25 @@ class TelemetryRepository(
|
|||||||
private fun observeTelemetry() {
|
private fun observeTelemetry() {
|
||||||
repoScope.launch {
|
repoScope.launch {
|
||||||
bluetoothService.latestFrame.collectLatest { frame ->
|
bluetoothService.latestFrame.collectLatest { frame ->
|
||||||
if (frame != null && isRecording) {
|
if (frame != null) {
|
||||||
csvLogger.logFrame(frame)
|
// Update BLM table with every frame (not just when recording)
|
||||||
currentSessionId?.let { sid ->
|
blmTableRepository.updateCell(
|
||||||
val dataPoint = TelemetryDataPointEntity(
|
rpm = frame.engineSpeedRpm,
|
||||||
sessionId = sid,
|
mapKpa = frame.mapKpa,
|
||||||
timestamp = frame.timestamp,
|
blm = frame.blm,
|
||||||
rawBytes = frame.rawBytes
|
intValue = frame.integrator
|
||||||
)
|
)
|
||||||
telemetryDao.insertDataPoints(listOf(dataPoint))
|
|
||||||
|
if (isRecording) {
|
||||||
|
csvLogger.logFrame(frame)
|
||||||
|
currentSessionId?.let { sid ->
|
||||||
|
val dataPoint = TelemetryDataPointEntity(
|
||||||
|
sessionId = sid,
|
||||||
|
timestamp = frame.timestamp,
|
||||||
|
rawBytes = frame.rawBytes
|
||||||
|
)
|
||||||
|
telemetryDao.insertDataPoints(listOf(dataPoint))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,226 @@
|
|||||||
|
package com.example.esp32aldldashboard.ui.blm
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.example.esp32aldldashboard.repository.BLMTableRepository
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun BLMTableScreen(
|
||||||
|
viewModel: BLMTableViewModel,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val tableData by viewModel.tableData.collectAsStateWithLifecycle()
|
||||||
|
val rpmBands = viewModel.rpmBands
|
||||||
|
val mapBands = viewModel.mapBands
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(16.dp)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
// Header with title and clear button
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = "BLM/INT Table",
|
||||||
|
style = MaterialTheme.typography.headlineMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "RPM (vertical) × MAP (horizontal)",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = { viewModel.clearTable() },
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.error
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Text("Clear")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Legend
|
||||||
|
BLMLegend()
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
// Table container
|
||||||
|
Column {
|
||||||
|
// MAP headers (top)
|
||||||
|
Row {
|
||||||
|
// Empty corner cell
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(60.dp)
|
||||||
|
.background(Color(0xFF2C2C2C))
|
||||||
|
.border(1.dp, Color(0xFF3C3C3C)),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "RPM\\MAP",
|
||||||
|
fontSize = 10.sp,
|
||||||
|
color = Color.Gray,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MAP band headers
|
||||||
|
mapBands.forEach { map ->
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(50.dp)
|
||||||
|
.height(60.dp)
|
||||||
|
.background(Color(0xFF2C2C2C))
|
||||||
|
.border(1.dp, Color(0xFF3C3C3C)),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "$map",
|
||||||
|
fontSize = 11.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = Color(0xFF00E5FF),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data rows
|
||||||
|
rpmBands.forEachIndexed { rowIndex, rpm ->
|
||||||
|
Row {
|
||||||
|
// RPM band header (left)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(60.dp)
|
||||||
|
.height(50.dp)
|
||||||
|
.background(Color(0xFF2C2C2C))
|
||||||
|
.border(1.dp, Color(0xFF3C3C3C)),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "$rpm",
|
||||||
|
fontSize = 11.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = Color(0xFF00E5FF),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data cells
|
||||||
|
if (rowIndex < tableData.size) {
|
||||||
|
tableData[rowIndex].forEach { cell ->
|
||||||
|
val colorArgb = viewModel.getBLMColor(cell.blm)
|
||||||
|
val cellColor = Color(colorArgb)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(50.dp)
|
||||||
|
.height(50.dp)
|
||||||
|
.background(cellColor.copy(alpha = 0.3f))
|
||||||
|
.border(1.dp, cellColor),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = "${cell.blm}",
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = if (cell.blm > 140 || cell.blm < 116) Color.White else Color.Black
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "${cell.intValue}",
|
||||||
|
fontSize = 10.sp,
|
||||||
|
color = if (cell.blm > 140 || cell.blm < 116) Color.White.copy(alpha = 0.7f) else Color.Black.copy(alpha = 0.7f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun BLMLegend() {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = Color(0xFF1E1E1E))
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(12.dp)) {
|
||||||
|
Text(
|
||||||
|
text = "Color Legend",
|
||||||
|
fontSize = 12.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly
|
||||||
|
) {
|
||||||
|
LegendItem(color = Color(0xFF00E676), label = "≤120 Lean", textColor = Color.White)
|
||||||
|
LegendItem(color = Color(0xFF2196F3), label = "128 Ideal", textColor = Color.White)
|
||||||
|
LegendItem(color = Color(0xFFFF3D00), label = "≥150 Rich", textColor = Color.White)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "BLM = Block Learn Multiplier (fuel trim). INT = Integrator (short-term correction). Values show most recent update.",
|
||||||
|
fontSize = 10.sp,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun LegendItem(color: Color, label: String, textColor: Color) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(16.dp)
|
||||||
|
.background(color, shape = RoundedCornerShape(2.dp))
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
Text(
|
||||||
|
text = label,
|
||||||
|
fontSize = 10.sp,
|
||||||
|
color = textColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.Info
|
import androidx.compose.material.icons.filled.Info
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material.icons.filled.ShowChart
|
import androidx.compose.material.icons.filled.ShowChart
|
||||||
|
import androidx.compose.material.icons.filled.TableChart
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@@ -18,6 +19,8 @@ import androidx.core.content.ContextCompat
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.example.esp32aldldashboard.AldlApplication
|
import com.example.esp32aldldashboard.AldlApplication
|
||||||
|
import com.example.esp32aldldashboard.ui.blm.BLMTableScreen
|
||||||
|
import com.example.esp32aldldashboard.ui.blm.BLMTableViewModelFactory
|
||||||
import com.example.esp32aldldashboard.ui.charts.ChartsScreen
|
import com.example.esp32aldldashboard.ui.charts.ChartsScreen
|
||||||
import com.example.esp32aldldashboard.ui.settings.SettingsScreen
|
import com.example.esp32aldldashboard.ui.settings.SettingsScreen
|
||||||
|
|
||||||
@@ -96,12 +99,19 @@ fun MainScreen(
|
|||||||
colors = NavigationBarItemDefaults.colors(selectedIconColor = NeonCyan, unselectedIconColor = TextMuted)
|
colors = NavigationBarItemDefaults.colors(selectedIconColor = NeonCyan, unselectedIconColor = TextMuted)
|
||||||
)
|
)
|
||||||
NavigationBarItem(
|
NavigationBarItem(
|
||||||
icon = { Icon(Icons.Default.Settings, contentDescription = "Settings") },
|
icon = { Icon(Icons.Default.TableChart, contentDescription = "BLM Table") },
|
||||||
label = { Text("Settings") },
|
label = { Text("BLM") },
|
||||||
selected = selectedTab == 2,
|
selected = selectedTab == 2,
|
||||||
onClick = { selectedTab = 2 },
|
onClick = { selectedTab = 2 },
|
||||||
colors = NavigationBarItemDefaults.colors(selectedIconColor = NeonCyan, unselectedIconColor = TextMuted)
|
colors = NavigationBarItemDefaults.colors(selectedIconColor = NeonCyan, unselectedIconColor = TextMuted)
|
||||||
)
|
)
|
||||||
|
NavigationBarItem(
|
||||||
|
icon = { Icon(Icons.Default.Settings, contentDescription = "Settings") },
|
||||||
|
label = { Text("Settings") },
|
||||||
|
selected = selectedTab == 3,
|
||||||
|
onClick = { selectedTab = 3 },
|
||||||
|
colors = NavigationBarItemDefaults.colors(selectedIconColor = NeonCyan, unselectedIconColor = TextMuted)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
@@ -120,7 +130,16 @@ fun MainScreen(
|
|||||||
chartPreferencesRepository = app.chartPreferencesRepository,
|
chartPreferencesRepository = app.chartPreferencesRepository,
|
||||||
modifier = modifier.padding(paddingValues)
|
modifier = modifier.padding(paddingValues)
|
||||||
)
|
)
|
||||||
2 -> SettingsScreen(
|
2 -> {
|
||||||
|
val blmViewModel: com.example.esp32aldldashboard.ui.blm.BLMTableViewModel = viewModel(
|
||||||
|
factory = BLMTableViewModelFactory(app.blmTableRepository)
|
||||||
|
)
|
||||||
|
BLMTableScreen(
|
||||||
|
viewModel = blmViewModel,
|
||||||
|
modifier = modifier.padding(paddingValues)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
3 -> SettingsScreen(
|
||||||
settingsRepository = app.settingsRepository,
|
settingsRepository = app.settingsRepository,
|
||||||
modifier = modifier.padding(paddingValues)
|
modifier = modifier.padding(paddingValues)
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user