critical priority low complexity frontend pending frontend specialist Tier 1

Acceptance Criteria

Widget renders three mutually exclusive toggle buttons labelled with the human-readable strings from SummaryPeriodExtension (task-001); active button is visually distinct from inactive using design token colors
Tapping a non-custom option immediately invokes the onPeriodChanged callback with the appropriate SummaryPeriod; no intermediate dialog is shown
Tapping the Custom Date Range option opens a date-range picker (showDateRangePicker or equivalent); on confirmation, onPeriodChanged is invoked with the selected custom SummaryPeriod; on cancellation, the previously active option remains selected
Each toggle button has a Semantics widget with label set to the full period description (e.g. 'Rolling 12-month period, selected') and isToggleButton: true so screen readers announce state correctly
All foreground/background color pairs used in the widget achieve a contrast ratio of at least 4.5:1 (WCAG 2.2 AA) — verified using the contrast checker in the project design token audit
Widget responds to MediaQuery textScaleFactor up to 2.0 without overflow — tested at 1.0, 1.5, and 2.0 scale factors
Widget is stateless externally: it accepts a selectedPeriod parameter to display current selection and an onPeriodChanged callback — no internal state beyond transient date picker handling
Widget is exported from the features barrel and can be embedded in any screen without importing BLoC internals directly

Technical Requirements

frameworks
Flutter
Riverpod
data models
SummaryPeriod
PeriodType
SummaryPeriodExtension
performance requirements
Widget must rebuild only when selectedPeriod changes — use const constructors for static children
Date picker must open within one frame of the tap gesture (no async gap before showing)
security requirements
Custom date range must not allow future end dates beyond today to prevent inflated stats display
Widget must not persist date selections to storage — persistence is the BLoC/Riverpod layer's responsibility
ui components
ToggleButtons or SegmentedButton (Flutter 3.10+)
showDateRangePicker (Material date picker)
Semantics wrapper per button
Design token: colors, typography, spacing, radii from shared theme

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Use Flutter's SegmentedButton (available from Flutter 3.10) for the three-option toggle — it handles mutual exclusivity natively and integrates with Material You theming. If the minimum Flutter version is older than 3.10, use ToggleButtons with a single selected index. Style the active segment using the design token for primaryAccent and inactive using surfaceVariant — never hardcode hex values. For the custom date picker, wrap showDateRangePicker in a try/catch and treat a null return (back button) as cancellation.

Keep the widget in lib/features/annual_summary/presentation/widgets/summary_period_selector.dart. The onPeriodChanged callback pattern is preferred over directly calling a BLoC/Riverpod method from inside the widget — this keeps the widget reusable and testable in isolation. Add a // WCAG 2.2 AA verified comment above each color token usage so reviewers can quickly audit accessibility compliance.

Testing Requirements

Widget tests (flutter_test + WidgetTester). Test groups: (1) Rendering — widget shows three buttons with correct labels at textScaleFactor 1.0, 1.5, and 2.0 without overflow; (2) Interaction — tapping Rolling 12-Month calls onPeriodChanged with correct SummaryPeriod; tapping Custom opens the date picker and cancellation leaves state unchanged; (3) Accessibility — pumpWidget and check that Semantics tree contains toggle button roles and correct selected state strings; (4) Visual regression — golden tests at 1.0 and 2.0 scale for both light and dark themes if the project uses them. All tests use mockCallback to assert onPeriodChanged call count and arguments.

Component
Summary Period Selector
ui low
Epic Risks (3)
high impact medium prob integration

Activity records may contain duplicate entries (as evidenced by the duplicate-detection feature dependency) or proxy-registered activities that should be attributed differently. Including duplicates or mis-attributed records would produce inflated stats, undermining trust in the summary.

Mitigation & Contingency

Mitigation: Implement the aggregation query to join against the deduplication-reviewed-flag on activity records and filter out unresolved duplicates. Coordinate with the duplicate-detection feature team to confirm the authoritative flag field before implementing the RPC. Include a data-quality warning in the summary when unresolved duplicates are detected.

Contingency: If deduplication state is unreliable at release time, add a prominent disclaimer in the summary UI noting that figures reflect all registered activities and may include duplicates pending review. Track a follow-up task to re-aggregate after deduplication runs.

medium impact high prob scope

Each organisation wants to define their own milestone thresholds (e.g., NHF's counting model differs from HLF's certification model). Implementing configurable thresholds may expand scope significantly if the configuration UI is expected in this epic.

Mitigation & Contingency

Mitigation: Scope this epic strictly to the evaluation engine and a hardcoded default threshold set. Define the MilestoneDefinition interface with an organisation_id discriminator so per-org configs can be loaded from the database in a later sprint. Build the admin configuration UI as a separate follow-on task outside this epic.

Contingency: If stakeholders require per-org milestone configuration before launch, deliver a JSON-based configuration file per org as an interim solution, loaded from Supabase storage, until a full admin UI is built.

medium impact medium prob technical

Android 13+ restricts access to media collections and requires READ_MEDIA_IMAGES permission for gallery saves, while older Android versions use WRITE_EXTERNAL_STORAGE. Handling both permission models correctly across the device matrix is error-prone.

Mitigation & Contingency

Mitigation: Use the permission_handler Flutter package with version-aware permission requests abstracted behind the summary-share-service interface. Write platform-specific unit tests for both Android API levels in the test harness. Test on a minimum of three Android versions (API 29, 32, 34) in CI.

Contingency: If gallery save is broken on specific Android versions at launch, disable the 'Save to gallery' option on affected API levels and surface only clipboard and system share sheet, which require no media permissions.