ADR-0068: One settings section card
- Status: Accepted
- Date: 2026-10-17
- Amended: 2026-10-20 (Warm ledger — label outside the card, no inner header circle or divider; ADR-0079)
Context
Every other destination renders its content in a Material Card — the app's
MaterialTheme.shapes.medium (12 dp) rounded surface on surfaceContainerLow.
The Settings task screens did not: each section was a bare Column
(SettingsCard in ui/settings/SettingsScreen.kt) — an icon + title row, a
HorizontalDivider and then the rows — with no surface and no shape, so it read
as a sharp-cornered rectangle. And SettingsNavigationRow painted its own
surfaceContainerLow background with no shape, so every navigable settings row —
including the Settings index task list — was a sharp rectangle too (issue #176).
Same purpose, two shapes.
Decision
ui/components/SettingsSectionCard.kt is the app's one settings section surface
(ADR-0065). It is a Material Card that owns the shared card shape and container
colour — MaterialTheme.shapes.medium on surfaceContainerLow, exactly what
CollapsibleSectionCard and every destination Card already use — and hosts an
optional header (icon + title) above a HorizontalDivider, then the section's
rows. The card owns the horizontal content inset, so the rows it hosts stay
transparent: SettingsNavigationRow no longer paints a background of its own and
SettingsRow no longer re-indents itself. Both keep the ADR-0063 contract (one
merged announcement, trailing control on the row's vertical centre). The header
divider stays inside the card, full width. Every settings section routes through
the one component — the task screens' cards (SettingsScreen.kt,
SecuritySection.kt) and the Settings index task list (SettingsIndex.kt).
Consequences
A settings section can no longer drift into a sharp-cornered rectangle: the shape
and container colour are owned once. The header, the divider and the rows share
one card surface, and the index's task rows are rounded like every other
destination's list. Adding a settings section means composing
SettingsSectionCard and putting SettingsRow / SettingsNavigationRow inside
it, not rebuilding a column.
Warm ledger amendment (2026-10-20)
The card keeps the shared 20 dp large shape on AppSurface.grouping with a
16 dp content inset, but it no longer has an inner header circle or a
HorizontalDivider. A section's label is plain page copy outside and above
the card: a 10/16 uppercase eyebrow in the supporting colour (ADR-0063/0079).
The card hosts rows only; a null label omits it entirely, so a one-row group
never repeats its heading.
Related
- ADR-0063 — One settings row with a vertically centred trailing slot
- ADR-0064 — One shared search field
- ADR-0065 — The design language is enforced, not re-decided per screen
Verification
SettingsSectionCardTest samples the section card's rendered pixels: the rounded
top-left corner reveals the backdrop and the body is filled with the shared
container colour, a SettingsNavigationRow over a sentinel backdrop stays
transparent, and every SettingsIndex task row is hosted by the tagged card.
SettingsTaskScaffoldTest asserts the uppercase section label sits outside the
card and that no divider or header circle is rendered inside it.
scripts/ui-guard.sh rule 4 fails when SettingsRow.kt hand-rolls a
.background( or a settings screen defines its own SettingsCard container.