high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

Widget renders a success illustration (SVG or Lottie asset) at minimum 120x120 logical pixels, centered above the summary content
Widget displays activity type name, formatted date (locale-aware, e.g., 'Monday 14 April'), and duration in human-readable form (e.g., '30 minutes')
An auto-dismiss countdown timer is visible (e.g., circular progress or text '3…2…1') and navigates away automatically when it reaches zero
User can tap a 'Done' button to dismiss immediately without waiting for the timer
On widget mount, a Semantics live region (SemanticsProperties.liveRegion = true) announces 'Activity registered successfully' to screen readers
All text elements have Semantics labels and pass WCAG AA contrast ratio (minimum 4.5:1 for normal text, 3:1 for large text) against the background
Widget entrance uses a fade + slide-up animation completing within 300ms using Flutter's AnimationController
Widget is stateless except for the auto-dismiss timer, which is managed in a StatefulWidget or Riverpod AsyncNotifier with proper disposal on unmount
Widget accepts activityType (String), date (DateTime), and durationMinutes (int) as required constructor parameters
Golden test or widget test verifies correct rendering with known inputs

Technical Requirements

frameworks
Flutter
Riverpod
flutter_test
data models
activity
activity_type
performance requirements
Entrance animation runs at 60fps on mid-range Android device
Widget build time under 16ms (no heavy synchronous work in build())
security requirements
No personal contact data displayed on this screen — only activity metadata
Auto-dismiss must not navigate to a screen that exposes sensitive data without user intent
ui components
SuccessIllustration (asset image or Lottie)
ActivitySummaryCard (type, date, duration)
AutoDismissTimer (countdown indicator)
AppButton (primary, 'Done')

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use a StatefulWidget with a single AnimationController for the entrance animation and a Timer for auto-dismiss. Dispose both in dispose(). Pass a countdown duration as a constructor parameter (default 4 seconds) so it can be shortened in tests. For the live region, wrap the success message in a Semantics widget with liveRegion: true — Flutter will announce it on first render.

Use design tokens for all spacing, colors, and typography — do not hardcode values. The success illustration should be an asset bundled with the app; use a placeholder colored container if the asset is not yet available so the widget is testable independently. Format the date using the intl package's DateFormat, respecting the device locale.

Testing Requirements

Widget tests using flutter_test. Test 1: widget renders with valid inputs and displays all three summary fields. Test 2: auto-dismiss timer fires after the configured duration and triggers the onDismiss callback. Test 3: tapping 'Done' calls onDismiss immediately.

Test 4: Semantics tree contains a live region node with the correct announcement string. Test 5: animation controller is disposed when widget is removed from tree (use tester.pumpWidget(Container()) after initial render and assert no leak via debugPrint checks). Optionally add a golden test for pixel-level regression.

Epic Risks (4)
high impact medium prob scope

As wizard steps accumulate additional features (duplicate warning, retroactive date chips, custom duration entry), the two-tap happy path may inadvertently require extra interactions. A step that previously auto-advanced may start requiring a confirmation tap, breaking the core promise of the feature and increasing friction for high-frequency users like HLF's 380-registration peer mentor.

Mitigation & Contingency

Mitigation: Define and automate a regression test that performs the complete two-tap happy path (open bottom sheet → confirm → confirm) and asserts the confirmation view is reached in exactly two tap events. Run this test in CI on every PR touching the wizard. Treat any failure as a blocking defect.

Contingency: If a new feature unavoidably adds a tap to the happy path, provide a 'quick mode' toggle in user settings that collapses the wizard to a single-confirmation screen for users who never change defaults.

medium impact medium prob technical

Flutter bottom sheets are dismissed on back-button press or background tap by default. If the wizard state is not preserved, a peer mentor who accidentally dismisses mid-flow loses all their entered data and must start over — a significant frustration for users with cognitive disabilities or motor impairments who take longer to fill each step.

Mitigation & Contingency

Mitigation: Implement the wizard state as a persistent Cubit that outlives the bottom sheet widget's lifecycle, scoped to the registration feature route. On re-open, the Cubit restores the previous step and field values. Add a 'discard changes?' confirmation dialog when the user explicitly dismisses a partially filled wizard.

Contingency: If persistent state proves difficult to implement with the chosen routing strategy, implement draft auto-save to a local draft repository every time a field value changes, and restore from draft on the next open.

high impact high prob technical

Multi-step wizard bottom sheets are among the most complex accessibility scenarios in Flutter. Screen readers (TalkBack, VoiceOver) may not announce step transitions, focus may land on the wrong element after advancing, and animated transitions can interfere with the accessibility tree update cycle — making the feature unusable for Blindeforbundet users who rely on screen readers.

Mitigation & Contingency

Mitigation: Assign each wizard step a unique Semantics container with a live region announcement on mount. Use ExcludeSemantics on inactive steps during transition animations. Test each step transition manually with TalkBack and VoiceOver as part of the definition of done for each step component.

Contingency: If animated transitions cause accessibility tree corruption, disable step transition animations entirely in accessibility mode (detected via MediaQuery.accessibleNavigation) and use instant step replacement instead.

medium impact medium prob dependency

The NotesStep relies on the OS keyboard's built-in dictation button for speech-to-text input. This button's availability, position, and behaviour varies significantly between iOS (reliable, visible dictation key) and Android (varies by keyboard, OEM skin, and language settings). HLF and Blindeforbundet specifically requested this capability; if it is unreliable on Android, it fails a SHOULD HAVE requirement for a significant portion of users.

Mitigation & Contingency

Mitigation: Document that the notes dictation feature depends on the device's native keyboard dictation and requires no in-app microphone permission. Add explicit placeholder copy informing users they can use their keyboard's dictation button. Test on a minimum of three Android OEM keyboards (Gboard, Samsung, Swiftkey) and two iOS versions.

Contingency: If native keyboard dictation is too unreliable on Android, implement a fallback in-app microphone button in the NotesStep that triggers the platform's SpeechRecognition API directly via a method channel, scoped only to the notes field with no session recording capability.