Implement semantics service facade wrapping SemanticsService
epic-screen-reader-support-foundation-task-005 — Create the SemanticsServiceFacade class that wraps Flutter's SemanticsService.announce() and platform MethodChannel calls. Provide a testable interface (abstract class + concrete implementation) so tests can inject a mock. Support announcement queuing, priority levels (polite vs assertive), and locale-aware text. Register as a Riverpod provider.
Acceptance Criteria
Technical Requirements
Implementation Notes
Implement the queue as a List
The platform difference between VoiceOver (iOS) and TalkBack (Android) is largely handled by Flutter's SemanticsService.announce() — you do not need separate MethodChannel calls unless you need custom announcement modes not exposed by Flutter. AnnouncementItem: {String message, AnnouncementPriority priority, Locale? locale}. Keep the Riverpod provider as Provider
Testing Requirements
Write unit tests using flutter_test: (1) polite announcements are queued and processed in order, (2) assertive announcement bypasses queue, (3) clearQueue removes pending items, (4) dispose cancels timers and prevents further announcements, (5) locale is passed correctly to underlying service, (6) queue processes with correct delay between items. Use a mock SemanticsService or capture calls via the abstract interface. Widget tests should verify integration with the Riverpod provider override. Minimum 85% branch coverage on the facade implementation.
Flutter's SemanticsService behaves differently between iOS (VoiceOver) and Android (TalkBack) in edge cases — e.g., announcement queuing, focus-gain timing, and attribute support. If the facade does not correctly abstract these differences, announcements may be silent or misfired on one platform, causing regression on the other platform to go unnoticed until device testing.
Mitigation & Contingency
Mitigation: Write platform-divergence unit tests early using SemanticsServiceFacade mocks. Validate announcement delivery on a physical iPhone (VoiceOver) and Android device (TalkBack) at the end of each sprint. Document known platform differences in the facade's inline API comments.
Contingency: If a platform difference cannot be abstracted cleanly, expose a platform-specific override path in the facade and implement targeted workarounds per platform, accepting the added complexity in exchange for correct behaviour.
Accessibility preferences stored in local storage may need new fields as higher-tier epics are implemented (e.g., announcement verbosity, sensitive-field guard toggle). Schema changes to an already-persisted store risk data migration failures or silent defaults on existing installs, breaking user preferences.
Mitigation & Contingency
Mitigation: Design the AccessibilitySettingsRepository with a versioned JSON schema from the start, using merge-with-defaults on read so new fields fall back gracefully. Define the full expected field list upfront based on all downstream epic requirements before writing the first record.
Contingency: If migration fails on a live install, fall back to full reset-to-defaults with a one-time in-app notification informing the user that accessibility preferences have been reset and inviting them to reconfigure.