Run accessibility audit on complete wizard flow
epic-quick-activity-registration-wizard-ui-task-015 — Execute a full accessibility audit of the assembled wizard using Flutter's SemanticsChecker and manual TalkBack/VoiceOver walkthroughs. Verify: all touch targets ≥ 48dp, color contrast ≥ 4.5:1 for text, no unlabelled interactive elements, correct focus order, reduce-motion respected, and confirmation state is announced. Fix any WCAG 2.2 AA violations found.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
Common WCAG violations to watch for in Flutter wizard UIs: (a) FilterChip widgets default to a small hit area — wrap in a SizedBox(height: 48, width: 48) minimum or use the Chip's materialTapTargetSize: MaterialTapTargetSize.padded property; (b) icon-only buttons (close, back arrow) often have no semantic label — add Semantics(label: 'Close', button: true) or Tooltip which also sets the semantics label; (c) PageView page transitions use animations — check MediaQueryData.disableAnimations and use AnimationController with duration zero when set; (d) confirmation live region: wrap the success message in Semantics(liveRegion: true) or use a FocusNode requestFocus in the confirmation view's initState post-frame callback. Produce an audit checklist markdown file alongside the code changes documenting pass/fail for each WCAG 2.2 AA success criterion relevant to the wizard.
Testing Requirements
Testing is split into three layers: (1) Automated: add flutter_test semantics assertions (tester.getSemantics, SemanticsChecker) for minimum touch target size via RenderBox size checks, label presence, and live region flags. (2) Semi-automated: run Flutter's SemanticsDebugger in debug build, screenshot every step, verify labels visible. (3) Manual: walk through the full wizard on a physical iOS device with VoiceOver enabled and on an Android device with TalkBack enabled — document each step's focus announcement in the audit report. Contrast checking: extract design token hex values, run through WebAIM Contrast Checker or equivalent CLI tool.
All automated assertions must be committed to the test suite and must pass in CI.
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.
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.
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.
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.