Apply design token system to all UI components
epic-bufdir-report-history-ui-task-008 — Ensure all three components (ReportHistoryScreen, ReportHistoryListItem, ReportSummaryMetricsWidget) exclusively use the project design token system for colors, typography, spacing, border radii, and elevation. Remove any hardcoded style values. Validate that the components respond correctly to system-level dynamic type scaling and that the design token theme is applied consistently across light mode rendering.
Acceptance Criteria
Technical Requirements
Execution Context
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.
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.
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.