Implement prominent logout button
epic-no-access-screen-ui-task-005 — Add a prominent logout button to the no-access-screen-widget. The button must meet the 44×44 dp minimum touch target, use the primary action button style from the design token system, and trigger the authentication sign-out flow. Include a semantic label and role for screen-reader users.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Use the project's existing authentication BLoC or Riverpod notifier to trigger sign-out rather than calling Supabase directly from the widget — this keeps the widget decoupled from the auth provider. The sign-out action should dispatch an event (e.g. AuthEvent.signOutRequested) and the widget should listen for the resulting state change to trigger navigation. Use the app's reusable AppButton widget to maintain consistent visual style.
Set the navigation action to use context.go('/') or equivalent router reset so the back stack is cleared. Ensure the ARB key is something like commonLogout or noAccessScreenLogoutButton.
Testing Requirements
Write widget and unit tests using flutter_test. Test 1: mock the auth sign-out method and assert it is called when the button is tapped. Test 2: assert the loading indicator appears while sign-out is in progress. Test 3: assert the button is disabled during loading (cannot be tapped twice).
Test 4: mock a sign-out failure and assert an error message is displayed. Test 5: assert navigation to the auth screen occurs after successful sign-out by verifying the router receives the correct navigation event. Test 6: verify the Semantics node has the correct label and button role.
Flutter's live region (SemanticsProperties.liveRegion) announcement may be delayed or swallowed by the OS accessibility engine if the Semantics tree is not fully built when the screen mounts, causing screen-reader users to miss the denial announcement.
Mitigation & Contingency
Mitigation: Trigger the live region announcement from a post-frame callback (WidgetsBinding.addPostFrameCallback) to ensure the Semantics tree is committed before the announcement fires. Test on both VoiceOver (iOS) and TalkBack (Android) physical devices.
Contingency: If live region timing is unreliable, fall back to using SemanticsService.announce() directly in the initState post-frame callback, which provides more deterministic announcement timing.
The organisation logo may fail to load (network error, missing asset) leaving a broken image in an otherwise functional screen, degrading the professional appearance and potentially confusing users.
Mitigation & Contingency
Mitigation: Wrap the logo widget in an error builder that renders a styled fallback (organisation name text or a generic icon) when the logo asset or network image fails to load.
Contingency: If logo loading is persistently unreliable across organisations, remove the logo from the no-access screen entirely in favour of a text-only header using the organisation's display name from the design token system.