Implement AccessibleSearchInputField widget
epic-contact-search-accessible-ui-task-001 — Build the AccessibleSearchInputField Flutter widget wrapping AppTextField with Flutter Semantics widget. Include semantic label, hint text, and role annotations compliant with WCAG 2.2 AA. Wire up the clear button with its own semantic label and ensure the field is navigable via keyboard and switch access.
Acceptance Criteria
Technical Requirements
Implementation Notes
Wrap the root of the widget with FocusTraversalGroup using ReadingOrderTraversalPolicy to enforce field → clear button focus order. Use Semantics with label and hint parameters directly — avoid MergeSemantics unless you need to collapse child nodes intentionally. For the clear button: use AnimatedOpacity or Visibility(maintainState: false) conditioned on controller.text.isNotEmpty so it disappears from both the visual layer and the semantics tree when not relevant. Do not use textField: true on the Semantics node wrapping AppTextField — AppTextField already provides its own semantics from the underlying TextField; adding textField: true on a parent node would create a duplicate announcement.
Instead, annotate only the outer container with label and hint, and rely on the inner TextField's native semantics for text-field role announcement. Expose a FocusNode parameter so the parent screen can programmatically focus the field (e.g., on screen load).
Testing Requirements
Widget-test AccessibleSearchInputField: (1) renders with AppTextField as a descendant, (2) Semantics node has correct label and hint via tester.getSemantics(), (3) clear button Semantics node has label 'Clear search', (4) clear button is absent from semantics tree when field is empty, (5) onChanged fires when text is entered, (6) onClear fires when clear button is tapped and field is empty afterward, (7) FocusTraversalGroup orders field before clear button. Use flutter_test SemanticsHandle for semantic assertions. No golden tests required for this task.
Flutter's Semantics live region support for announcing dynamic result count changes may behave inconsistently between VoiceOver (iOS) and TalkBack (Android), particularly regarding announcement throttling and focus management, causing the feature to pass testing on one platform and fail on the other.
Mitigation & Contingency
Mitigation: Test live region announcements on both iOS (VoiceOver) and Android (TalkBack) early in development using the existing accessibility test harness. Reference the existing LiveRegionAnnouncer component (608-live-region-announcer) patterns used elsewhere in the app.
Contingency: If cross-platform consistency cannot be achieved, implement a platform-specific announcement strategy using the SemanticsService.announce API with platform-conditional announcement timing to work around OS-specific throttling behaviour.
Voice-to-text progressive enhancement for Blindeforbundet may not be available or may behave unpredictably on all device/OS combinations, particularly older Android devices, potentially causing crashes or silent failures that degrade the search experience.
Mitigation & Contingency
Mitigation: Implement voice-to-text as a strictly optional enhancement: detect availability at runtime, show the microphone button only when the platform speech API reports availability, and wrap all voice invocations in try/catch with graceful degradation to standard text input.
Contingency: If voice-to-text causes instability on a subset of devices discovered during TestFlight/beta, disable the feature flag for that platform version while a fix is investigated, without impacting the core text-based search functionality.