high priority low complexity frontend pending frontend specialist Tier 0

Acceptance Criteria

KeyboardAwareLayout is a reusable StatelessWidget that accepts a required Widget child parameter
The child is wrapped in a SingleChildScrollView with reverse: true so the bottom of the content stays visible when keyboard rises
Bottom padding equal to MediaQuery.of(context).viewInsets.bottom is applied via a Padding widget below the child, so content shifts up when keyboard appears
The SingleChildScrollView uses physics: ClampingScrollPhysics() to prevent overscroll bounce that can disorient users with vestibular disorders
KeyboardAwareLayout does not contain any login-specific logic — it is a generic layout utility reusable across the app
When keyboard is dismissed, the bottom padding returns to zero and the layout collapses back without animation jank
The widget does not introduce additional Scaffold or Material ancestors — it is purely a layout wrapper
The component is placed in the shared/reusable widgets layer (not inside the login feature folder), reflecting its generic utility nature

Technical Requirements

frameworks
Flutter
performance requirements
Widget rebuilds only when MediaQuery.viewInsets changes — use MediaQuery.viewInsetsOf(context) (Flutter 3.10+) for targeted dependency instead of full MediaQuery.of(context)
ui components
SingleChildScrollView (reverse: true)
Padding (bottom: viewInsets.bottom)

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Implementation is intentionally simple — resist adding complexity. StatelessWidget with a build method that reads MediaQuery.viewInsetsOf(context).bottom and returns a SingleChildScrollView(reverse: true, child: Padding(padding: EdgeInsets.only(bottom: keyboardHeight), child: child)). The reverse: true property on SingleChildScrollView means the scroll anchor is at the bottom, so when content grows (keyboard appears), the visible area stays at the bottom automatically — this is the key trick. Do not use packages like keyboard_avoider unless the built-in approach proves insufficient.

Place in lib/core/widgets/keyboard_aware_layout.dart. The component serves universal design goals: users with motor impairments who rely on switch access or external keyboards are particularly dependent on fields remaining visible.

Testing Requirements

Write widget tests using flutter_test. Test: (1) when viewInsets.bottom is 0, no bottom padding is added, (2) when viewInsets.bottom is 300 (simulated keyboard), bottom padding of 300 is applied, (3) child widget is rendered inside a SingleChildScrollView, (4) physics is ClampingScrollPhysics. Use MediaQuery override in tests to simulate keyboard presence: wrap the widget under test with a MediaQuery that has viewInsets: EdgeInsets.only(bottom: 300).

Component
Login Screen
ui low
Epic Risks (3)
high impact medium prob scope

Automated accessibility checks (e.g., flutter_accessibility_service) may pass while manual VoiceOver/TalkBack testing reveals focus-order issues, missing semantic roles, or live region announcements that fire too early or not at all. Discovering these late risks delaying the MVP release.

Mitigation & Contingency

Mitigation: Conduct manual VoiceOver and TalkBack testing on physical devices at the end of every sprint, not only at release. Define accessibility acceptance criteria per component and include them in the DoD. Use Semantics widgets explicitly rather than relying on implicit semantics from Flutter's default widgets for all interactive elements.

Contingency: Maintain a prioritized accessibility bug backlog separate from the main backlog. If critical VoiceOver issues are found close to release, create an explicit accessibility hotfix sprint before TestFlight distribution to Blindeforbundet testers.

medium impact medium prob technical

Keyboard height varies significantly between iOS and Android, between device sizes (iPhone SE vs iPad), and with third-party keyboards. The KeyboardAwareLayout may not correctly adjust scroll offset in all combinations, causing input fields to remain hidden behind the keyboard on certain device/keyboard configurations.

Mitigation & Contingency

Mitigation: Test on a matrix of devices including iPhone SE (small viewport), a mid-size Android phone, and a tablet. Implement the layout using MediaQuery.viewInsets.bottom rather than a fixed padding value to correctly respond to any keyboard height. Include edge cases for floating keyboards on iPads.

Contingency: If device-specific issues are found after release, implement a bottom-padding fallback using BottomPadding inset and allow users to manually scroll. Log affected device/OS combinations for targeted fixes.

high impact low prob dependency

If the design token system's colour palette is updated without re-running contrast validation, form field labels, error messages, or placeholder text could fall below the WCAG 2.2 AA 4.5:1 ratio, causing a compliance regression.

Mitigation & Contingency

Mitigation: Integrate a contrast ratio validator (e.g., a CI lint step using the contrast-ratio-validator component) that checks all colour pairs used in the login form on every pull request. Document which token pairs are used for labels, errors, and backgrounds in the login form.

Contingency: If a contrast regression is detected post-merge, hot-patch the affected design token value. Do not ship a TestFlight build with known WCAG AA failures to Blindeforbundet testers.