flutter_edge_guard

pub package License: MIT Flutter Dart

Make your entire Flutter app Android 15 Edge-to-Edge compliant with a single line of code.

flutter_edge_guard is a drop-in protection layer and diagnostics engine that automatically handles system bar and gesture inset overlaps for your app, meaning you don't have to manually add SafeArea to dozens of existing screen classes.


What is Edge-to-Edge? (And why you need this)

Starting with Android 15 (API 35), Google enforces "edge-to-edge" window behavior by default:

  • The status bar (top) and navigation/gesture bar (bottom) are transparent.
  • Your app's background draws behind these system bars to look modern and immersive.

The Problem: If you built your app before Android 15, your bottom buttons, Floating Action Buttons (FABs), or last list items will now be trapped underneath the Android gesture bar. They become untappable or visually broken.

The Old Fix: Go through all 70-80 of your Scaffold screen classes and manually wrap their bodies in SafeArea. (Tedious, and often causes "double-padding" bugs where things get pushed too far up).

The Edge Guard Fix: Wrap your root widget in EdgeGuardApp. It automatically calculates and applies the exact required padding to the bottom of all your screens globally. Your UI is fixed instantly, and your backgrounds still draw beautifully behind the system bars.


Table of Contents


Key Features

  • 🪄 Zero-Edit Global Auto-Fix: Make your whole app edge-to-edge safe just by replacing MaterialApp with EdgeGuardApp. No need to edit your 80+ existing screen files.
  • 🛡️ Intelligent Double-Pad Prevention: Automatically zeroes out MediaQuery insets after applying them, so if you did use SafeArea somewhere, it won't push your UI up twice.
  • ⚡ Animated Keyboard Handling: Smoothly animates bottom-docked actions when the on-screen keyboard (IME) appears or dismisses.
  • 🎨 System Bar Scrims: Dynamic gradient overlays for status and navigation bars ensuring icon and text contrast against arbitrary content.
  • 🔍 Real-Time Diagnostics Engine: Inspects system gestures, navigation modes (3-button, 2-button, gesture), display cutouts, foldables, iOS notches, and Dynamic Island.
  • 🐞 Floating Debug Inspector: On-screen developer tool to visualize active insets, collision zones, and export JSON diagnostic reports.
  • 🩺 Project Doctor CLI: Scans Android manifests, Gradle configurations, and Dart code for common edge-to-edge deprecations and pitfalls.

Requirements

  • Dart SDK: >=3.5.0 <4.0.0
  • Flutter: >=3.24.0

Installation

Add flutter_edge_guard to your pubspec.yaml:

dependencies:
  flutter_edge_guard: ^0.1.0

Or run:

flutter pub add flutter_edge_guard

Quick Start

Wrap your root widget with EdgeGuardApp (a drop-in replacement for MaterialApp). This applies bottom-edge navigation bar protection to all 80+ screens in your app with a single line of code, while preventing double-padding issues.

import 'package:flutter/material.dart';
import 'package:flutter_edge_guard/flutter_edge_guard.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    // 1-line change: replace MaterialApp with EdgeGuardApp
    return EdgeGuardApp(
      title: 'My App',
      home: const HomeScreen(),
    );
  }
}

2. Full-Bleed Exemptions

If you have a full-bleed screen (like a splash screen, map, or immersive photo viewer) that should draw behind the navigation bar without any padding, simply wrap it in EdgeGuardExempt:

// In your routes map or navigation logic:
'/splash': (context) => const EdgeGuardExempt(child: SplashScreen()),

Configuration Reference

EdgeGuardConfig allows you to customize the behavior of the protection layer. By default, core protections (protectBottomActions, protectBottomSheets) are active, while developer tools remain opt-in:

const EdgeGuard(
  config: EdgeGuardConfig(
    protectBottomActions: true,  // Default: true
    protectBottomSheets: true,   // Default: true
    enableDiagnostics: false,    // Default: false
    enableInspector: false,      // Default: false
    enableDebugOverlay: false,   // Default: false
    showWarnings: false,         // Default: false
    debugOnlyInspector: false,   // Default: false
  ),
  child: MyApp(),
)
Option Type Default Description
protectBottomActions bool true Enables automatic bottom inset protection in EdgeGuardBottomAction.
protectBottomSheets bool true Enables automatic safe inset padding in EdgeGuardBottomSheet.
enableDiagnostics bool false Enables real-time runtime diagnostics analysis.
enableInspector bool false Enables the floating interactive inspector UI.
enableDebugOverlay bool false Displays visual system inset zones directly on screen.
showWarnings bool false Prints diagnostic warnings to the debug console.
debugOnlyInspector bool false Limits inspector visibility strictly to debug builds (kDebugMode).

Widgets in Detail

1. EdgeGuard (Root Provider)

Extracts granular MediaQuery data (paddingOf, viewPaddingOf, viewInsetsOf, systemGestureInsetsOf, displayFeaturesOf) and shares an immutable EdgeInsetsInfo snapshot via EdgeGuardScope.

EdgeGuard(
  config: const EdgeGuardConfig.standard,
  child: MyHomePage(),
)

2. EdgeGuardBottomAction

Wraps bottom-anchored widgets (e.g. submit buttons, persistent footers) to ensure they never clip beneath navigation bars, while preventing accidental double-padding when nested under existing SafeAreas.

Scaffold(
  body: const ContentList(),
  bottomNavigationBar: EdgeGuardBottomAction(
    padding: const EdgeInsets.all(16.0),
    child: FilledButton(
      onPressed: () {},
      child: const Text('Submit'),
    ),
  ),
);

3. EdgeGuardAnimatedAction

Smoothly animates bottom-docked action bars when the keyboard opens or closes:

EdgeGuardAnimatedAction(
  duration: const Duration(milliseconds: 250),
  curve: Curves.easeOutCubic,
  padding: const EdgeInsets.all(16),
  child: FilledButton(
    onPressed: () {},
    child: const Text('Save Changes'),
  ),
)

4. EdgeGuardBottomSheet

A drop-in container for modal bottom sheets that respects both gesture navigation bars and keyboard insets:

showModalBottomSheet(
  context: context,
  builder: (context) => EdgeGuardBottomSheet(
    padding: const EdgeInsets.all(24),
    child: Column(
      mainAxisSize: MainAxisSize.min,
      children: const [
        Text('Safe Bottom Sheet'),
        TextField(decoration: InputDecoration(labelText: 'Type here')),
      ],
    ),
  ),
);

5. EdgeGuardScrim

Draws a subtle, non-interactive gradient behind translucent status or navigation bars to maintain WCAG contrast ratios across arbitrary app backgrounds:

Stack(
  children: [
    const ColorfulBackground(),
    const EdgeGuardScrim(
      edge: EdgeGuardScrimEdge.both, // .top, .bottom, or .both
      maxOpacity: 0.4,
    ),
    const Scaffold(backgroundColor: Colors.transparent, body: MainContent()),
  ],
)

6. EdgeGuardInspector

Enables an interactive floating debug panel to inspect system insets, view identified conflicts, and export JSON diagnostics:

EdgeGuard(
  config: const EdgeGuardConfig(enableInspector: true),
  child: const EdgeGuardInspector(
    child: MyApp(),
  ),
)

7. EdgeGuardZoneOverlay

Visually renders color-coded overlays for status bars (red), navigation bars (blue), gesture areas (orange), and cutouts (purple) in development mode.


Diagnostics Engine

Inspect the current window state programmatically at any point in the widget tree:

final report = EdgeGuardDiagnostics.inspect(context);

print('Active Insets: ${report.insets}');
print('Navigation Mode: ${report.platform.navigationMode}');
print('Issues Detected: ${report.issues.length}');

for (final issue in report.issues) {
  print('[${issue.severity.name}] ${issue.title}: ${issue.problem}');
  print('Suggested Fix: ${issue.solution}');
}

Or use the non-throwing variant:

final report = EdgeGuardDiagnostics.tryInspect(context);

Project Doctor CLI

flutter_edge_guard includes a static analyzer CLI to audit your project for edge-to-edge readiness.

Run Locally

dart run flutter_edge_guard:doctor

CI/CD Integration

Run with strict exit codes in GitHub Actions or other CI pipelines:

dart run flutter_edge_guard:doctor --json --fail-on=warning

Flags:

  • --json: Outputs machine-readable JSON.
  • --fail-on=<warning|critical>: Exits with a non-zero exit code if issues at or above the threshold are detected.
  • --path=<directory>: Analyzes a specific project directory.

Limitations

  • Navigation Mode Heuristics: Android gesture navigation detection relies on platform signals (systemGestureInsets, viewPadding). While highly accurate on modern devices, it is heuristic and does not access non-public OS APIs.
  • Web & Desktop Targets: Insets are reported as zero or desktop-appropriate window paddings since edge-to-edge system bar overlaps do not apply to desktop/browser window frames.

License

MIT License. See LICENSE for details.

Libraries

flutter_edge_guard