Add upload progress overlay to thumbnail widget
epic-receipt-capture-and-attachment-ui-accessibility-task-002 — Overlay a circular progress indicator on the thumbnail while the receipt image is uploading. Accept an upload progress stream (0.0–1.0) as input. Show a checkmark or tick icon on completion, and a retry icon on failure. Transition animations must respect reduced-motion settings.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Extend ReceiptThumbnailPreview from task-001 by adding the uploadProgress parameter — do not create a new widget class. Wrap the image container in a Stack and conditionally add an overlay child driven by a StreamBuilder
The overlay background should use Colors.black.withOpacity(0.55) — verify this meets 3:1 contrast ratio against the progress indicator color using design tokens.
Testing Requirements
Use flutter_test with a StreamController
Flutter's accessibility live region support (SemanticsProperties.liveRegion) has known inconsistencies between iOS VoiceOver and Android TalkBack, and between Flutter versions. Threshold-crossing announcements may fail to fire or double-fire, breaking the accessibility contract for Blindeforbundet users.
Mitigation & Contingency
Mitigation: Test live region announcements on physical devices with VoiceOver and TalkBack enabled from the first iteration. Use the AccessibilityLiveRegionAnnouncer component pattern already established in the project. Verify announcement timing relative to Bloc state emissions to avoid double-fires.
Contingency: If Flutter live regions prove unreliable, implement a platform-channel fallback that calls UIAccessibility.post(notification:) on iOS and AccessibilityManager.sendAccessibilityEvent() on Android directly, bypassing Flutter's abstraction.
The org-configurable threshold must be available at form-render time. If the threshold configuration is fetched asynchronously and not cached, the indicator may briefly show the wrong state (e.g., 'optional' before the threshold loads), confusing users and potentially allowing invalid submissions.
Mitigation & Contingency
Mitigation: Ensure the receipt threshold validator loads and caches the org configuration at app startup or organization selection time, not lazily on form open. Use a loading state in the indicator widget rather than defaulting to 'optional' while configuration is pending.
Contingency: If startup caching is not feasible, treat an unknown threshold as 'receipt required' (fail safe) and surface a clear loading indicator until the configuration resolves, preventing invalid submissions while the config loads.