Skip to content

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.

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.