content: import 'dart:math' as math;
  
  import 'package:flex_seed_scheme/flex_seed_scheme.dart';
  import 'package:flutter/material.dart';
  
  // TODO(rydmike): Investigate why we in this Flutter version suddenly need to
  //  ignore discarded futures for AnimationController()..forward
  // ignore_for_file: discarded_futures
  
  const Duration _kUnconfirmedSplashDuration = Duration(milliseconds: 20);
  const Duration _kSplashFadeDuration = Duration(milliseconds: 20);
  
  /// Logical pixels
  const double _kSplashInitialSize = 0.0;
  
  /// pixels per millisecond
  const double _kSplashConfirmedVelocity = 1000.0;
  
  /// A visual reaction on a piece of [Material] to user input.
  ///
  /// An immediate highlight ink feature whose origin starts at the input
  /// touch point, but expands from touch point in zero duration for an immediate
  /// highlight effect instead of ink.
  ///
  /// This feature is a complete copy of Flutter SDK [InkSplash], but with the
  /// splash timings and velocity adjusted. This could probably be made simpler,
  /// but it is no worse than the [InkSplash] and a quick way to make
  /// one that only has the ink highlight feature, without animated splash.
  ///
  /// You can also use the NoSplash.splashFactory to defeat the default ink
  /// splash drawn by an [InkWell] or [ButtonStyle]. It is similar to this
  /// feature, but it animates the appearance of the tap highlight, whereas
  /// [FlexInstantSplash] does not animate the appearance of the tap highlight,
  /// it is instant.
  ///
  /// This object is rarely created directly. Instead of creating an ink splash
  /// directly, consider using an [InkResponse] or [InkWell] widget, which uses
  /// gestures (such as tap and long-press) to trigger ink splashes.
  ///
  /// See also:
  ///
  ///  * [InkRipple], which is an ink splash feature that expands more
  ///    aggressively than [InkSplash] class does.
  ///  * [InkResponse], which uses gestures to trigger ink highlights and ink
  ///    splashes in the parent [Material].
  ///  * [InkWell], which is a rectangular [InkResponse] (the most common type of
  ///    ink response).
  ///  * [Material], which is the widget on which the ink splash is painted.
  ///  * [InkHighlight], which is an ink feature that emphasizes a part of a
  ///    [Material].
  ///  * [Ink], a convenience widget for drawing images and other decorations on
  ///    Material widgets.
  class FlexInstantSplash extends InteractiveInkFeature {
    /// Begin a splash, centered at position relative to [referenceBox].
    ///
    /// The [controller] argument is typically obtained via
    /// `Material.of(context)`.
    ///
    /// If `containedInkWell` is true, then the splash will be sized to fit
    /// the well rectangle, then clipped to it when drawn. The well
    /// rectangle is the box returned by `rectCallback`, if provided, or
    /// otherwise is the bounds of the [referenceBox].
    ///
    /// If `containedInkWell` is false, then `rectCallback` should be null.
    /// The ink splash is clipped only to the edges of the [Material].
    /// This is the default.
    ///
    /// When the splash is removed, `onRemoved` will be called.
    FlexInstantSplash({
      required MaterialInkController controller,
      required super.referenceBox,
      required TextDirection textDirection,
      Offset? position,
      required Color color,
      bool containedInkWell = false,
      RectCallback? rectCallback,
      BorderRadius? borderRadius,
      super.customBorder,
      double? radius,
      super.onRemoved,
    })  : _position = position,
          _borderRadius = borderRadius ?? BorderRadius.zero,
          _targetRadius = radius ??
              _getTargetRadius(
                  referenceBox, containedInkWell, rectCallback, position!),
          _clipCallback =
              _getClipCallback(referenceBox, containedInkWell, rectCallback),
          _repositionToReferenceBox = !containedInkWell,
          _textDirection = textDirection,
          super(controller: controller, color: color) {
      _radiusController = AnimationController(
          duration: _kUnconfirmedSplashDuration, vsync: controller.vsync)
        ..addListener(controller.markNeedsPaint)
        ..forward();
      _radius = _radiusController.drive(Tween<double>(
        begin: _kSplashInitialSize,
        end: _targetRadius,
      ));
      _alphaController = AnimationController(
          duration: _kSplashFadeDuration, vsync: controller.vsync)
        ..addListener(controller.markNeedsPaint)
        ..addStatusListener(_handleAlphaStatusChanged);
      _alpha = _alphaController!.drive(IntTween(
        begin: color.alpha8bit,
        end: 0,
      ));
  
      controller.addInkFeature(this);
    }
  
    final Offset? _position;
    final BorderRadius _borderRadius;
    final double _targetRadius;
    final RectCallback? _clipCallback;
    final bool _repositionToReferenceBox;
    final TextDirection _textDirection;
  
    late Animation<double> _radius;
    late AnimationController _radiusController;
  
    late Animation<int> _alpha;
    AnimationController? _alphaController;
  
    /// Used to specify this type of ink splash for an [InkWell], [InkResponse],
    /// material [Theme], or [ButtonStyle].
    static const InteractiveInkFeatureFactory splashFactory =
        _InstantSplashFactory();
  
    @override
    void confirm() {
      final int duration = (_targetRadius / _kSplashConfirmedVelocity).floor();
      _radiusController
        ..duration = Duration(milliseconds: duration)
        ..forward();
      _alphaController!.forward();
    }
  
    // coverage:ignore-start
    @override
    void cancel() {
      _alphaController?.forward();
    }
    // coverage:ignore-end
  
    void _handleAlphaStatusChanged(AnimationStatus status) {
      if (status == AnimationStatus.completed) {
        dispose();
      }
    }
  
    @override
    void dispose() {
      _radiusController.dispose();
      _alphaController!.dispose();
      _alphaController = null;
      super.dispose();
    }
  
    @override
    void paintFeature(Canvas canvas, Matrix4 transform) {
      final Paint paint = Paint()..color = color.withAlpha(_alpha.value);
      Offset? center = _position;
      // coverage:ignore-start
      if (_repositionToReferenceBox) {
        center = Offset.lerp(center, referenceBox.size.center(Offset.zero),
            _radiusController.value);
      }
      // coverage:ignore-end
      paintInkCircle(
        canvas: canvas,
        transform: transform,
        paint: paint,
        center: center!,
        textDirection: _textDirection,
        radius: _radius.value,
        customBorder: customBorder,
        borderRadius: _borderRadius,
        clipCallback: _clipCallback,
      );
    }
  }
  
  RectCallback? _getClipCallback(
      RenderBox referenceBox, bool containedInkWell, RectCallback? rectCallback) {
    if (rectCallback != null) {
      return rectCallback;
    }
    if (containedInkWell) {
      return () => Offset.zero & referenceBox.size;
    }
    return null;
  }
  
  double _getTargetRadius(RenderBox referenceBox, bool containedInkWell,
      RectCallback? rectCallback, Offset position) {
    if (containedInkWell) {
      final Size size =
          rectCallback != null ? rectCallback().size : referenceBox.size;
      return _getSplashRadiusForPositionInSize(size, position);
    }
    return Material.defaultSplashRadius;
  }
  
  double _getSplashRadiusForPositionInSize(Size bounds, Offset position) {
    final double d1 = (position - bounds.topLeft(Offset.zero)).distance;
    final double d2 = (position - bounds.topRight(Offset.zero)).distance;
    final double d3 = (position - bounds.bottomLeft(Offset.zero)).distance;
    final double d4 = (position - bounds.bottomRight(Offset.zero)).distance;
    return math.max(math.max(d1, d2), math.max(d3, d4)).ceilToDouble();
  }
  
  class _InstantSplashFactory extends InteractiveInkFeatureFactory {
    const _InstantSplashFactory();
  
    @override
    InteractiveInkFeature create({
      required MaterialInkController controller,
      required RenderBox referenceBox,
      required Offset position,
      required Color color,
      required TextDirection textDirection,
      bool containedInkWell = false,
      RectCallback? rectCallback,
      BorderRadius? borderRadius,
      ShapeBorder? customBorder,
      double? radius,
      VoidCallback? onRemoved,
    }) {
      return FlexInstantSplash(
        controller: controller,
        referenceBox: referenceBox,
        position: position,
        color: color,
        containedInkWell: containedInkWell,
        rectCallback: rectCallback,
        borderRadius: borderRadius,
        customBorder: customBorder,
        radius: radius,
        onRemoved: onRemoved,
        textDirection: textDirection,
      );
    }
  }
  