A setting is a title and a box, and a wait's bar spans the screen

A field's hint had a grey line of its own between the label and the box, so a
form of a dozen settings was mostly explanation. It is the empty box's
placeholder now, where it costs no height and says the same thing to anybody
who has not typed yet.

The wait's bar was drawn in whatever width the status row had left beside its
words, which is where the context figure goes -- so a session loading a model
or reading a prompt stopped saying how full it was, at the moment somebody is
watching it fill. The bar is the whole width above the row instead, the
compaction's indeterminate one with it, and the percentage joins the status
word ("reading prompt 30%") rather than replacing the context. The row keeps
the bar's height when there is no bar: it sits above the transcript and the
box, and one that came and went would move both under the reader's thumb
every time a turn started.

Checked on the emulator against the sandbox's progress rig: /loading and
/reading both draw a full-width bar with "context unknown" still beside them,
and the settings form has no grey lines left between a label and its box.
ktfmt, compile, lint and the unit tests are clean.
This commit is contained in:
iris-ai committed 2026-09-21 12:13:08 -04:00
1 parent 1aac22bfc9
commit 5626a7d595
2 files changed
+87 -53

No files matched your search

@@ -35,9 +35,10 @@ import androidx.compose.ui.unit.dp
* is the framing rather than the text, and a field whose contents are smaller than the text beside
* it is a field the reader has to lean in to check. See UI_RULES on never shrinking text to fit.
*
* [hint] is what leaving it blank means, and it goes above the box with the label for the same
* reason the label does: inside, it is gone the moment anybody types, which is exactly when a
* reader looks back to check what they are overriding.
* [hint] is what leaving it blank means, drawn inside the empty box. It had a grey line of its own
* above the box until 2026-09-21: a form of a dozen settings was then mostly explanation, and a
* setting should be a title and a box to type in. Inside, it costs no height and is gone the moment
* anybody types -- which is the trade, since that is also when somebody might look back at it.
*/
@Composable
fun LabelledField(
@@ -61,15 +62,7 @@ fun LabelledField(
// control beside it is a switch or a picker. Smaller and greyer on the ones that are
// fields reads as two ranks of setting where there is one.
Text(label, modifier = Modifier.padding(bottom = 2.dp))
hint?.let {
Text(
it,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(bottom = 2.dp),
)
}
FieldBox(value, onValueChange, enabled, lines, keyboardOptions, keyboardActions)
FieldBox(value, onValueChange, enabled, lines, keyboardOptions, keyboardActions, hint)
}
}
@@ -82,6 +75,7 @@ private fun FieldBox(
lines: Int,
keyboardOptions: KeyboardOptions,
keyboardActions: KeyboardActions,
hint: String?,
) {
val interactions = remember { MutableInteractionSource() }
val focused by interactions.collectIsFocusedAsState()
@@ -119,6 +113,15 @@ private fun FieldBox(
.background(MaterialTheme.colorScheme.surfaceContainerHighest, shape)
.border(1.dp, edge, shape)
.padding(horizontal = 10.dp, vertical = 8.dp),
decorationBox = { field -> Box { field() } },
decorationBox = { field ->
Box {
// Under the text rather than beside it: the value is what the box is for, and a
// hint that pushed it sideways would move every character as somebody typed.
if (value.isEmpty() && hint != null) {
Text(hint, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
field()
}
},
)
}