celebrate static method

void celebrate(
  1. BuildContext context, {
  2. Preset preset = Preset.nova,
  3. CelebrationScene? scene,
  4. ConfettiShowcase? showcase,
  5. bool enableHaptics = true,
  6. bool enableSound = false,
  7. String? soundAssetPath,
  8. CelebrationFeedback? feedback,
  9. List<String>? emojiPool,
  10. ConfettiCustomization? customization,
  11. CelebrationMessageOptions? overlayMessage,
  12. VoidCallback? onComplete,
})

Shows a full-screen confetti animation above the current route.

  • context — any BuildContext within the widget tree. Used to obtain the nearest Overlay.
  • preset — animation style. Defaults to Preset.nova.
  • enableHaptics — fires platform haptic feedback at animation start. Defaults to true.
  • enableSound — plays the asset at soundAssetPath when the animation starts. Defaults to false. Failures are caught silently.
  • soundAssetPath — Flutter asset path registered in the consuming app's pubspec.yaml (e.g. 'assets/sounds/cheer.mp3'). Ignored when enableSound is false. Use trusted paths only — do not pass raw user-supplied strings without allowlisting.
  • feedback — optional grouped haptic/audio settings. When non-null, overrides enableHaptics, enableSound, and soundAssetPath so you can bind one object from app state (e.g. user toggles).
  • emojiPool — unicode strings for emoji-shaped particles; see ConfettiWidget.emojiPool.
  • scene — optional CelebrationScene (preset + base customization), e.g. CelebrationScene.fromConfettiType, CelebrationScene.compose, or CelebrationScene.themed. When non-null, CelebrationScene.preset overrides preset, and CelebrationScene.customization is merged under customization (call-site wins per field).
  • customization — optional count / colors / shapes / physics; see ConfettiCustomization.
  • overlayMessage — optional banner (CelebrationMessageOptions): text, alignment, padding, TextStyle, BoxDecoration, and/or CelebrationMessageOptions.durationInSeconds to cap overlay lifetime.
  • showcase — optional curated tick burst (ConfettiShowcase); when non-null, drives particles instead of preset.
  • onComplete — called once when all particles have faded and the overlay has been removed.

When no Overlay ancestor exists (e.g. wrong context), this returns immediately without showing anything — it does not throw.

Implementation

static void celebrate(
  BuildContext context, {
  Preset preset = Preset.nova,
  CelebrationScene? scene,
  ConfettiShowcase? showcase,
  bool enableHaptics = true,
  bool enableSound = false,
  String? soundAssetPath,
  CelebrationFeedback? feedback,
  List<String>? emojiPool,
  ConfettiCustomization? customization,
  CelebrationMessageOptions? overlayMessage,
  VoidCallback? onComplete,
}) {
  // Dismiss any running animation first.
  dismiss();

  final overlay = Overlay.maybeOf(context);
  if (overlay == null) return;

  final effectivePreset = scene?.preset ?? preset;
  final effectiveCustomization =
      ConfettiCustomization.merge(scene?.customization, customization);

  OverlayEntry? entry;

  void removeEntry() {
    entry?.remove();
    if (_current == entry) _current = null;
    onComplete?.call();
  }

  final msg = overlayMessage;
  final showBanner = msg != null && msg.shouldPaintText;
  final useHost = showBanner || (msg?.durationInSeconds != null);

  if (useHost && msg != null) {
    entry = OverlayEntry(
      builder: (_) => _CelebrationOverlayHost(
        preset: effectivePreset,
        showcase: showcase,
        customization: effectiveCustomization,
        feedback: feedback,
        enableHaptics: enableHaptics,
        enableSound: enableSound,
        soundAssetPath: soundAssetPath,
        emojiPool: emojiPool,
        messageOptions: msg,
        showMessageLayer: showBanner,
        onFinished: removeEntry,
      ),
    );
  } else {
    entry = OverlayEntry(
      builder: (_) => IgnorePointer(
        child: ConfettiWidget(
          preset: effectivePreset,
          showcase: showcase,
          autoPlay: true,
          feedback: feedback,
          enableHaptics: enableHaptics,
          enableSound: enableSound,
          soundAssetPath: soundAssetPath,
          emojiPool: emojiPool,
          customization: effectiveCustomization,
          onComplete: removeEntry,
        ),
      ),
    );
  }

  _current = entry;
  overlay.insert(entry);
}