wrap static method

Widget wrap({
  1. required Widget child,
  2. GlassThemeData? theme,
  3. bool respectSystemAccessibility = true,
  4. bool adaptiveQuality = false,
  5. GlassAdaptiveScopeConfig? adaptiveConfig,
  6. Brightness? brightnessResolver(
    1. BuildContext
    )?,
})

Wraps child in the Liquid Glass infrastructure scopes and applies all behavioral configuration.

Responsibility: widget-tree composition and runtime behavior. All configuration that affects how glass widgets behave lives here — explicit, visible, and co-located with the widget tree entry point.

Optional — provides app-wide theming and adaptive quality. GlassBackdropScope is no longer needed (each glass layer manages its own backdrop); wrap() is only required if you use theme: or adaptiveQuality:.

// Zero-config (most apps):
runApp(LiquidGlassWidgets.wrap(const MyApp()));

// Recommended for Android / broad device support:
runApp(LiquidGlassWidgets.wrap(
  child: const MyApp(),
  adaptiveQuality: true,
  theme: GlassThemeData(...),
));

// Game / experience — bypass accessibility, conservative quality start:
runApp(LiquidGlassWidgets.wrap(
  child: const MyApp(),
  respectSystemAccessibility: false,
  adaptiveQuality: true,
  adaptiveConfig: GlassAdaptiveScopeConfig(
    initialQuality: GlassQuality.standard,
    allowStepUp: true,
  ),
));

Parameters

respectSystemAccessibility (default true)
When true, system Reduce Motion and Reduce Transparency flags are respected automatically — no extra setup required. All glass widgets read MediaQuery directly and degrade gracefully. Set to false to ignore system accessibility flags globally (e.g. for a game where full glass fidelity is intentional regardless of OS settings). A GlassAccessibilityScope placed anywhere in the widget tree always takes precedence over this flag, allowing per-subtree overrides.

adaptiveQuality (default false, experimental)
When true, inserts a root GlassAdaptiveScope that automatically benchmarks the device and adjusts the global glass quality ceiling in real time. Three phases:

  • Phase 1 (synchronous): forces minimal where shaders are unsupported; caps at standard on web.
  • Phase 2 (~180 frames ≈ 3 s at 60 fps): measures real P75 raster durations and sets the initial quality tier.
  • Phase 3 (ongoing, near-zero overhead): degrades when P95 exceeds 1.5× the frame budget for 3 consecutive windows; recovers when P95 drops below 0.6× budget for 10 consecutive windows.

Experimental in 0.8.0 — Phase 2 thresholds (12 ms / 20 ms P75) are based on reasoning, not yet validated across the full Android device landscape. Enable this feature and report unexpected quality degradation or promotion to help us tune the thresholds.

Acts as an app-wide quality ceiling — individual widgets with an explicit quality: parameter are still capped by it. When no adaptiveConfig is provided, the scope starts at GlassQuality.standard to prevent jank during the warm-up window on mid-range devices.

For per-screen control, use GlassAdaptiveScope directly in the tree.

adaptiveConfig (optional)
Custom GlassAdaptiveScopeConfig for the root GlassAdaptiveScope. Ignored when adaptiveQuality is false. Defaults to GlassAdaptiveScopeConfig(initialQuality: GlassQuality.standard).

Scope nesting order (outermost → innermost → child)

GlassAdaptiveScope (when enabled) → GlassTheme (when provided) → child

Implementation

///
/// **`adaptiveConfig`** (optional)\
/// Custom [GlassAdaptiveScopeConfig] for the root [GlassAdaptiveScope].
/// Ignored when [adaptiveQuality] is `false`. Defaults to
/// `GlassAdaptiveScopeConfig(initialQuality: GlassQuality.standard)`.
///
/// ### Scope nesting order (outermost → innermost → child)
///
/// `GlassAdaptiveScope` (when enabled) → `GlassTheme` (when provided) → `child`
static Widget wrap({
  required Widget child,
  GlassThemeData? theme,
  bool respectSystemAccessibility = true,
  bool adaptiveQuality = false,
  GlassAdaptiveScopeConfig? adaptiveConfig,

  /// Optional brightness resolver for MaterialApp integration.
  ///
  /// When using `MaterialApp`, pass `Theme.maybeBrightnessOf` here so glass
  /// widgets correctly honour `ThemeMode.light` / `.dark` / `.system` even
  /// when the device OS and the app theme disagree:
  ///
  /// ```dart
  /// runApp(LiquidGlassWidgets.wrap(
  ///   child: const MyApp(),
  ///   brightnessResolver: Theme.maybeBrightnessOf,
  /// ));
  /// ```
  ///
  /// This package has zero `flutter/material.dart` imports (required for the
  /// `cupertino_ui` split). The callback pattern lets you bridge Material's
  /// `ThemeMode` into the glass brightness cascade without coupling the
  /// package to Material. `CupertinoApp` users can omit this parameter.
  Brightness? Function(BuildContext)? brightnessResolver,
}) {
  // Apply global accessibility preference.
  glass_config.respectSystemAccessibility = respectSystemAccessibility;

  // Register the optional Material brightness resolver.
  // This lets MaterialApp users pass Theme.maybeBrightnessOf without this
  // package needing to import flutter/material.dart.
  glassExternalBrightnessResolver = brightnessResolver;

  Widget result = child;

  if (theme != null) {
    result = GlassTheme(data: theme, child: result);
  }

  if (adaptiveQuality) {
    // When no adaptiveConfig is given: GlassAdaptiveScope.initState() seeds
    // the first frame at GlassQuality.standard while Phase 2 benchmarks the
    // device (~3 s). Phase 2 then promotes to `premium` if the device passes
    // the warmup threshold — no caller config needed.
    //
    // When the caller provides adaptiveConfig: use their settings as-is.
    // If initialQuality is null, Phase 2 still runs fresh and promotes/demotes
    // from the conservative standard starting point.
    final config = adaptiveConfig ?? const GlassAdaptiveScopeConfig();

    result = GlassAdaptiveScope(
      minQuality: config.minQuality,
      maxQuality: config.maxQuality,
      initialQuality: config.initialQuality,
      targetFrameMs: config.targetFrameMs,
      allowStepUp: config.allowStepUp,
      warmupPremiumThresholdMs: config.warmupPremiumThresholdMs,
      warmupStandardThresholdMs: config.warmupStandardThresholdMs,
      frostStep: config.frostStep,
      onQualityChanged: config.onQualityChanged,
      onDiagnostic: config.onDiagnostic,
      debugLogDiagnostics: config.debugLogDiagnostics,
      child: result,
    );
  }

  return result;
}