content: 
  // Copyright 2014 The Flutter Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  import 'dart:math' as math;
  
  import 'package:flutter/foundation.dart';
  import 'package:flutter/material.dart';
  import 'package:flutter/widgets.dart';
  
  // Minimum logical pixel size of the IconButton.
  // See: <https://material.io/design/usability/accessibility.html#layout-typography>.
  const double _kMinButtonSize = kMinInteractiveDimension;
  
  /// A material design icon button.
  ///
  /// An icon button is a picture printed on a [Material] widget that reacts to
  /// touches by filling with color (ink).
  ///
  /// Icon buttons are commonly used in the [AppBar.actions] field, but they can
  /// be used in many other places as well.
  ///
  /// If the [onPressed] callback is null, then the button will be disabled and
  /// will not react to touch.
  ///
  /// Requires one of its ancestors to be a [Material] widget.
  ///
  /// The hit region of an icon button will, if possible, be at least
  /// kMinInteractiveDimension pixels in size, regardless of the actual
  /// [iconSize], to satisfy the [touch target size](https://material.io/design/layout/spacing-methods.html#touch-targets)
  /// requirements in the Material Design specification. The [alignment] controls
  /// how the icon itself is positioned within the hit region.
  ///
  /// {@tool dartpad --template=stateful_widget_scaffold_center}
  ///
  /// This sample shows an `IconButton` that uses the Material icon "volume_up" to
  /// increase the volume.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/assets/material/icon_button.png)
  ///
  /// ```dart preamble
  /// double _volume = 0.0;
  /// ```
  ///
  /// ```dart
  /// Widget build(BuildContext context) {
  ///   return Column(
  ///     mainAxisSize: MainAxisSize.min,
  ///     children: <Widget>[
  ///       IconButton(
  ///         icon: Icon(Icons.volume_up),
  ///         onPressed: () {
  ///           setState(() {
  ///             _volume += 10;
  ///           });
  ///         },
  ///       ),
  ///       Text('Volume : $_volume')
  ///     ],
  ///   );
  /// }
  /// ```
  /// {@end-tool}
  ///
  /// ### Adding a filled background
  ///
  /// Icon buttons don't support specifying a background color or other
  /// background decoration because typically the icon is just displayed
  /// on top of the parent widget's background. Icon buttons that appear
  /// in [AppBar.actions] are an example of this.
  ///
  /// It's easy enough to create an icon button with a filled background
  /// using the [Ink] widget. The [Ink] widget renders a decoration on
  /// the underlying [Material] along with the splash and highlight
  /// [InkResponse] contributed by descendant widgets.
  ///
  /// {@tool dartpad --template=stateless_widget_scaffold}
  ///
  /// In this sample the icon button's background color is defined with an [Ink]
  /// widget whose child is an [InkIconButton]. The icon button's filled background
  /// is a light shade of blue, it's a filled circle, and it's as big as the
  /// button is.
  ///
  /// ![](https://flutter.github.io/assets-for-api-docs/assets/material/icon_button_background.png)
  ///
  /// ```dart
  /// Widget build(BuildContext context) {
  ///   return Material(
  ///     color: Colors.white,
  ///     child: Center(
  ///       child: Ink(
  ///         decoration: const ShapeDecoration(
  ///           color: Colors.lightBlue,
  ///           shape: CircleBorder(),
  ///         ),
  ///         child: IconButton(
  ///           icon: Icon(Icons.android),
  ///           color: Colors.white,
  ///           onPressed: () {},
  ///         ),
  ///       ),
  ///     ),
  ///   );
  /// }
  /// ```
  /// {@end-tool}
  ///
  /// See also:
  ///
  ///  * [Icons], a library of predefined icons.
  ///  * [BackButton], an icon button for a "back" affordance which adapts to the
  ///    current platform's conventions.
  ///  * [CloseButton], an icon button for closing pages.
  ///  * [AppBar], to show a toolbar at the top of an application.
  ///  * [RaisedButton] and [FlatButton], for buttons with text in them.
  ///  * [InkResponse] and [InkWell], for the ink splash effect itself.
  class InkIconButton extends StatelessWidget {
    /// Creates an icon button.
    ///
    /// Icon buttons are commonly used in the [AppBar.actions] field, but they can
    /// be used in many other places as well.
    ///
    /// Requires one of its ancestors to be a [Material] widget.
    ///
    /// The [iconSize], [padding], [autofocus], and [alignment] arguments must not
    /// be null (though they each have default values).
    ///
    /// The [icon] argument must be specified, and is typically either an [Icon]
    /// or an [ImageIcon].
    const InkIconButton({
      Key key,
      this.iconSize = 24.0,
      this.visualDensity,
      this.padding = const EdgeInsets.all(8.0),
      this.alignment = Alignment.center,
      this.splashRadius,
      @required this.icon,
      this.color,
      this.focusColor,
      this.hoverColor,
      this.highlightColor,
      this.splashColor,
      this.disabledColor,
      @required this.onPressed,
      this.onLongPress,
      this.focusNode,
      this.autofocus = false,
      this.enableFeedback = true,
      this.constraints,
    }) : assert(iconSize != null),
          assert(padding != null),
          assert(alignment != null),
          assert(splashRadius == null || splashRadius > 0),
          assert(autofocus != null),
          assert(icon != null),
          super(key: key);
  
    /// The size of the icon inside the button.
    ///
    /// This property must not be null. It defaults to 24.0.
    ///
    /// The size given here is passed down to the widget in the [icon] property
    /// via an [IconTheme]. Setting the size here instead of in, for example, the
    /// [Icon.size] property allows the [InkIconButton] to size the splash area to
    /// fit the [Icon]. If you were to set the size of the [Icon] using
    /// [Icon.size] instead, then the [InkIconButton] would default to 24.0 and then
    /// the [Icon] itself would likely get clipped.
    final double iconSize;
  
    /// Defines how compact the icon button's layout will be.
    ///
    /// {@macro flutter.material.themedata.visualDensity}
    ///
    /// See also:
    ///
    ///  * [ThemeData.visualDensity], which specifies the [density] for all widgets
    ///    within a [Theme].
    final VisualDensity visualDensity;
  
    /// The padding around the button's icon. The entire padded icon will react
    /// to input gestures.
    ///
    /// This property must not be null. It defaults to 8.0 padding on all sides.
    final EdgeInsetsGeometry padding;
  
    /// Defines how the icon is positioned within the IconButton.
    ///
    /// This property must not be null. It defaults to [Alignment.center].
    ///
    /// See also:
    ///
    ///  * [Alignment], a class with convenient constants typically used to
    ///    specify an [AlignmentGeometry].
    ///  * [AlignmentDirectional], like [Alignment] for specifying alignments
    ///    relative to text direction.
    final AlignmentGeometry alignment;
  
    /// The splash radius.
    ///
    /// If null, default splash radius of [Material.defaultSplashRadius] is used.
    final double splashRadius;
  
    /// The icon to display inside the button.
    ///
    /// The [Icon.size] and [Icon.color] of the icon is configured automatically
    /// based on the [iconSize] and [color] properties of _this_ widget using an
    /// [IconTheme] and therefore should not be explicitly given in the icon
    /// widget.
    ///
    /// This property must not be null.
    ///
    /// See [Icon], [ImageIcon].
    final Widget icon;
  
    /// The color for the button's icon when it has the input focus.
    ///
    /// Defaults to [ThemeData.focusColor] of the ambient theme.
    final Color focusColor;
  
    /// The color for the button's icon when a pointer is hovering over it.
    ///
    /// Defaults to [ThemeData.hoverColor] of the ambient theme.
    final Color hoverColor;
  
    /// The color to use for the icon inside the button, if the icon is enabled.
    /// Defaults to leaving this up to the [icon] widget.
    ///
    /// The icon is enabled if [onPressed] is not null.
    ///
    /// ```dart
    /// IconButton(
    ///   color: Colors.blue,
    ///   onPressed: _handleTap,
    ///   icon: Icons.widgets,
    /// )
    /// ```
    final Color color;
  
    /// The primary color of the button when the button is in the down (pressed) state.
    /// The splash is represented as a circular overlay that appears above the
    /// [highlightColor] overlay. The splash overlay has a center point that matches
    /// the hit point of the user touch event. The splash overlay will expand to
    /// fill the button area if the touch is held for long enough time. If the splash
    /// color has transparency then the highlight and button color will show through.
    ///
    /// Defaults to the Theme's splash color, [ThemeData.splashColor].
    final Color splashColor;
  
    /// The secondary color of the button when the button is in the down (pressed)
    /// state. The highlight color is represented as a solid color that is overlaid over the
    /// button color (if any). If the highlight color has transparency, the button color
    /// will show through. The highlight fades in quickly as the button is held down.
    ///
    /// Defaults to the Theme's highlight color, [ThemeData.highlightColor].
    final Color highlightColor;
  
    /// The color to use for the icon inside the button, if the icon is disabled.
    /// Defaults to the [ThemeData.disabledColor] of the current [Theme].
    ///
    /// The icon is disabled if [onPressed] is null.
    final Color disabledColor;
  
    /// The callback that is called when the button is tapped or otherwise activated.
    ///
    /// If this is set to null, the button will be disabled.
    final VoidCallback onPressed;
    final VoidCallback onLongPress;
  
    /// {@macro flutter.widgets.Focus.focusNode}
    final FocusNode focusNode;
  
    /// {@macro flutter.widgets.Focus.autofocus}
    final bool autofocus;
  
    /// Text that describes the action that will occur when the button is pressed.
    ///
    /// This text is displayed when the user long-presses on the button and is
    /// used for accessibility.
    /// Whether detected gestures should provide acoustic and/or haptic feedback.
    ///
    /// For example, on Android a tap will produce a clicking sound and a
    /// long-press will produce a short vibration, when feedback is enabled.
    ///
    /// See also:
    ///
    ///  * [Feedback] for providing platform-specific feedback to certain actions.
    final bool enableFeedback;
  
    /// Optional size constraints for the button.
    ///
    /// When unspecified, defaults to:
    /// ```dart
    /// const BoxConstraints(
    ///   minWidth: kMinInteractiveDimension,
    ///   minHeight: kMinInteractiveDimension,
    /// )
    /// ```
    /// where [kMinInteractiveDimension] is 48.0, and then with visual density
    /// applied.
    ///
    /// The default constraints ensure that the button is accessible.
    /// Specifying this parameter enables creation of buttons smaller than
    /// the minimum size, but it is not recommended.
    ///
    /// The visual density uses the [visualDensity] parameter if specified,
    /// and `Theme.of(context).visualDensity` otherwise.
    final BoxConstraints constraints;
  
    @override
    Widget build(BuildContext context) {
      assert(debugCheckHasMaterial(context));
      final ThemeData theme = Theme.of(context);
      Color currentColor;
      if (onPressed != null)
        currentColor = color;
      else
        currentColor = disabledColor ?? theme.disabledColor;
  
      final VisualDensity effectiveVisualDensity = visualDensity ?? theme.visualDensity;
  
      final BoxConstraints unadjustedConstraints = constraints ?? const BoxConstraints(
        minWidth: _kMinButtonSize,
        minHeight: _kMinButtonSize,
      );
      final BoxConstraints adjustedConstraints = effectiveVisualDensity.effectiveConstraints(unadjustedConstraints);
  
      Widget result = ConstrainedBox(
        constraints: adjustedConstraints,
        child: Padding(
          padding: padding,
          child: SizedBox(
            height: iconSize,
            width: iconSize,
            child: Align(
              alignment: alignment,
              child: IconTheme.merge(
                data: IconThemeData(
                  size: iconSize,
                  color: currentColor,
                ),
                child: icon,
              ),
            ),
          ),
        ),
      );
  
      return Semantics(
        button: true,
        enabled: onPressed != null,
        child: InkResponse(
          focusNode: focusNode,
          autofocus: autofocus,
          canRequestFocus: onPressed != null,
          onTap: onPressed,
          onLongPress: onLongPress,
          enableFeedback: enableFeedback,
          child: result,
          focusColor: focusColor ?? Theme.of(context).focusColor,
          hoverColor: hoverColor ?? Theme.of(context).hoverColor,
          highlightColor: highlightColor ?? Theme.of(context).highlightColor,
          splashColor: splashColor ?? Theme.of(context).splashColor,
          radius: splashRadius ?? math.max(
            Material.defaultSplashRadius,
            (iconSize + math.min(padding.horizontal, padding.vertical)) * 0.7,
            // x 0.5 for diameter -> radius and + 40% overflow derived from other Material apps.
          ),
        ),
      );
    }
  
    @override
    void debugFillProperties(DiagnosticPropertiesBuilder properties) {
      super.debugFillProperties(properties);
      properties.add(DiagnosticsProperty<Widget>('icon', icon, showName: false));
      properties.add(ObjectFlagProperty<VoidCallback>('onPressed', onPressed, ifNull: 'disabled'));
      properties.add(ColorProperty('color', color, defaultValue: null));
      properties.add(ColorProperty('disabledColor', disabledColor, defaultValue: null));
      properties.add(ColorProperty('focusColor', focusColor, defaultValue: null));
      properties.add(ColorProperty('hoverColor', hoverColor, defaultValue: null));
      properties.add(ColorProperty('highlightColor', highlightColor, defaultValue: null));
      properties.add(ColorProperty('splashColor', splashColor, defaultValue: null));
      properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
      properties.add(DiagnosticsProperty<FocusNode>('focusNode', focusNode, defaultValue: null));
    }
  }
  