Skip to content

Commit f247ca5

Browse files
eriedclaude
andcommitted
Inspect tab: range filter (min / max) with hidden count and clear
Two compact text fields above the byte grid: 'min' and 'max'. Cells whose decimal value falls outside [min..max] render at 18% alpha so the offset positions stay aligned (otherwise tapping the wrong cell to log a byte would be too easy). Empty input on either side means 'no bound on that side'. Counter '(N hidden)' appears next to the inputs; an X icon clears both fields. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9108ea9 commit f247ca5

1 file changed

Lines changed: 59 additions & 2 deletions

File tree

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

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
8181
import androidx.compose.runtime.setValue
8282
import androidx.compose.ui.Alignment
8383
import androidx.compose.ui.Modifier
84+
import androidx.compose.ui.draw.alpha
8485
import androidx.compose.ui.graphics.Color
8586
import androidx.compose.ui.platform.LocalContext
8687
import androidx.compose.ui.text.font.FontFamily
@@ -706,6 +707,55 @@ private fun InspectTab(vm: WheelDiagnosticsViewModel) {
706707
return@Column
707708
}
708709

710+
// Range filter: hide bytes outside [min..max]. Empty input on either
711+
// side means "no bound on that side". Hidden cells render dimly so
712+
// the byte offsets stay aligned in the grid (otherwise tapping the
713+
// wrong cell to log would be too easy).
714+
var minFilterText by rememberSaveable { mutableStateOf("") }
715+
var maxFilterText by rememberSaveable { mutableStateOf("") }
716+
val minFilter = minFilterText.toIntOrNull()
717+
val maxFilter = maxFilterText.toIntOrNull()
718+
fun outOfRange(v: Int): Boolean =
719+
(minFilter != null && v < minFilter) || (maxFilter != null && v > maxFilter)
720+
val hiddenCount = latestBytes.count { outOfRange(it) }
721+
722+
Row(
723+
verticalAlignment = Alignment.CenterVertically,
724+
modifier = Modifier.fillMaxWidth().padding(bottom = 6.dp)
725+
) {
726+
androidx.compose.material3.OutlinedTextField(
727+
value = minFilterText,
728+
onValueChange = { v -> minFilterText = v.filter { it.isDigit() } },
729+
label = { Text("min", style = MaterialTheme.typography.labelSmall) },
730+
singleLine = true,
731+
modifier = Modifier.width(80.dp),
732+
textStyle = MaterialTheme.typography.bodySmall
733+
)
734+
Spacer(Modifier.width(6.dp))
735+
androidx.compose.material3.OutlinedTextField(
736+
value = maxFilterText,
737+
onValueChange = { v -> maxFilterText = v.filter { it.isDigit() } },
738+
label = { Text("max", style = MaterialTheme.typography.labelSmall) },
739+
singleLine = true,
740+
modifier = Modifier.width(80.dp),
741+
textStyle = MaterialTheme.typography.bodySmall
742+
)
743+
Spacer(Modifier.width(8.dp))
744+
if (hiddenCount > 0) {
745+
Text(
746+
"($hiddenCount hidden)",
747+
style = MaterialTheme.typography.labelSmall,
748+
color = MaterialTheme.colorScheme.onSurfaceVariant
749+
)
750+
}
751+
Spacer(Modifier.weight(1f))
752+
if (minFilter != null || maxFilter != null) {
753+
IconButton(onClick = { minFilterText = ""; maxFilterText = "" }) {
754+
Icon(Icons.Default.Close, contentDescription = "Clear filter")
755+
}
756+
}
757+
}
758+
709759
// 6-column grid of byte cells. weight(1f) claims the leftover Column
710760
// height so the bottom row isn't clipped — the earlier fillMaxSize
711761
// approach was reading "as much as you want" rather than "exactly
@@ -717,7 +767,7 @@ private fun InspectTab(vm: WheelDiagnosticsViewModel) {
717767
) {
718768
items(latestBytes.size) { off ->
719769
val v = latestBytes[off]
720-
ByteInspectCell(off, v) {
770+
ByteInspectCell(off, v, dimmed = outOfRange(v)) {
721771
vm.logByteInspection(selected, off, v)
722772
}
723773
}
@@ -726,11 +776,18 @@ private fun InspectTab(vm: WheelDiagnosticsViewModel) {
726776
}
727777

728778
@Composable
729-
private fun ByteInspectCell(offset: Int, value: Int, onTap: () -> Unit) {
779+
private fun ByteInspectCell(
780+
offset: Int,
781+
value: Int,
782+
dimmed: Boolean = false,
783+
onTap: () -> Unit
784+
) {
730785
val hex = remember(value) { "%02x".format(value) }
786+
val cellAlpha = if (dimmed) 0.18f else 1f
731787
Column(
732788
modifier = Modifier
733789
.padding(2.dp)
790+
.alpha(cellAlpha)
734791
.border(
735792
1.dp,
736793
MaterialTheme.colorScheme.outline.copy(alpha = 0.3f),

0 commit comments

Comments
 (0)