Implement Re-download from Export History
epic-bufdir-reporting-export-ui-task-011 — Add re-download capability to the export history list: tapping the Re-download button on a history item retrieves the signed file URL from Supabase Storage and triggers the platform share sheet or file-save dialog. Handle expired URLs gracefully by re-generating a fresh signed URL via the repository. Show a progress indicator during URL resolution and surface errors with retry.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 2 - 518 tasks
Can start after Tier 1 completes
Implementation Notes
Implement RedownloadService as a separate injectable class to keep the list item widget thin. In the service: (1) attempt HEAD request on stored fileUrl to check validity, or catch the Supabase StorageException on download attempt, (2) on 403/expired error, call supabaseClient.storage.from(bucketName).createSignedUrl(filePath, 3600). Parse the filePath from the stored fileUrl — Supabase Storage signed URLs contain the bucket path as a query parameter or path segment. Use share_plus's SharePlus.share(url, subject: subject) — do NOT use SharePlus.shareFiles as it requires downloading to disk first.
Manage the per-item loading state in a local ValueNotifier
Testing Requirements
Write unit and widget tests covering: (1) successful URL resolution invokes share_plus with correct URL and subject, (2) HTTP 403 on stored URL triggers createSignedUrl and retries with fresh URL, (3) createSignedUrl failure shows error snackbar with Retry, (4) button is disabled during active resolution, (5) progress indicator appears and disappears correctly. Mock Supabase Storage client and share_plus plugin. Write an integration test on a device/emulator verifying the share sheet appears (can be dismissed). Test both iOS and Android paths if CI supports both simulators.
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.
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.