App Safe-Area / Window-Insets

mandatory

Consumo obrigatório de window-insets (status bar, nav bar, display cutout, IME) em todos os apps Koder. Implementação canônica: KoderSafeScaffold / KoderApp(safeArea: true) em engines/sdk/koder_kit v0.3.0+, Modifier.safeDrawingPadding() no Android nativo Compose, env(safe-area- inset-*) no web.

Spec — App safearea / windowinsets handling

Applicability

All Koder *pps*(mobile, desktop, TV, web PWA) — any surface where system chrome (status bar, navigation bar, display cutout, on-screen keyboard, title bar, task bar) can occlude rendered content.

Not applicable to CLIs, landing pages (static HTML with normal document flow), or pure server components.

Required behaviour

  1. *lways consume OS-reported insets.*The OS knows the exact pixel

    dimensions of system chrome on the current device and updates them live (orientation change, gesture nav vs 3-button, keyboard open/close, foldable unfold, PiP resize). Apps must consume these values — never hard-code pixel margins.

  2. *o content occluded by system chrome at rest.*Every interactive

    element — buttons, text fields, list items, sliders — must be fully tappable without fighting the nav bar, status bar, or cutout.

  3. *ext under the status bar is forbidden*unless the design is

    deliberately edgetoedge (splash screen, full-screen video, camera viewfinder) and the content is non-critical.

  4. *ME (on-screen keyboard) handling.*Forms must resize or scroll so the

    focused field stays visible above the keyboard. Default to resizeToAvoidBottomInset: true (Flutter) / WindowInsets.ime (native Android) / keyboardShouldPersistTaps='handled' (Web).

  5. *dgetoedge on Android 15+ is the platform default.*Apps targeting

    API ≥ 35 must handle insets explicitly; the OS no longer adds automatic padding.

Platform primitives

Platform API Notes
Android native (API 30+) WindowInsets.getInsets(WindowInsets.Type.systemBars()) Returns Insets(left, top, right, bottom) in px
Android native (compat) ViewCompat.getRootWindowInsets(view) + WindowInsetsCompat API 21+
Jetpack Compose WindowInsets.systemBars, .navigationBars, .statusBars, .safeDrawing, .ime Stateful; recomposes on change
Jetpack Compose Modifier.safeDrawingPadding(), .systemBarsPadding(), .imePadding() Apply padding automatically
Jetpack Compose Scaffold(contentWindowInsets = WindowInsets.safeDrawing) Handles all edges + IME at the Scaffold level
Jetpack Compose (Activity) enableEdgeToEdge() before setContent Required for targetSdk ≥ 35
Flutter MediaQuery.of(context).viewPadding EdgeInsets in logical pixels
Flutter SafeArea(child: …) widget Consumes padding; minimum: sets a floor
Flutter Scaffold(resizeToAvoidBottomInset: true) IME handling
iOS native UIWindow.safeAreaInsets, safeAreaLayoutGuide Equivalent to Android systemBars
Web (CSS) env(safe-area-inset-{top,right,bottom,left}) Required for iOS Safari PWA + Android WebView notch devices; fallback to 0 on older browsers
Web (CSS) <meta name="viewport" content="viewport-fit=cover"> Prerequisite for env(safe-area-inset-*) to produce non-zero values on iOS

SDK widgets (approved implementations)

Apps *ust*use the SDK-provided widget where available instead of re-implementing per edge. Using the SDK is the spec's deterministic compliance test.

Platform SDK Widget / API
Flutter (Android / iOS / Linux / macOS / Windows) engines/sdk/koder_kit v0.3.0+ KoderSafeScaffold(appBar:, body:, floatingActionButton:, …) — dropin replacement for Scaffold with SafeArea prewired + optional per-edge toggles + minimumPadding: floor
Flutter engines/sdk/koder_kit v0.3.0+ KoderApp(safeArea: true) — root-level SafeArea for apps that build their own Scaffolds; default true
Web engines/sdk/koder_web_kit (planned) <koder-safe-layout> custom element + baseline CSS vars --pad-top, --pad-bottom consuming env(safe-area-inset-*)
Native Android (Kotlin/Compose) koder-kit-android (deferred) KoderSafeScaffold { } composable; until the lib exists, apply the pattern below manually

Native Android Kotlin — inline pattern

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            KoderEyeTheme(...) {
                Surface(modifier = Modifier.fillMaxSize(), ...) {
                    Column(
                        modifier = Modifier
                            .fillMaxSize()
                            .safeDrawingPadding()     // ← consume all insets
                            .verticalScroll(...)
                            .padding(16.dp)
                    ) { ... }
                }
            }
        }
    }
}

Edgetoedge opt-out (rare)

Apps with genuine edgetoedge content (video players, splash screens, maps) pass safeArea: false on KoderApp and handle individual edges per screen — e.g. keep the video surface under the status bar but consume bottomPadding for playback controls.

Deterministic audit checks

/k-housekeep audit (ticket engines/sdk/koder_kit#003) grep-verifies:

  1. Every Flutter app with koder_kit in pubspec.yaml imports KoderApp.
  2. Every Scaffold(body: …) at the app entry point uses either SafeArea

    or KoderSafeScaffold. A raw Column / ListView / Stack at body: position triggers a warning.

  3. Every landing / web app that ships koder-web-kit.js also references

    koder-web-kit.css (or equivalent providing --pad-top vars).

  4. KoderApp(safeArea: false) presence triggers an info-level annotation:

    "edgetoedge opt-in — verify manually that insets are consumed per screen".

Rationale

This spec exists because the pattern is rediscovered per-app, forgotten in half of them, and leads to clipped UI that is only caught in screenshot review. Encapsulating it in the SDK reduces the cost from every app re-reads this spec to every app imports one symbol, and the audit makes compliance verifiable without human review. See engines/sdk/koder_kit/docs/rfcs/RFC-001-spec-encapsulation-across-platforms.md §2.1 for the AItokensavings argument.

Canonical reference

engines/sdk/koder_kit/lib/src/safe_scaffold.dart — Flutter reference. products/dev/eye/app/android/app/src/main/kotlin/dev/koder/eye/MainActivity.kt — native Kotlin reference pattern.

  • ../themes/light-dark.kmd — companion cross-cutting UI spec
  • ../koder-app/behaviors.kmd — parent behaviors spec

Source: ../home/koder/dev/koder/meta/docs/stack/specs/app-layout/safe-area.kmd