high priority medium complexity frontend pending frontend specialist Tier 5

Acceptance Criteria

Progress bar animates smoothly from 0 to 100% as ExportTriggerBloc emits progress updates
Status label updates in real time to reflect current phase: 'Fetching records…', 'Generating file…', 'Uploading…', 'Upload complete'
Progress bar and label are only visible when BLoC state is Exporting — hidden in Idle, AwaitingConfirmation, and Error states
On export completion (100%), the progress bar is replaced by a success banner containing the export filename and a 'Download' button
The 'Download' button triggers the share sheet / file-save dialog with the completed file URL from BLoC state
On export error, the progress section is replaced by a plain-language error message (no stack trace) and a 'Retry' button that re-dispatches ExportInitiated
Every status label change is announced via Flutter Semantics with liveRegion: true so TalkBack/VoiceOver reads it aloud
Success and error states include appropriate Semantics labels for screen readers
Progress percentage is announced as a live region update at minimum every 25% increment
Widget correctly handles a progress value of exactly 0 and exactly 1.0 without visual glitches
Widget test verifies all five state transitions: Idle → Exporting(25%) → Exporting(75%) → Success → Error with Retry

Technical Requirements

frameworks
Flutter
BLoC
apis
Supabase Storage (signed URL for Download button)
data models
bufdir_export_audit_log
performance requirements
AnimatedFraction or TweenAnimationBuilder must animate progress bar at 60 fps with no jank
Status label changes must not cause layout shifts — reserve fixed height for the status row
security requirements
Signed file URL from Supabase Storage must be fetched fresh at download time, not cached from export completion state
Error messages shown to the user must not expose internal Supabase error codes or server details
ui components
BufdirExportProgressIndicator (custom widget)
LinearProgressIndicator (Flutter built-in, animated)
BufdirExportSuccessBanner
BufdirExportErrorMessage
Semantics widget with liveRegion: true
BlocBuilder<ExportTriggerBloc, ExportTriggerState>

Execution Context

Execution Tier
Tier 5

Tier 5 - 253 tasks

Can start after Tier 4 completes

Implementation Notes

Model ExportTriggerBloc progress as a double (0.0–1.0) and map to labelled phases in the UI layer, not in the BLoC. Use TweenAnimationBuilder wrapping LinearProgressIndicator for smooth animation between progress values. Wrap each status label in Semantics(liveRegion: true, label: statusText) — Flutter's Semantics system will announce changes to TalkBack/VoiceOver automatically. For the success banner, use a Material SnackBar alternative embedded in the page body (not a floating SnackBar) to keep it in the focus order.

For error messages, prefer generic user-facing text like 'Export failed. Please check your connection and try again.' — log the technical error only to debugPrint or a crash reporter. Ensure the Retry button is at least 44×44 dp to meet WCAG touch target requirements.

Testing Requirements

Write widget tests with flutter_test covering: (1) progress bar renders and animates through mocked progress states, (2) status label text matches each BLoC state phase, (3) success banner appears with correct filename and Download button on completion, (4) error message and Retry button appear on error state, (5) Retry button re-dispatches ExportInitiated, (6) Semantics tree contains liveRegion nodes for status updates. Use MockExportTriggerBloc. Run flutter analyze and ensure no accessibility warnings. Test on both small (360dp) and large (412dp) screen widths.

Component
Bufdir Export Trigger Screen
ui medium
Epic Risks (2)
medium impact medium prob technical

For large exports that run for 10–30 seconds, a static loading spinner will feel broken to users on slow mobile connections. If the UI cannot display meaningful progress during the export pipeline, coordinators may abandon the flow or trigger duplicate exports by pressing the button multiple times.

Mitigation & Contingency

Mitigation: Implement streaming progress events from the orchestrator BLoC through named pipeline stages (querying, mapping, generating, uploading). Display each stage label with a progress indicator on the trigger screen. Disable the generate button immediately on first tap to prevent duplicates.

Contingency: If streaming pipeline progress is not feasible in the first release, implement a deterministic stage-based progress animation (10% querying, 50% generating, 90% uploading) that gives users feedback without requiring real server events.

high impact medium prob technical

Custom date range pickers are among the most common accessibility failures in mobile apps. Blindeforbundet users rely on VoiceOver, and NHF users include people with cognitive impairments. A non-accessible period picker could make the entire export workflow unusable for a significant portion of the intended user base.

Mitigation & Contingency

Mitigation: Build the period picker using Flutter's native date picker semantics as the foundation, with preset shortcuts as primary navigation (reducing the need to interact with the custom range picker at all). Test with VoiceOver on iOS and TalkBack on Android before UI epic sign-off. Engage Blindeforbundet's test contact for accessibility validation.

Contingency: If the custom date range picker cannot be made fully accessible before release, ship only the preset period shortcuts (covering the majority of use cases) and add the custom range picker in a follow-up sprint after dedicated accessibility remediation.