critical priority medium complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

SemanticsWrapperWidget accepts a `labelBuilder` parameter of type `String Function(BuildContext)` in addition to the static `label` string
When both `label` and `labelBuilder` are provided, `labelBuilder` takes precedence
When `labelBuilder` is provided, the resolved label updates correctly when the widget rebuilds with new context data
Widget accepts a `liveRegion` bool parameter; when true, sets Semantics.liveRegion: true so screen readers announce content changes
Widget reads from AccessibilitySettingsRepository via Riverpod to determine if simplified labels preference is enabled and adjusts output accordingly
Widget reads screen reader active state from ScreenReaderDetectionService and skips semantics computation entirely when no screen reader is active (performance optimization)
All existing static label and state functionality from task-009 is preserved without regression
The widget remains a ConsumerWidget (or equivalent Riverpod widget) and does not introduce unnecessary rebuilds when unrelated settings change
The live region flag is correctly passed through to the Semantics widget's liveRegion property
Dartdoc comments are updated to reflect new parameters

Technical Requirements

frameworks
Flutter
Riverpod
apis
Semantics.liveRegion
AccessibilitySettingsRepository provider
ScreenReaderDetectionService provider
ConsumerWidget
data models
AccessibilitySettings
ScreenReaderState
performance requirements
When screen reader is inactive, semantic computation is skipped via short-circuit in build()
labelBuilder is only called during build(); no caching needed but must not cause side effects
security requirements
labelBuilder callbacks must not access sensitive fields directly; route through SensitiveFieldConfigurationRegistry if field is flagged
ui components
SemanticsWrapperWidget (updated)
LiveRegionWrapper (optional internal helper)

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Convert SemanticsWrapperWidget from StatelessWidget to ConsumerWidget. Watch two providers: screenReaderActiveProvider (bool) and accessibilitySettingsProvider (AccessibilitySettings). Use select on accessibilitySettingsProvider to watch only the fields this widget cares about, preventing full rebuilds on unrelated settings changes. For label resolution: use a private _resolveLabel(BuildContext context) method that checks labelBuilder first, then falls back to label.

For the live region, pass it directly as Semantics(liveRegion: liveRegion ?? false, ...). Guard the entire Semantics wrapping behind a screenReaderActive check — when false, return child directly. This is important for Blindeforbundet users where VoiceOver is expected to be active, and for general performance.

Testing Requirements

Extend the existing widget test suite with additional test cases: (1) labelBuilder overrides static label, (2) labelBuilder receives correct BuildContext and produces the expected string, (3) liveRegion: true sets Semantics.liveRegion correctly in the semantics tree, (4) when screen reader is inactive (mocked ScreenReaderDetectionService returns false), the Semantics widget is not added to the tree (verify via SemanticsController finding no semantics node), (5) AccessibilitySettingsRepository simplified-labels preference modifies the resolved label. Use ProviderScope overrides in tests to inject mock providers. All new tests should be appended to the existing test file from task-011.

Component
Semantics Wrapper Widget
ui medium
Epic Risks (2)
high impact medium prob technical

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.

medium impact medium prob scope

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.