pop static method

Future<void> pop({
  1. required Widget child,
  2. Duration duration = Duration.zero,
  3. double popUpAnimationDuration = 0.4,
  4. BuildContext? context,
  5. Color? popBackgroundColor,
  6. Color? dismissBarrierColor,
  7. Color? backButtonBackgroundColor,
  8. Color? backButtonIconColor,
  9. Color? backgroundOverlaySplashColor,
  10. Color? shadowColor,
  11. bool showTimer = false,
  12. bool hasShadow = true,
  13. bool shouldBackgroundOverlayHaveBorderRadius = true,
  14. bool shouldDismissWhenTappingBackgroundOverlay = true,
  15. bool shouldBeMarginned = true,
  16. bool shouldAnimatePopup = true,
  17. bool shouldSaveThisPop = true,
  18. bool shouldBlurBackgroundOverlayLayer = true,
  19. bool isSecondaryTemporarySinglePop = false,
  20. Gradient? backgroundOverlayGradient,
  21. Offset? popPositionOffset,
  22. Offset? overlayBackgroundLayerOffset,
  23. BoxShadow? popShadow,
  24. VoidCallback? onDismiss,
  25. EdgeInsetsGeometry? popupBorderPadding,
  26. BorderRadiusGeometry? overlayBackgroundBorderRadius,
  27. Curve newWidgetResizeAnimationCurve = Curves.easeInOutBack,
})

Popup a Widget in front of your screen.

child : the Widget you want to popup - popIt will show an empty small box if no child is given duration : the duration to show a popup, if no duration is given, then Duration.zero is set by default, which will make the toast to not autodismiss if so, then in order to dismiss the toast, the user will then need to tap anywhere on the background overlay popUpAnimationDuration : the duration (in double type) for the animation popup to last --> default value is 0.5 sec

Implementation

/// [duration] : the duration to show a popup,
/// if no duration is given, then Duration.zero is set by default, which will make the toast to not autodismiss
/// if so, then in order to dismiss the toast, the user will then need to tap anywhere on the background overlay

/// [popUpAnimationDuration] : the duration (in double type) for the animation popup to last --> default value is 0.5 sec

static Future<void> pop({
  required final Widget child,
  final Duration duration = Duration.zero,
  final double popUpAnimationDuration = 0.4,
  final BuildContext? context,
  final Color? popBackgroundColor,
  final Color? dismissBarrierColor,
  final Color? backButtonBackgroundColor,
  final Color? backButtonIconColor,
  final Color? backgroundOverlaySplashColor,
  final Color? shadowColor,
  final bool showTimer = false,
  final bool hasShadow = true,
  final bool shouldBackgroundOverlayHaveBorderRadius = true,
  final bool shouldDismissWhenTappingBackgroundOverlay = true,
  final bool shouldBeMarginned = true,
  final bool shouldAnimatePopup = true,
  final bool shouldSaveThisPop = true,
  final bool shouldBlurBackgroundOverlayLayer = true,
  final bool isSecondaryTemporarySinglePop = false,
  final Gradient? backgroundOverlayGradient,
  final Offset? popPositionOffset,
  final Offset? overlayBackgroundLayerOffset,
  final BoxShadow? popShadow,
  final VoidCallback? onDismiss,
  final EdgeInsetsGeometry? popupBorderPadding,
  final BorderRadiusGeometry? overlayBackgroundBorderRadius,
  final Curve newWidgetResizeAnimationCurve = Curves.easeInOutBack,
}) async {
  // Ensure the overlay system is installed before showing the popup
  _PopThisBootstrapper.ensureInstalled(context: context);

  //if the widget tree is built
  if (WidgetsBinding.instance.isRootWidgetAttached) {
    if (shouldSaveThisPop == false && PopThis.isPopThisActive()) {
      PopThis.animatedDismissPopThis();
    }

    if (isSecondaryTemporarySinglePop == false) {
      //this Future.delayed is a safetynet to ensure the PopThis is called to be built
      //after any currently running build run of any other unrelated widget
      // await Future.delayed(0.sec, () {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        _updatePopPositionOffset(popPositionOffset);

        //log("_popThisController: ${_popThisController.state}");

        //if an original popIt Overlay already exists
        //then replace the popped widget with this new one
        if (_popThisController.state != null) {
          //first, save the child widget in the Widget history cache list
          if (shouldSaveThisPop == true) {
            _shouldSavePreviousPop.state = true;
            _savePopWidget(
              popToSave: child,
              popPositionOffset: popPositionOffset,
              // Pass all styling parameters
              popBackgroundColor: popBackgroundColor,
              backgroundOverlayColor: dismissBarrierColor,
              backButtonBackgroundColor: backButtonBackgroundColor,
              backButtonIconColor: backButtonIconColor,
              backgroundOverlaySplashColor: backgroundOverlaySplashColor,
              shadowColor: shadowColor,
              showTimer: showTimer,
              hasShadow: hasShadow,
              shouldBackgroundOverlayHaveBorderRadius:
                  shouldBackgroundOverlayHaveBorderRadius,
              shouldDismissWhenTappingBackgroundOverlay:
                  shouldDismissWhenTappingBackgroundOverlay,
              shouldBeMarginned: shouldBeMarginned,
              shouldAnimatePopup: shouldAnimatePopup,
              shouldBlurBackgroundOverlayLayer:
                  shouldBlurBackgroundOverlayLayer,
              popUpAnimationDuration: popUpAnimationDuration,
              backgroundOverlayGradient: backgroundOverlayGradient,
              popShadow: popShadow,
              popupBorderPadding: popupBorderPadding,
              overlayBackgroundBorderRadius: overlayBackgroundBorderRadius,
              animationCurve: newWidgetResizeAnimationCurve,
            );

            // Log for debugging purposes
            // log("After saving pop widget: ${_poppedWidgets.state.length} widgets in list");
          } else {
            _shouldSavePreviousPop.state = false;
          }

          //then repop with all style parameters
          _rePop(
            child,
            onDismiss,
            duration,
            popBackgroundColor: popBackgroundColor,
            backgroundOverlayColor: dismissBarrierColor,
            backButtonBackgroundColor: backButtonBackgroundColor,
            backButtonIconColor: backButtonIconColor,
            backgroundOverlaySplashColor: backgroundOverlaySplashColor,
            shadowColor: shadowColor,
            showTimer: showTimer,
            hasShadow: hasShadow,
            shouldBackgroundOverlayHaveBorderRadius:
                shouldBackgroundOverlayHaveBorderRadius,
            shouldDismissWhenTappingBackgroundOverlay:
                shouldDismissWhenTappingBackgroundOverlay,
            shouldBeMarginned: shouldBeMarginned,
            shouldAnimatePopup: shouldAnimatePopup,
            shouldBlurBackgroundOverlayLayer:
                shouldBlurBackgroundOverlayLayer,
            popUpAnimationDuration: popUpAnimationDuration,
            backgroundOverlayGradient: backgroundOverlayGradient,
            popShadow: popShadow,
            popupBorderPadding: popupBorderPadding,
            overlayBackgroundBorderRadius: overlayBackgroundBorderRadius,
            animationCurve: newWidgetResizeAnimationCurve,
          );
          return;
        } else {
          //set the timer (if given a duration to show the pop for)
          //if (duration != Duration.zero) {
          //initialise the _onDismissTimerController

          _onDismissTimerController.state = _OnDismissController()
            ..onDismissCallbacks.add(onDismiss)
            ..onDismissTimer = duration != Duration.zero
                ? PausableTimer(
                    duration,
                    () {
                      duration == Duration.zero
                          ? null
                          : PopThis.animatedDismissPopThis(
                              shouldPopBackToPreviousWidget: false);
                    },
                  )
                : PausableTimer(
                    Duration.zero,
                    () {},
                  );

          //start the TimerController
          _onDismissTimerController.state!.onDismissTimer.start();
          //  }

          //first, save the child widget in the Widget history cache list
          if (shouldSaveThisPop == true) {
            _savePopWidget(
              popToSave: child,
              popPositionOffset: popPositionOffset,
              // Pass all styling parameters
              popBackgroundColor: popBackgroundColor,
              backgroundOverlayColor: dismissBarrierColor,
              backButtonBackgroundColor: backButtonBackgroundColor,
              backButtonIconColor: backButtonIconColor,
              backgroundOverlaySplashColor: backgroundOverlaySplashColor,
              shadowColor: shadowColor,
              showTimer: showTimer,
              hasShadow: hasShadow,
              shouldBackgroundOverlayHaveBorderRadius:
                  shouldBackgroundOverlayHaveBorderRadius,
              shouldDismissWhenTappingBackgroundOverlay:
                  shouldDismissWhenTappingBackgroundOverlay,
              shouldBeMarginned: shouldBeMarginned,
              shouldAnimatePopup: shouldAnimatePopup,
              shouldBlurBackgroundOverlayLayer:
                  shouldBlurBackgroundOverlayLayer,
              popUpAnimationDuration: popUpAnimationDuration,
              backgroundOverlayGradient: backgroundOverlayGradient,
              popShadow: popShadow,
              popupBorderPadding: popupBorderPadding,
              overlayBackgroundBorderRadius: overlayBackgroundBorderRadius,
              animationCurve: newWidgetResizeAnimationCurve,
            );
          } else {
            //if the user does not want to save the widget, then set the _shouldSavePreviousPop to false
            _shouldSavePreviousPop.state = false;
          }

          _popThisController.state = _showCustomOverlay(
            (context, opacity) => OnBuilder(
                listenTo: _poppedWidgets,
                builder: () {
                  // Get all parameters from current pop widget's state or fallback to original ones
                  var lastWidget = _poppedWidgets.state.isNotEmpty
                      ? _poppedWidgets.state.last
                      : null;

                  // Colors
                  Color? currentBackgroundOverlayColor =
                      lastWidget?.backgroundOverlayColor ??
                          dismissBarrierColor;
                  Color? currentBackgroundOverlaySplashColor =
                      lastWidget?.backgroundOverlaySplashColor ??
                          backgroundOverlaySplashColor;
                  Color? currentPopBackgroundColor =
                      lastWidget?.popBackgroundColor ?? popBackgroundColor;
                  Color? currentBackButtonBackgroundColor =
                      lastWidget?.backButtonBackgroundColor ??
                          backButtonBackgroundColor;
                  Color? currentBackButtonIconColor =
                      lastWidget?.backButtonIconColor ?? backButtonIconColor;
                  Color? currentShadowColor =
                      lastWidget?.shadowColor ?? shadowColor;

                  // Boolean flags
                  bool currentShowTimer = lastWidget?.showTimer ?? showTimer;
                  bool currentHasShadow = lastWidget?.hasShadow ?? hasShadow;
                  bool currentShouldBackgroundOverlayHaveBorderRadius =
                      lastWidget?.shouldBackgroundOverlayHaveBorderRadius ??
                          shouldBackgroundOverlayHaveBorderRadius;
                  bool currentShouldDismissWhenTappingBackgroundOverlay =
                      lastWidget?.shouldDismissWhenTappingBackgroundOverlay ??
                          shouldDismissWhenTappingBackgroundOverlay;
                  bool currentShouldBeMarginned =
                      lastWidget?.shouldBeMarginned ?? shouldBeMarginned;
                  bool currentShouldAnimatePopup =
                      lastWidget?.shouldAnimatePopup ?? shouldAnimatePopup;

                  // Numeric values
                  double currentPopUpAnimationDuration =
                      lastWidget?.popUpAnimationDuration ??
                          popUpAnimationDuration;

                  // Complex objects

                  BoxShadow? currentPopShadow =
                      lastWidget?.popShadow ?? popShadow;
                  EdgeInsetsGeometry? currentPopupBorderPadding =
                      lastWidget?.popupBorderPadding ?? popupBorderPadding;
                  BorderRadiusGeometry? currentOverlayBackgroundBorderRadius =
                      lastWidget?.overlayBackgroundBorderRadius ??
                          overlayBackgroundBorderRadius;
                  Curve currentAnimationCurve = lastWidget?.animationCurve ??
                      newWidgetResizeAnimationCurve;

                  return ClipRRect(
                    borderRadius:
                        currentShouldBackgroundOverlayHaveBorderRadius
                            ? currentOverlayBackgroundBorderRadius ??
                                BorderRadius.circular(0)
                            : BorderRadius.zero,
                    child: Scaffold(
                      resizeToAvoidBottomInset: false,
                      backgroundColor: Colors.transparent,
                      body: SizedBox(
                        height: 100.h,
                        width: 100.w,
                        child: Material(
                          type: MaterialType.transparency,
                          child: Stack(
                            clipBehavior: Clip.none,
                            children: [
                              //Background Empty space widget
                              Positioned(
                                left: overlayBackgroundLayerOffset?.dx,
                                top: overlayBackgroundLayerOffset?.dy,
                                child: //creates a underneath overlay layer

                                    //this animatedSwitcher controls
                                    //the background overlay fade animation at the end of the pop
                                    AnimatedSwitcher(
                                  //  key: const ValueKey('main_switcher'),
                                  duration: 0.3.sec,
                                  switchInCurve: Curves.easeIn,
                                  switchOutCurve: Curves.easeInOut,
                                  child: PopThis.isPopThisActive() == false
                                      ? const SizedBox(
                                          //   key: ValueKey('empty_box_main'),
                                          )
                                      : STweenAnimationBuilder<double>(
                                          tween: Tween<double>(
                                            begin: (lastWidget
                                                        ?.shouldBlurBackgroundOverlayLayer ??
                                                    shouldBlurBackgroundOverlayLayer)
                                                ? 0.0
                                                : 10.0,
                                            end: (lastWidget
                                                        ?.shouldBlurBackgroundOverlayLayer ??
                                                    shouldBlurBackgroundOverlayLayer)
                                                ? 10.0
                                                : 0.0,
                                          ),
                                          duration: 0.3.sec,
                                          curve: Curves.easeOut,
                                          builder:
                                              (context, blurValue, child) =>
                                                  ClipRect(
                                            child: BackdropFilter(
                                              filter: ImageFilter.blur(
                                                sigmaX: blurValue,
                                                sigmaY: blurValue,
                                              ),
                                              child: child,
                                            ),
                                          ),
                                          child: SButton(
                                            //  key: const ValueKey('button_main'),
                                            onTap: (position) {
                                              // Use the temporary variable we created
                                              bool shouldDismiss =
                                                  currentShouldDismissWhenTappingBackgroundOverlay;

                                              shouldDismiss == false
                                                  ? null
                                                  : PopThis
                                                      .animatedDismissPopThis(
                                                      shouldPopBackToPreviousWidget:
                                                          false,
                                                    );
                                            },
                                            splashColor:
                                                currentBackgroundOverlaySplashColor ??
                                                    Colors.transparent,
                                            shouldBounce: false,
                                            child: Box(
                                              height: 100.h,
                                              width: 100.w,
                                              color:
                                                  currentBackgroundOverlayColor ??
                                                      Colors.black.withValues(
                                                          alpha: 0.3),
                                            ),
                                          ),
                                        ),
                                ),
                              ),

                              // the toast content widget
                              _popThisController.state == null
                                  ? const SizedBox().animate(
                                      effects: [
                                        FadeEffect(
                                          duration:
                                              currentPopUpAnimationDuration
                                                  .sec,
                                          curve: currentAnimationCurve,
                                        ),
                                      ],
                                    )
                                  : Positioned(
                                      left: _popPositionOffset.state?.dx,
                                      top: _popPositionOffset.state?.dy,
                                      child: _AnimatedPopContent(
                                        animationDuration:
                                            currentPopUpAnimationDuration,
                                        animationCurve: currentAnimationCurve,
                                        shouldAnimatePopup:
                                            currentShouldAnimatePopup,
                                        child: _PopThisUp(
                                          isSecondaryPop: false,
                                          backgroundColor:
                                              currentPopBackgroundColor,
                                          duration: duration,
                                          showTimer: currentShowTimer,
                                          // if an offset position is not given, then remove the margin,
                                          // so the popup can be in the center
                                          shouldBeMarginned:
                                              popPositionOffset == null
                                                  ? false
                                                  : currentShouldBeMarginned,
                                          isCentered:
                                              popPositionOffset == null
                                                  ? true
                                                  : false,
                                          hasShadow: currentHasShadow,
                                          boxShadow: currentPopShadow,
                                          shadowColor: currentShadowColor,
                                          backButtonBackgroundColor:
                                              currentBackButtonBackgroundColor,
                                          backButtonIconColor:
                                              currentBackButtonIconColor,
                                          popupBorderPadding:
                                              currentPopupBorderPadding,
                                          child:
                                              _poppedWidgets.state.isNotEmpty
                                                  ? _poppedWidgets.state.last
                                                          ?.savedPop ??
                                                      child
                                                  : child,
                                        ),
                                      ),
                                    ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  );
                }),
            duration: duration,
            context: context,
          );
        }
      });
    } else {
      //as precaution, dismiss any previous secondary temp pop
      PopThis.dismissSecondaryTempPopThis();

      //then show the Secondary Temp popup

      _secondaryTempPopThisController.state = _showCustomOverlay(
        (context, opacity) => Material(
          type: MaterialType.transparency,
          child: ClipRRect(
            borderRadius: shouldBackgroundOverlayHaveBorderRadius
                ? overlayBackgroundBorderRadius ?? BorderRadius.circular(32)
                : BorderRadius.zero,
            child: Scaffold(
              resizeToAvoidBottomInset: false,
              backgroundColor: Colors.transparent,
              body: SizedBox(
                height: 100.h,
                width: 100.w,
                child: Stack(
                  clipBehavior: Clip.none,
                  children: [
                    //Background Empty space widget
                    Positioned(
                      left: overlayBackgroundLayerOffset?.dx,
                      top: overlayBackgroundLayerOffset?.dy,
                      child: //creates a underneath overlay layer

                          //this animatedSwitcher controls
                          //the background overlay fade animation at the end of the pop
                          AnimatedSwitcher(
                        // key: const ValueKey('secondary_switcher'),
                        duration: 0.3.sec,
                        switchInCurve: Curves.easeIn,
                        switchOutCurve: Curves.easeInOut,
                        child: STweenAnimationBuilder<double>(
                          tween: Tween<double>(
                            begin:
                                shouldBlurBackgroundOverlayLayer ? 0.0 : 10.0,
                            end:
                                shouldBlurBackgroundOverlayLayer ? 10.0 : 0.0,
                          ),
                          duration: 0.3.sec,
                          curve: Curves.easeOut,
                          builder: (context, blurValue, child) => ClipRect(
                            child: BackdropFilter(
                              filter: ImageFilter.blur(
                                sigmaX: blurValue,
                                sigmaY: blurValue,
                              ),
                              child: child,
                            ),
                          ),
                          child: SButton(
                            // key: const ValueKey('button_secondary'),
                            onTap: (position) =>
                                shouldDismissWhenTappingBackgroundOverlay ==
                                        false
                                    ? null
                                    : PopThis
                                        .animatedDismissSecondaryTempPopThis(
                                            onDismissExtraCallback:
                                                onDismiss),
                            splashColor: backgroundOverlaySplashColor ??
                                Colors.transparent,
                            shouldBounce: false,
                            child: Box(
                              height: 100.h,
                              width: 100.w,
                              color: dismissBarrierColor ??
                                  Colors.black.withValues(alpha: 0.3),
                            ),
                          ),
                        ),
                      ),
                    ),

                    // the toast content widget
                    Positioned(
                      left: popPositionOffset?.dx,
                      top: popPositionOffset?.dy,
                      child: _AnimatedPopContent(
                        animationDuration: popUpAnimationDuration,
                        animationCurve: newWidgetResizeAnimationCurve,
                        shouldAnimatePopup: shouldAnimatePopup,
                        child: _PopThisUp(
                          isSecondaryPop: true,
                          backgroundColor: popBackgroundColor,
                          duration: duration,
                          showTimer: showTimer,
                          // if an offset position is not given, then remove the margin,
                          // so the popup can be in the center
                          shouldBeMarginned: popPositionOffset == null
                              ? false
                              : shouldBeMarginned,
                          isCentered:
                              popPositionOffset == null ? true : false,
                          hasShadow: hasShadow,
                          boxShadow: popShadow,
                          shadowColor: shadowColor,
                          backButtonBackgroundColor:
                              backButtonBackgroundColor,
                          backButtonIconColor: backButtonIconColor,
                          popupBorderPadding: popupBorderPadding,
                          child: _poppedWidgets.state.isNotEmpty
                              ? _poppedWidgets.state.last?.savedPop ?? child
                              : child,
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ),
        duration: duration,
        context: context,
      );
    }
  }
}