high priority medium complexity frontend pending frontend specialist Tier 3

Acceptance Criteria

Screen renders a single scrollable column with: page header, BufdirPeriodSelectorWidget, BufdirExportFormatSelector, primary 'Export' button, and an area reserved for progress feedback — in that visual order
The 'Export' button is disabled (greyed out with design token disabled color) until both a period and a format have been selected (state is ExportTriggerPeriodSelected or later with format set)
Tapping 'Export' opens BufdirExportConfirmationDialog; on Confirm, the Bloc receives ExportStartedEvent
While in ExportTriggerExporting state: the Export button is replaced by a LinearProgressIndicator (or CircularProgressIndicator) showing Bloc progress value 0–100; period selector and format selector are disabled/non-interactive
On ExportTriggerComplete: a success banner/snackbar is shown with a 'Download' link to the signed file URL; the screen resets to idle after 3 seconds or on user dismissal
On ExportTriggerError: an inline error card is shown below the Export button with the sanitized error message and a 'Try again' button that resets to the last valid selection state
All interactive elements are disabled during exporting state to prevent double-submission
Screen uses page header from the shared AppPageHeader widget with title 'Export to Bufdir'
No inline styles — all colors, spacing, and typography sourced from design token system
Widget integration test covers idle → confirm → exporting → complete happy path and verifies UI state at each transition

Technical Requirements

frameworks
Flutter
BLoC
Riverpod
data models
ExportTriggerState (all subtypes)
BufdirExportSummary (assembled from Bloc state for dialog)
performance requirements
Progress indicator animates smoothly at 60 fps — use AnimatedSwitcher or TweenAnimationBuilder for progress value changes
Screen rebuild on state change must only rebuild the state-dependent subtree via BlocBuilder selectors, not the entire scaffold
security requirements
Signed file URL from ExportTriggerComplete state must only be displayed in-app and never written to device logs or clipboard automatically
All interactive elements are locked during export to prevent concurrent export requests
ui components
BufdirExportTriggerScreen (main scaffold)
AppPageHeader (shared widget, title: 'Export to Bufdir')
BufdirPeriodSelectorWidget (task-001/002)
BufdirExportFormatSelector (task-003)
BufdirExportConfirmationDialog (task-004)
AnimatedProgressArea (switches between button and progress indicator)
ExportSuccessBanner
ExportErrorCard

Execution Context

Execution Tier
Tier 3

Tier 3 - 413 tasks

Can start after Tier 2 completes

Implementation Notes

Use BlocBuilder with a buildWhen selector to minimize rebuilds — only rebuild the action area (button/progress) on state class changes, not on progress int increments for the progress bar (use a separate BlocBuilder with a selector for progress only). The AnimatedProgressArea should use AnimatedSwitcher with a FadeTransition child between the Export button and the progress indicator to avoid jarring layout shifts. Assemble BufdirExportSummary for the dialog directly from Bloc state fields (period, format) plus an estimated count from the Bloc (if available, else show a loading placeholder). Use the app's existing AppButton widget for the primary action — pass isLoading: false and isDisabled based on state.

On ExportTriggerComplete, use ScaffoldMessenger.of(context).showSnackBar with a custom SnackBar containing an InkWell 'Download' link — avoid BottomSheet which interrupts the screen flow. Reset to idle by dispatching a ResetExportEvent after the snackbar duration. Follow the single-action screen layout: BufdirPeriodSelectorWidget and BufdirExportFormatSelector are the two inputs; the Export button is the single action — keep the layout clean with AppSpacing.lg vertical gaps between sections.

Testing Requirements

Write flutter_test integration tests using a fake ExportTriggerCubit: (1) idle state — Export button disabled, no progress indicator visible, (2) period + format selected — Export button enabled, (3) tapping Export opens confirmation dialog, (4) confirming dialog triggers exporting state — progress indicator visible, selectors non-interactive, (5) exporting state with progress 50 — LinearProgressIndicator value is 0.5, (6) ExportTriggerComplete — success banner visible, download link present, (7) ExportTriggerError — error card visible, 'Try again' button present. Also write a golden test at 375 dp width for idle and exporting states to catch unintended layout regressions. All tests use fake Cubit — no real API calls.

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.