Skip to content

Commit 69f3acf

Browse files
eriedclaude
andcommitted
0.4.0-preview6: square shapes everywhere, EUC motor temp tiers, placeholder fix
UI: - Every Button / OutlinedButton / TextButton / OutlinedTextField / AssistChip / AlertDialog now passes shape = RoundedCornerShape(0.dp). Material3 Buttons defaulted to a pill shape that ignored MaterialTheme.shapes, so Service Mode still looked rounded after the theme override. Now every component is hard-edged. - Commands tab: each command button is a fixed 80.dp tall so the row layout stays uniform with 2-line descriptions; outer LazyColumn gets contentPadding(bottom = 24.dp) so the last category clears the dialog edge. - Inspect grid: contentPadding(bottom = 16.dp) so the last byte row doesn't kiss the dialog frame. Dashboard: - Temp / battery / voltage stat cards now show the placeholder ("-") instead of a deceptive "0%" / "0.0V" / "32 °F" when the parser hasn't decoded a real value yet (the 32 °F bug was the Fahrenheit conversion of an internal 0 °C reading — looked like a real freezer reading, was actually "no data"). - Placeholder changed from em-dash to ASCII hyphen. - Temp color tiers raised to EUC-realistic thresholds: <70 °C green 70-90 yellow 90-105 orange >105 red (always evaluated on stored °C so the rule holds for °C and °F users). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0044235 commit 69f3acf

5 files changed

Lines changed: 142 additions & 47 deletions

File tree

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ android {
2727
applicationId = "com.eried.eucplanet"
2828
minSdk = 29
2929
targetSdk = 35
30-
versionCode = 30
31-
versionName = "0.4.0-preview4"
30+
versionCode = 32
31+
versionName = "0.4.0-preview6"
3232

3333
val buildStamp = SimpleDateFormat("yyMMdd.HHmm")
3434
.apply { timeZone = TimeZone.getTimeZone("UTC") }

app/src/main/java/com/eried/eucplanet/diagnostics/WheelDiagnosticsDialog.kt

Lines changed: 70 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,21 @@ fun WheelDiagnosticsDialog(
200200

201201
if (stopConfirm) {
202202
AlertDialog(
203+
shape = RoundedCornerShape(0.dp),
203204
onDismissRequest = { stopConfirm = false },
204205
title = { Text("Exit Service Mode") },
205206
text = {
206207
Text("This clears the in-memory log and exits Service Mode.\n\nShare the log first if you need it.")
207208
},
208209
confirmButton = {
209-
TextButton(onClick = {
210+
TextButton(shape = RoundedCornerShape(0.dp), onClick = {
210211
stopConfirm = false
211212
vm.stopDiagnostics()
212213
onDismiss()
213214
}) { Text("Exit") }
214215
},
215216
dismissButton = {
216-
TextButton(onClick = { stopConfirm = false }) { Text("Cancel") }
217+
TextButton(shape = RoundedCornerShape(0.dp), onClick = { stopConfirm = false }) { Text("Cancel") }
217218
}
218219
)
219220
}
@@ -308,7 +309,7 @@ private fun CommentRow(vm: WheelDiagnosticsViewModel) {
308309
comment = ""
309310
}
310311
}
311-
OutlinedTextField(
312+
OutlinedTextField(shape = RoundedCornerShape(0.dp),
312313
value = comment,
313314
onValueChange = { comment = it },
314315
modifier = Modifier.weight(1f),
@@ -353,6 +354,7 @@ private fun AttachDataDialog(
353354
}
354355
}
355356
AlertDialog(
357+
shape = RoundedCornerShape(0.dp),
356358
onDismissRequest = onDismiss,
357359
title = { Text("Attach data to log") },
358360
text = {
@@ -382,15 +384,15 @@ private fun AttachDataDialog(
382384
},
383385
confirmButton = {
384386
val any = selected.values.any { it }
385-
TextButton(
387+
TextButton(shape = RoundedCornerShape(0.dp),
386388
enabled = any,
387389
onClick = {
388390
onSubmit(selected.filterValues { it }.keys)
389391
}
390392
) { Text("Attach") }
391393
},
392394
dismissButton = {
393-
TextButton(onClick = onDismiss) { Text("Cancel") }
395+
TextButton(shape = RoundedCornerShape(0.dp), onClick = onDismiss) { Text("Cancel") }
394396
}
395397
)
396398
}
@@ -474,7 +476,7 @@ private fun CommandsTab(vm: WheelDiagnosticsViewModel) {
474476

475477
Column(modifier = Modifier.fillMaxSize()) {
476478
Box(modifier = Modifier.padding(top = 8.dp, start = 4.dp)) {
477-
OutlinedButton(onClick = { familyMenuExpanded = true }) {
479+
OutlinedButton(shape = RoundedCornerShape(0.dp), onClick = { familyMenuExpanded = true }) {
478480
Text(selectedFamily?.displayName ?: "(no families)")
479481
Spacer(Modifier.width(6.dp))
480482
Icon(
@@ -523,7 +525,17 @@ private fun CommandsTab(vm: WheelDiagnosticsViewModel) {
523525

524526
val grouped = remember(cmds) { cmds.groupBy { it.category } }
525527

526-
LazyColumn(modifier = Modifier.fillMaxSize().padding(top = 8.dp)) {
528+
// Each command button has a fixed height that fits the label + a
529+
// 2-line description; this keeps the grid uniform regardless of
530+
// description length and lets the heightIn() calculation below land
531+
// exactly on the row's true size (so the last row can't bleed
532+
// outside its slot and get clipped). Bottom contentPadding gives
533+
// the final category breathing room from the dialog edge.
534+
val commandButtonHeight = 80.dp
535+
LazyColumn(
536+
modifier = Modifier.fillMaxSize().padding(top = 8.dp),
537+
contentPadding = PaddingValues(bottom = 24.dp)
538+
) {
527539
grouped.forEach { (category, list) ->
528540
item {
529541
Text(
@@ -534,22 +546,34 @@ private fun CommandsTab(vm: WheelDiagnosticsViewModel) {
534546
)
535547
}
536548
item {
549+
val rows = (list.size + 2) / 3
537550
LazyVerticalGrid(
538551
columns = GridCells.Adaptive(110.dp),
539552
contentPadding = PaddingValues(2.dp),
540553
horizontalArrangement = Arrangement.spacedBy(6.dp),
541554
verticalArrangement = Arrangement.spacedBy(6.dp),
542555
modifier = Modifier
543556
.fillMaxWidth()
544-
.heightIn(max = (((list.size + 2) / 3) * 64 + 16).dp)
557+
// Each row = button height (80) + vertical spacing (6).
558+
// Plus the contentPadding's 2*2dp.
559+
.heightIn(max = (rows * 80 + (rows - 1).coerceAtLeast(0) * 6 + 4).dp)
545560
) {
546561
items(list) { cmd ->
547562
OutlinedButton(
563+
shape = RoundedCornerShape(0.dp),
548564
onClick = { vm.fireCommand(cmd) },
549-
modifier = Modifier.fillMaxWidth()
565+
modifier = Modifier
566+
.fillMaxWidth()
567+
.height(commandButtonHeight),
568+
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp)
550569
) {
551570
Column {
552-
Text(cmd.label, style = MaterialTheme.typography.labelLarge)
571+
Text(
572+
cmd.label,
573+
style = MaterialTheme.typography.labelLarge,
574+
maxLines = 1,
575+
overflow = TextOverflow.Ellipsis
576+
)
553577
Text(
554578
cmd.description,
555579
style = MaterialTheme.typography.labelSmall,
@@ -637,7 +661,7 @@ private fun InspectTab(vm: WheelDiagnosticsViewModel) {
637661
// their options; families with one prefix auto-pick it.
638662
Row(verticalAlignment = Alignment.CenterVertically) {
639663
Box {
640-
OutlinedButton(onClick = { familyMenuExpanded = true }) {
664+
OutlinedButton(shape = RoundedCornerShape(0.dp), onClick = { familyMenuExpanded = true }) {
641665
Text(selectedFamily?.displayName ?: "")
642666
Spacer(Modifier.width(6.dp))
643667
Icon(
@@ -666,7 +690,7 @@ private fun InspectTab(vm: WheelDiagnosticsViewModel) {
666690
val familyName = selectedFamily?.displayName ?: ""
667691
val singleOption = types.size <= 1
668692
Box {
669-
OutlinedButton(
693+
OutlinedButton(shape = RoundedCornerShape(0.dp),
670694
onClick = { if (!singleOption) menuExpanded = true },
671695
enabled = !singleOption
672696
) {
@@ -723,7 +747,7 @@ private fun InspectTab(vm: WheelDiagnosticsViewModel) {
723747
verticalAlignment = Alignment.CenterVertically,
724748
modifier = Modifier.fillMaxWidth().padding(bottom = 6.dp)
725749
) {
726-
androidx.compose.material3.OutlinedTextField(
750+
androidx.compose.material3.OutlinedTextField(shape = RoundedCornerShape(0.dp),
727751
value = minFilterText,
728752
onValueChange = { v -> minFilterText = v.filter { it.isDigit() } },
729753
label = { Text("min", style = MaterialTheme.typography.labelSmall) },
@@ -732,7 +756,7 @@ private fun InspectTab(vm: WheelDiagnosticsViewModel) {
732756
textStyle = MaterialTheme.typography.bodySmall
733757
)
734758
Spacer(Modifier.width(6.dp))
735-
androidx.compose.material3.OutlinedTextField(
759+
androidx.compose.material3.OutlinedTextField(shape = RoundedCornerShape(0.dp),
736760
value = maxFilterText,
737761
onValueChange = { v -> maxFilterText = v.filter { it.isDigit() } },
738762
label = { Text("max", style = MaterialTheme.typography.labelSmall) },
@@ -757,13 +781,12 @@ private fun InspectTab(vm: WheelDiagnosticsViewModel) {
757781
}
758782

759783
// 6-column grid of byte cells. weight(1f) claims the leftover Column
760-
// height so the bottom row isn't clipped — the earlier fillMaxSize
761-
// approach was reading "as much as you want" rather than "exactly
762-
// the leftover after headers", which let the grid request more than
763-
// the column had and the last row was cropped.
784+
// height so the bottom row isn't clipped, plus a bottom contentPadding
785+
// so the last row doesn't kiss the dialog edge.
764786
LazyVerticalGrid(
765787
columns = GridCells.Fixed(6),
766-
modifier = Modifier.weight(1f).fillMaxWidth()
788+
modifier = Modifier.weight(1f).fillMaxWidth(),
789+
contentPadding = PaddingValues(bottom = 16.dp)
767790
) {
768791
items(latestBytes.size) { off ->
769792
val v = latestBytes[off]
@@ -791,7 +814,7 @@ private fun ByteInspectCell(
791814
.border(
792815
1.dp,
793816
MaterialTheme.colorScheme.outline.copy(alpha = 0.3f),
794-
RoundedCornerShape(4.dp)
817+
RoundedCornerShape(0.dp)
795818
)
796819
.clickable(onClick = onTap)
797820
.padding(4.dp),
@@ -889,7 +912,7 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
889912
)
890913
} else {
891914
Box(modifier = Modifier.padding(top = 4.dp, bottom = 6.dp)) {
892-
OutlinedButton(onClick = { presetMenuOpen = true }) {
915+
OutlinedButton(shape = RoundedCornerShape(0.dp), onClick = { presetMenuOpen = true }) {
893916
Text(activePresetFamily.displayName)
894917
Spacer(Modifier.width(6.dp))
895918
Icon(Icons.Default.KeyboardArrowDown, contentDescription = null)
@@ -911,7 +934,7 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
911934
val hex = remember(cmd.bytes) {
912935
cmd.bytes.joinToString(" ") { "%02x".format(it) }
913936
}
914-
AssistChip(
937+
AssistChip(shape = RoundedCornerShape(0.dp),
915938
onClick = { appendBytes(hex) },
916939
label = {
917940
Column {
@@ -940,7 +963,7 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
940963
Column(modifier = Modifier.padding(top = 4.dp)) {
941964
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(2.dp)) {
942965
hexChars.subList(0, 8).forEach { c ->
943-
OutlinedButton(
966+
OutlinedButton(shape = RoundedCornerShape(0.dp),
944967
onClick = { appendChar(c) },
945968
modifier = Modifier.weight(1f).height(40.dp),
946969
contentPadding = PaddingValues(0.dp)
@@ -950,7 +973,7 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
950973
Spacer(Modifier.height(2.dp))
951974
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(2.dp)) {
952975
hexChars.subList(8, 16).forEach { c ->
953-
OutlinedButton(
976+
OutlinedButton(shape = RoundedCornerShape(0.dp),
954977
onClick = { appendChar(c) },
955978
modifier = Modifier.weight(1f).height(40.dp),
956979
contentPadding = PaddingValues(0.dp)
@@ -959,25 +982,25 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
959982
}
960983
Spacer(Modifier.height(2.dp))
961984
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(2.dp)) {
962-
OutlinedButton(
985+
OutlinedButton(shape = RoundedCornerShape(0.dp),
963986
onClick = { appendChar(' ') },
964987
modifier = Modifier.weight(1f).height(40.dp),
965988
contentPadding = PaddingValues(0.dp)
966989
) { Text("space", style = MaterialTheme.typography.labelSmall) }
967-
OutlinedButton(
990+
OutlinedButton(shape = RoundedCornerShape(0.dp),
968991
onClick = { if (raw.isNotEmpty()) setRaw(raw.dropLast(1)) },
969992
modifier = Modifier.weight(1f).height(40.dp),
970993
contentPadding = PaddingValues(0.dp)
971994
) { Icon(Icons.Default.Backspace, contentDescription = "Backspace", modifier = Modifier.size(18.dp)) }
972995
// stackVersion read here so recomposition fires on push/pop
973996
@Suppress("UNUSED_VARIABLE") val v = stackVersion
974-
OutlinedButton(
997+
OutlinedButton(shape = RoundedCornerShape(0.dp),
975998
onClick = { undo() },
976999
enabled = undoStack.isNotEmpty(),
9771000
modifier = Modifier.weight(1f).height(40.dp),
9781001
contentPadding = PaddingValues(0.dp)
9791002
) { Icon(Icons.AutoMirrored.Filled.Undo, contentDescription = "Undo", modifier = Modifier.size(18.dp)) }
980-
OutlinedButton(
1003+
OutlinedButton(shape = RoundedCornerShape(0.dp),
9811004
onClick = { redo() },
9821005
enabled = redoStack.isNotEmpty(),
9831006
modifier = Modifier.weight(1f).height(40.dp),
@@ -994,7 +1017,7 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
9941017
modifier = Modifier.fillMaxWidth(),
9951018
verticalAlignment = Alignment.CenterVertically
9961019
) {
997-
OutlinedTextField(
1020+
OutlinedTextField(shape = RoundedCornerShape(0.dp),
9981021
value = raw,
9991022
onValueChange = { setRaw(it) },
10001023
modifier = Modifier.weight(1f),
@@ -1006,11 +1029,11 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
10061029
)
10071030
Spacer(Modifier.width(6.dp))
10081031
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
1009-
OutlinedButton(
1032+
OutlinedButton(shape = RoundedCornerShape(0.dp),
10101033
onClick = { setRaw(vm.formatHex(raw)) },
10111034
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp)
10121035
) { Text("fmt") }
1013-
OutlinedButton(
1036+
OutlinedButton(shape = RoundedCornerShape(0.dp),
10141037
onClick = { if (raw.isNotEmpty()) setRaw("") },
10151038
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp)
10161039
) { Text("cls") }
@@ -1023,17 +1046,28 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
10231046
title = "Wrap mode: ${mode.name.lowercase().replace('_', ' ')}",
10241047
defaultExpanded = false
10251048
) {
1049+
// Veteran and Begode commands are literal (fixed opcodes / ASCII
1050+
// strings already including their full wire format), so LITERAL
1051+
// covers them — no separate WRAP_VETERAN / WRAP_BEGODE entries.
1052+
// The segmented row stays scrollable so newer protocols can
1053+
// join without redesigning the layout.
10261054
val modes = listOf(
10271055
WheelDiagnosticsViewModel.WrapMode.LITERAL to "Literal",
1028-
WheelDiagnosticsViewModel.WrapMode.WRAP_EXTENDED to "Wrap V2",
1029-
WheelDiagnosticsViewModel.WrapMode.WRAP_V14_SHORT to "Wrap V14"
1056+
WheelDiagnosticsViewModel.WrapMode.WRAP_EXTENDED to "V2 ext",
1057+
WheelDiagnosticsViewModel.WrapMode.WRAP_V14_SHORT to "V14",
1058+
WheelDiagnosticsViewModel.WrapMode.WRAP_KINGSONG to "KS",
1059+
WheelDiagnosticsViewModel.WrapMode.WRAP_NINEBOT_LEGACY to "9bot",
1060+
WheelDiagnosticsViewModel.WrapMode.WRAP_INMOTION_V1 to "V1"
10301061
)
10311062
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth().padding(top = 4.dp)) {
10321063
modes.forEachIndexed { index, (m, label) ->
10331064
SegmentedButton(
10341065
selected = mode == m,
10351066
onClick = { mode = m },
1036-
shape = SegmentedButtonDefaults.itemShape(index = index, count = modes.size)
1067+
// Force square corners on the segmented row to match
1068+
// the rest of Service Mode (the default itemShape
1069+
// gives rounded ends that bypassed the theme).
1070+
shape = RoundedCornerShape(0.dp)
10371071
) { Text(label) }
10381072
}
10391073
}
@@ -1049,7 +1083,7 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
10491083
// Read-only output field. Filled background + dimmed border so it
10501084
// visually contrasts with the editable Input field above.
10511085
val readOnlyContainer = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.6f)
1052-
OutlinedTextField(
1086+
OutlinedTextField(shape = RoundedCornerShape(0.dp),
10531087
value = preview.display,
10541088
onValueChange = {},
10551089
readOnly = true,
@@ -1073,7 +1107,7 @@ private fun RawTab(vm: WheelDiagnosticsViewModel) {
10731107
// Match fmt/cls in the hex-input row: same OutlinedButton, same
10741108
// compact padding so the dialog doesn't have one giant CTA when
10751109
// the rest of the right column is small chips.
1076-
OutlinedButton(
1110+
OutlinedButton(shape = RoundedCornerShape(0.dp),
10771111
onClick = { vm.fireRawHex(raw, mode) },
10781112
enabled = canSend,
10791113
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp)

0 commit comments

Comments
 (0)