presentNudge function

Future<void> presentNudge({
  1. required BuildContext context,
  2. required NudgeConfig config,
  3. EngageActionContext actionContext = EngageActionContext.unknown,
  4. VariableScope scope = VariableScope.empty,
  5. VoidCallback? onPresented,
  6. ValueChanged<ModalRoute>? onRoute,
})

Presents a NudgeConfig over the app, choosing the bottom-sheet or dialog strategy by its surface. Returns a future that completes when the nudge is dismissed (button action, close affordance, scrim, or drag-down).

Implementation

Future<void> presentNudge({
  required BuildContext context,
  required NudgeConfig config,
  EngageActionContext actionContext = EngageActionContext.unknown,
  VariableScope scope = VariableScope.empty,
  VoidCallback? onPresented,
  ValueChanged<ModalRoute<dynamic>>? onRoute,
}) {
  final presentation = _presentations[config.surface.displayType] ??
      const BottomSheetPresentation();
  final viewportWidth = MediaQuery.sizeOf(context).width;
  final canvas = config.canvas;
  final surfaceScale = campaignCanvasDesignScale(
    viewportWidth: viewportWidth,
    designWidth: config.designWidth,
    fullWidth: config.surface.isBottomSheet,
  );
  final maxDialogCanvasWidth = math.max(
    1.0,
    config.designWidth - 2 * config.surface.minHorizontalMargin,
  );
  final fittedCanvasWidth = config.surface.isBottomSheet
      ? canvas.width
      : math.min(canvas.width, maxDialogCanvasWidth);
  final runtimeWidthFraction =
      (fittedCanvasWidth * surfaceScale / viewportWidth)
          .clamp(0.01, 1.0)
          .toDouble();
  final runtimeSurface = config.surface.scaled(
    surfaceScale,
    widthFractionOverride:
        config.surface.isBottomSheet ? null : runtimeWidthFraction,
  );

  final closePlacement = config.surface.closeButton.placement;
  final customCanvasFrame = !config.surface.isFullScreen;

  // Wrap the content so button taps can hand the host the campaign context, and
  // so the renderers can interpolate `{{ placeholder }}` copy against [scope].
  final nudgeContent = EngageActionContextScope(
    actionContext: actionContext,
    child: VariableScopeProvider(
      scope: scope,
      child: _AutoDismissNudge(
        // Any authored auto-dismiss is honored on every surface. The dashboard
        // authors it for full-screen nudges only; the SDK stays ready for more.
        after: config.surface.autoDismissAfter,
        child: CampaignCanvasActionScope(
          onActions: _handleCanvasActions,
          child: config.surface.isFullScreen
              ? FullScreenNudgeView(
                  canvas: canvas,
                  designWidth: config.designWidth,
                  surface: config.surface,
                )
              : customCanvasFrame
                  ? CampaignCanvasStage(
                      canvas: canvas,
                      showBackground: !config.surface.isBottomSheet,
                    )
                  : CampaignCanvasView(
                      canvas: canvas,
                      designWidth: config.designWidth,
                      fullWidth: runtimeSurface.isBottomSheet,
                    ),
        ),
      ),
    ),
  );
  final presented = onPresented == null
      ? nudgeContent
      : _NudgePresented(onPresented: onPresented, child: nudgeContent);
  final content = onRoute == null
      ? presented
      : _NudgeRouteCapture(onRoute: onRoute, child: presented);
  if (customCanvasFrame) {
    return presentPlacedCanvasNudge(
      context: context,
      surface: config.surface,
      closePlacement: closePlacement,
      authoredSize: Size(canvas.width, canvas.height),
      designWidth: config.designWidth,
      stage: content,
      canvasBackground: config.surface.isBottomSheet ? canvas.background : null,
    );
  }
  return presentation.present(
    context: context,
    surface: runtimeSurface,
    content: content,
  );
}