Skip to content

ADR-0028: ComposeCharts for report visuals

  • Status: Accepted
  • Date: 2026-08-22
  • Deciders: maintainers
  • Supersedes: ADR-0013
  • Related: ui.md, issue #51

Context

ADR-0013 hand-rolled the reports donut and trend bars with Compose Canvas. That kept dependencies at zero but left animations, gridlines, axis/value labels and adaptive sizing unimplemented, and every new chart type would re-implement drawing + gesture + tooltip logic by hand.

Decision

Report charts are rendered with io.github.ehsannarmani:compose-charts (Apache-2.0):

  • Category breakdown → PieChart with Pie.Style.Stroke (donut).
  • 6-month trend → ColumnChart with gridlines and a base-currency value scale.

Version is 1.0.0 (amended 2026-08-22). The original pin to 0.2.0 existed because 0.2.5+ releases are compiled with Kotlin 2.3.10, which the then-toolchain (Kotlin 2.2.10 embedded via AGP 9.x built-in Kotlin) could not consume. The toolchain has since lifted KGP to 2.3.10 through AGP's documented "upgrade to a higher KGP version" route (root build.gradle.kts classpath), unpinning the library. Version bumps must still re-check the Kotlin metadata requirement against the toolchain before upgrading; upstream 1.0.0 enables its pie label helper by default, so the donut passes LabelHelperProperties(enabled = false) to keep the legend app-side.

App-side responsibilities stay app-side:

  • Donut center total, selection bubble (ChartTooltip) and legend rows (icons) — 0.2.0's PieChart has no popup or hole text.
  • Trend month labels and per-bar tap bubbles — the library draws canvas labels as pixels (invisible to TalkBack); labels are Compose Texts below the chart, taps land on an overlay row of per-bar cells that also carry the accessibility summaries.
  • All colors derive from MaterialTheme.colorScheme via reportChartPalette() / screen-level colors — nothing hardcoded.
  • Mapping to library models lives in pure functions (ui/reports/charts/ChartAdapters.kt), JVM-unit-tested; money strings are always formatted from Long minor units through MoneyFormatter, never from the library's Double.

Library internals (arc math, animation timing) are not tested.

Consequences

  • Charts animate on entry; trend gains gridlines and a value scale.
  • One extra dependency (+32 KiB APK, R8-minified, no extra keep rules).
  • Version bumps must re-check the Kotlin metadata requirement against the toolchain before upgrading.
  • common/ChartGeometry hit-testing was deleted with its tests; ChartTooltip remains (donut selection).

Alternatives considered

  • Keep hand-rolled Canvas (ADR-0013) — rejected: per-chart reimplementation of interaction/accessibility for every new visual.
  • Vico / MPAndroidChart — rejected: View-interop or heavier theming than a pure-Compose KMP library for two chart types.