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.

Applicability

All Koder apps (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. Always 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. No 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. Text under the status bar is forbidden unless the design is

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

  4. IME (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. Edge-to-edge 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 must 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:, …) — drop-in replacement for Scaffold with SafeArea pre-wired + 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 {
            KoderKonsulTheme(...) {
                Surface(modifier = Modifier.fillMaxSize(), ...) {
                    Column(
                        modifier = Modifier
                            .fillMaxSize()
                            .safeDrawingPadding()     // ← consume all insets
                            .verticalScroll(...)
                            .padding(16.dp)
                    ) { ... }
                }
            }
        }
    }
}

Edge-to-edge opt-out (rare)

Apps with genuine edge-to-edge 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:

    "edge-to-edge 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 AI-token-savings argument.

Canonical reference

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

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