medium priority low complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

Zero hardcoded color values (hex literals, Color(0x...), named colors) remain in ReportHistoryScreen, ReportHistoryListItem, or ReportSummaryMetricsWidget
Zero hardcoded font size values remain — all typography uses design token TextStyle references
Zero hardcoded spacing values (padding, margin, gap) remain — all spacing uses design token constants
Zero hardcoded border radius values remain — all radii use design token constants
Zero hardcoded elevation values remain — all elevation uses design token constants
All components render correctly in light mode with the design token theme applied via ThemeData
When the device's system font scale is increased (e.g., to 1.5x), all text in the components scales proportionally without overflow or clipping
When the device's system font scale is increased to 2.0x, components reflow gracefully (no pixel overflow, no text truncation where avoidable)
A static code analysis pass (grep for hardcoded values) returns zero matches in the three component files
The components look visually consistent with other screens in the app that already use the design token system

Technical Requirements

frameworks
Flutter
performance requirements
Token lookup must not cause extra widget tree rebuilds — tokens should be accessed via Theme.of(context) or a static constant map, not computed per-frame
ui components
ReportHistoryScreen
ReportHistoryListItem
ReportSummaryMetricsWidget
ThemeData (Flutter design token integration)
TextTheme (typography tokens)
ColorScheme (color tokens)

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Access design tokens via Theme.of(context).colorScheme, Theme.of(context).textTheme, and the project's custom token extension (likely an AppTokens or AppTheme class — check the existing token setup in the codebase). Do not store BuildContext to access tokens outside of build() — pass token values down as constructor arguments if needed outside the widget tree. For spacing tokens, use the project's established spacing constants (e.g., AppSpacing.sm, AppSpacing.md) consistently. Validate font scaling by running the app in Flutter's accessibility inspector with largest font size enabled.

Note: the task scope is light mode only; do not introduce dark mode concerns in this task.

Testing Requirements

Widget tests (flutter_test): render each component inside a pumped ThemeData that uses the design token system; assert that text styles match token-defined styles using find.byType(Text) and verifying textStyle properties. Write a test that pumps the widget with textScaleFactor: 1.5 and textScaleFactor: 2.0 and asserts no RenderFlex overflow errors. Static analysis: run a grep or linter rule against the three files to assert no hardcoded Color, double fontSize, or EdgeInsets with literal pixel values that bypass the token system.

Epic Risks (2)
high impact medium prob integration

The ReportSummaryMetricsWidget must display metrics as they were at time of submission, not recalculated from current data. If the metrics are not stored as a JSON snapshot in the history record at export time, the widget will either show wrong data or require a full re-aggregation on every list load.

Mitigation & Contingency

Mitigation: Ensure the Bufdir export pipeline (bufdir-report-export feature) writes a summary_metrics JSONB column in the history record at export time, containing total_activities, total_hours, and participants_reached. The UI widget reads only from this snapshot field — never from live aggregation queries.

Contingency: If snapshot data is missing for historical records (e.g., older exports before the column existed), display a 'Metrics not available for this report' placeholder in the widget rather than showing zeros or triggering a live aggregation that could return different figures.

medium impact medium prob scope

Re-export can take several seconds (it runs the full generation pipeline). Without adequate progress feedback, coordinators may tap the button multiple times, triggering duplicate exports and duplicate history records.

Mitigation & Contingency

Mitigation: Disable the re-export button immediately on first tap and show an inline progress indicator on the list item. Guard against duplicate invocations at the service layer using an in-progress flag keyed by report ID. Display a loading state on the list item throughout the operation.

Contingency: If duplicate re-export records are created (e.g., due to a race condition), the history table will show multiple entries for the same original report — which is harmless but confusing. Add a deduplication UI hint ('Re-exported N times') and a backend guard that prevents more than one in-flight re-export for the same source record ID simultaneously.