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 →
PieChartwithPie.Style.Stroke(donut). - 6-month trend →
ColumnChartwith 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'sPieCharthas 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.colorSchemeviareportChartPalette()/ 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 fromLongminor units throughMoneyFormatter, never from the library'sDouble.
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/ChartGeometryhit-testing was deleted with its tests;ChartTooltipremains (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.