LCOV - code coverage report
Current view: top level - button - mongol_outlined_button.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 58 0.0 %
Date: 2021-08-02 17:55:49 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2014 The Flutter Authors.
       2             : // Copyright 2021 Suragch.
       3             : // All rights reserved.
       4             : // Use of this source code is governed by a BSD-style license that can be
       5             : // found in the LICENSE file.
       6             : 
       7             : import 'dart:math' as math;
       8             : import 'dart:ui' show lerpDouble;
       9             : 
      10             : import 'package:flutter/foundation.dart';
      11             : import 'package:flutter/widgets.dart';
      12             : import 'package:flutter/material.dart'
      13             :     show
      14             :         ButtonStyle,
      15             :         ButtonStyleButton,
      16             :         ColorScheme,
      17             :         Colors,
      18             :         InkRipple,
      19             :         InteractiveInkFeatureFactory,
      20             :         MaterialState,
      21             :         MaterialStateProperty,
      22             :         MaterialTapTargetSize,
      23             :         OutlinedButtonTheme,
      24             :         Theme,
      25             :         ThemeData,
      26             :         VisualDensity,
      27             :         kThemeChangeDuration;
      28             : 
      29             : /// A vertical Material Design "Outlined Button"; essentially a [MongolTextButton]
      30             : /// with an outlined border.
      31             : ///
      32             : /// Outlined buttons are medium-emphasis buttons. They contain actions
      33             : /// that are important, but they aren’t the primary action in an app.
      34             : ///
      35             : /// An outlined button is a label [child] displayed on a (zero
      36             : /// elevation) [Material] widget. The label's [MongolText] and [Icon]
      37             : /// widgets are displayed in the [style]'s
      38             : /// [ButtonStyle.foregroundColor] and the outline's weight and color
      39             : /// are defined by [ButtonStyle.side].  The button reacts to touches
      40             : /// by filling with the [style]'s [ButtonStyle.backgroundColor].
      41             : ///
      42             : /// The outlined button's default style is defined by [defaultStyleOf].
      43             : /// The style of this outline button can be overridden with its [style]
      44             : /// parameter. The style of all text buttons in a subtree can be
      45             : /// overridden with the [OutlinedButtonTheme] and the style of all of the
      46             : /// outlined buttons in an app can be overridden with the [Theme]'s
      47             : /// [ThemeData.outlinedButtonTheme] property.
      48             : ///
      49             : /// Unlike [MongolTextButton] or [MongolElevatedButton], outline buttons have a
      50             : /// default [ButtonStyle.side] which defines the appearance of the
      51             : /// outline.  Because the default `side` is non-null, it
      52             : /// unconditionally overrides the shape's [OutlinedBorder.side]. In
      53             : /// other words, to specify an outlined button's shape _and_ the
      54             : /// appearance of its outline, both the [ButtonStyle.shape] and
      55             : /// [ButtonStyle.side] properties must be specified.
      56             : ///
      57             : /// {@tool dartpad --template=stateless_widget_scaffold_center}
      58             : ///
      59             : /// Here is an example of a basic [MongolOutlinedButton].
      60             : ///
      61             : /// ```dart
      62             : /// Widget build(BuildContext context) {
      63             : ///   return MongolOutlinedButton(
      64             : ///     onPressed: () {
      65             : ///       print('Received click');
      66             : ///     },
      67             : ///     child: const MongolText('Click Me'),
      68             : ///   );
      69             : /// }
      70             : /// ```
      71             : /// {@end-tool}
      72             : ///
      73             : /// The static [styleFrom] method is a convenient way to create a
      74             : /// outlined button [ButtonStyle] from simple values.
      75             : ///
      76             : /// See also:
      77             : ///
      78             : ///  * [MongolElevatedButton], a filled vertical material design button with a shadow.
      79             : ///  * [MongolTextButton], a vertical material design button without a shadow.
      80             : ///  * <https://material.io/design/components/buttons.html>
      81             : class MongolOutlinedButton extends ButtonStyleButton {
      82             :   /// Create a MongolOutlinedButton.
      83             :   ///
      84             :   /// The [autofocus] and [clipBehavior] arguments must not be null.
      85           0 :   const MongolOutlinedButton({
      86             :     Key? key,
      87             :     required VoidCallback? onPressed,
      88             :     VoidCallback? onLongPress,
      89             :     ButtonStyle? style,
      90             :     FocusNode? focusNode,
      91             :     bool autofocus = false,
      92             :     Clip clipBehavior = Clip.none,
      93             :     required Widget child,
      94           0 :   }) : super(
      95             :           key: key,
      96             :           onPressed: onPressed,
      97             :           onLongPress: onLongPress,
      98             :           style: style,
      99             :           focusNode: focusNode,
     100             :           autofocus: autofocus,
     101             :           clipBehavior: clipBehavior,
     102             :           child: child,
     103             :         );
     104             : 
     105             :   /// Create a text button from a pair of widgets that serve as the button's
     106             :   /// [icon] and [label].
     107             :   ///
     108             :   /// The icon and label are arranged in a column and padded by 12 logical pixels
     109             :   /// at the start, and 16 at the end, with an 8 pixel gap in between.
     110             :   ///
     111             :   /// The [icon] and [label] arguments must not be null.
     112             :   factory MongolOutlinedButton.icon({
     113             :     Key? key,
     114             :     required VoidCallback? onPressed,
     115             :     VoidCallback? onLongPress,
     116             :     ButtonStyle? style,
     117             :     FocusNode? focusNode,
     118             :     bool? autofocus,
     119             :     Clip? clipBehavior,
     120             :     required Widget icon,
     121             :     required Widget label,
     122             :   }) = _MongolOutlinedButtonWithIcon;
     123             : 
     124             :   /// A static convenience method that constructs an outlined button
     125             :   /// [ButtonStyle] given simple values.
     126             :   ///
     127             :   /// The [primary], and [onSurface] colors are used to create a
     128             :   /// [MaterialStateProperty] [ButtonStyle.foregroundColor] value in the same
     129             :   /// way that [defaultStyleOf] uses the [ColorScheme] colors with the same
     130             :   /// names. Specify a value for [primary] to specify the color of the button's
     131             :   /// text and icons as well as the overlay colors used to indicate the hover,
     132             :   /// focus, and pressed states. Use [onSurface] to specify the button's
     133             :   /// disabled text and icon color.
     134             :   ///
     135             :   /// Similarly, the [enabledMouseCursor] and [disabledMouseCursor]
     136             :   /// parameters are used to construct [ButtonStyle.mouseCursor].
     137             :   ///
     138             :   /// All of the other parameters are either used directly or used to
     139             :   /// create a [MaterialStateProperty] with a single value for all
     140             :   /// states.
     141             :   ///
     142             :   /// All parameters default to null, by default this method returns
     143             :   /// a [ButtonStyle] that doesn't override anything.
     144             :   ///
     145             :   /// For example, to override the default shape and outline for an
     146             :   /// [MongolOutlinedButton], one could write:
     147             :   ///
     148             :   /// ```dart
     149             :   /// MongolOutlinedButton(
     150             :   ///   style: OutlinedButton.styleFrom(
     151             :   ///      shape: StadiumBorder(),
     152             :   ///      side: BorderSide(width: 2, color: Colors.green),
     153             :   ///   ),
     154             :   /// )
     155             :   /// ```
     156           0 :   static ButtonStyle styleFrom({
     157             :     Color? primary,
     158             :     Color? onSurface,
     159             :     Color? backgroundColor,
     160             :     Color? shadowColor,
     161             :     double? elevation,
     162             :     TextStyle? textStyle,
     163             :     EdgeInsetsGeometry? padding,
     164             :     Size? minimumSize,
     165             :     Size? fixedSize,
     166             :     Size? maximumSize,
     167             :     BorderSide? side,
     168             :     OutlinedBorder? shape,
     169             :     MouseCursor? enabledMouseCursor,
     170             :     MouseCursor? disabledMouseCursor,
     171             :     VisualDensity? visualDensity,
     172             :     MaterialTapTargetSize? tapTargetSize,
     173             :     Duration? animationDuration,
     174             :     bool? enableFeedback,
     175             :     AlignmentGeometry? alignment,
     176             :     InteractiveInkFeatureFactory? splashFactory,
     177             :   }) {
     178             :     final MaterialStateProperty<Color?>? foregroundColor =
     179             :         (onSurface == null && primary == null)
     180             :             ? null
     181           0 :             : _OutlinedButtonDefaultForeground(primary, onSurface);
     182             :     final MaterialStateProperty<Color?>? overlayColor =
     183           0 :         (primary == null) ? null : _OutlinedButtonDefaultOverlay(primary);
     184             :     final MaterialStateProperty<MouseCursor>? mouseCursor =
     185             :         (enabledMouseCursor == null && disabledMouseCursor == null)
     186             :             ? null
     187           0 :             : _OutlinedButtonDefaultMouseCursor(
     188             :                 enabledMouseCursor!, disabledMouseCursor!);
     189             : 
     190           0 :     return ButtonStyle(
     191           0 :       textStyle: ButtonStyleButton.allOrNull<TextStyle>(textStyle),
     192             :       foregroundColor: foregroundColor,
     193           0 :       backgroundColor: ButtonStyleButton.allOrNull<Color>(backgroundColor),
     194             :       overlayColor: overlayColor,
     195           0 :       shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor),
     196           0 :       elevation: ButtonStyleButton.allOrNull<double>(elevation),
     197           0 :       padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding),
     198           0 :       minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize),
     199           0 :       fixedSize: ButtonStyleButton.allOrNull<Size>(fixedSize),
     200             :       // TODO: add when becomes available in stable channel
     201             :       //maximumSize: ButtonStyleButton.allOrNull<Size>(maximumSize),
     202           0 :       side: ButtonStyleButton.allOrNull<BorderSide>(side),
     203           0 :       shape: ButtonStyleButton.allOrNull<OutlinedBorder>(shape),
     204             :       mouseCursor: mouseCursor,
     205             :       visualDensity: visualDensity,
     206             :       tapTargetSize: tapTargetSize,
     207             :       animationDuration: animationDuration,
     208             :       enableFeedback: enableFeedback,
     209             :       alignment: alignment,
     210             :       splashFactory: splashFactory,
     211             :     );
     212             :   }
     213             : 
     214             :   /// Defines the button's default appearance.
     215             :   ///
     216             :   /// With the exception of [ButtonStyle.side], which defines the
     217             :   /// outline, and [ButtonStyle.padding], the returned style is the
     218             :   /// same as for [MongolTextButton].
     219             :   ///
     220             :   /// The button [child]'s [MongolText] and [Icon] widgets are rendered with
     221             :   /// the [ButtonStyle]'s foreground color. The button's [InkWell] adds
     222             :   /// the style's overlay color when the button is focused, hovered
     223             :   /// or pressed. The button's background color becomes its [Material]
     224             :   /// color and is transparent by default.
     225             :   ///
     226             :   /// All of the ButtonStyle's defaults appear below. In this list
     227             :   /// "Theme.foo" is shorthand for `Theme.of(context).foo`. Color
     228             :   /// scheme values like "onSurface(0.38)" are shorthand for
     229             :   /// `onSurface.withOpacity(0.38)`. [MaterialStateProperty] valued
     230             :   /// properties that are not followed by a sublist have the same
     231             :   /// value for all states, otherwise the values are as specified for
     232             :   /// each state and "others" means all other states.
     233             :   ///
     234             :   /// The color of the [ButtonStyle.textStyle] is not used, the
     235             :   /// [ButtonStyle.foregroundColor] is used instead.
     236             :   ///
     237             :   /// * `textStyle` - Theme.textTheme.button
     238             :   /// * `backgroundColor` - transparent
     239             :   /// * `foregroundColor`
     240             :   ///   * disabled - Theme.colorScheme.onSurface(0.38)
     241             :   ///   * others - Theme.colorScheme.primary
     242             :   /// * `overlayColor`
     243             :   ///   * hovered - Theme.colorScheme.primary(0.04)
     244             :   ///   * focused or pressed - Theme.colorScheme.primary(0.12)
     245             :   /// * `shadowColor` - Theme.shadowColor
     246             :   /// * `elevation` - 0
     247             :   /// * `padding`
     248             :   ///   * `textScaleFactor <= 1` - vertical(16)
     249             :   ///   * `1 < textScaleFactor <= 2` - lerp(vertical(16), vertical(8))
     250             :   ///   * `2 < textScaleFactor <= 3` - lerp(vertical(8), vertical(4))
     251             :   ///   * `3 < textScaleFactor` - vertical(4)
     252             :   /// * `minimumSize` - Size(36, 64)
     253             :   /// * `fixedSize` - null
     254             :   /// * `maximumSize` - Size.infinite
     255             :   /// * `side` - BorderSide(width: 1, color: Theme.colorScheme.onSurface(0.12))
     256             :   /// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))
     257             :   /// * `mouseCursor`
     258             :   ///   * disabled - SystemMouseCursors.forbidden
     259             :   ///   * others - SystemMouseCursors.click
     260             :   /// * `visualDensity` - theme.visualDensity
     261             :   /// * `tapTargetSize` - theme.materialTapTargetSize
     262             :   /// * `animationDuration` - kThemeChangeDuration
     263             :   /// * `enableFeedback` - true
     264             :   /// * `alignment` - Alignment.center
     265             :   /// * `splashFactory` - InkRipple.splashFactory
     266           0 :   @override
     267             :   ButtonStyle defaultStyleOf(BuildContext context) {
     268           0 :     final ThemeData theme = Theme.of(context);
     269           0 :     final ColorScheme colorScheme = theme.colorScheme;
     270             : 
     271           0 :     final EdgeInsetsGeometry scaledPadding = ButtonStyleButton.scaledPadding(
     272             :       const EdgeInsets.symmetric(vertical: 16),
     273             :       const EdgeInsets.symmetric(vertical: 8),
     274             :       const EdgeInsets.symmetric(vertical: 4),
     275           0 :       MediaQuery.maybeOf(context)?.textScaleFactor ?? 1,
     276             :     );
     277             : 
     278           0 :     return styleFrom(
     279           0 :       primary: colorScheme.primary,
     280           0 :       onSurface: colorScheme.onSurface,
     281             :       backgroundColor: Colors.transparent,
     282           0 :       shadowColor: theme.shadowColor,
     283             :       elevation: 0,
     284           0 :       textStyle: theme.textTheme.button,
     285             :       padding: scaledPadding,
     286             :       minimumSize: const Size(36, 64),
     287             :       maximumSize: Size.infinite,
     288           0 :       side: BorderSide(
     289           0 :         color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
     290             :         width: 1,
     291             :       ),
     292             :       shape: const RoundedRectangleBorder(
     293             :           borderRadius: BorderRadius.all(Radius.circular(4))),
     294             :       enabledMouseCursor: SystemMouseCursors.click,
     295             :       disabledMouseCursor: SystemMouseCursors.forbidden,
     296           0 :       visualDensity: theme.visualDensity,
     297           0 :       tapTargetSize: theme.materialTapTargetSize,
     298             :       animationDuration: kThemeChangeDuration,
     299             :       enableFeedback: true,
     300             :       alignment: Alignment.center,
     301             :       splashFactory: InkRipple.splashFactory,
     302             :     );
     303             :   }
     304             : 
     305           0 :   @override
     306             :   ButtonStyle? themeStyleOf(BuildContext context) {
     307           0 :     return OutlinedButtonTheme.of(context).style;
     308             :   }
     309             : }
     310             : 
     311             : @immutable
     312             : class _OutlinedButtonDefaultForeground extends MaterialStateProperty<Color?>
     313             :     with Diagnosticable {
     314           0 :   _OutlinedButtonDefaultForeground(this.primary, this.onSurface);
     315             : 
     316             :   final Color? primary;
     317             :   final Color? onSurface;
     318             : 
     319           0 :   @override
     320             :   Color? resolve(Set<MaterialState> states) {
     321           0 :     if (states.contains(MaterialState.disabled)) {
     322           0 :       return onSurface?.withOpacity(0.38);
     323             :     }
     324           0 :     return primary;
     325             :   }
     326             : }
     327             : 
     328             : @immutable
     329             : class _OutlinedButtonDefaultOverlay extends MaterialStateProperty<Color?>
     330             :     with Diagnosticable {
     331           0 :   _OutlinedButtonDefaultOverlay(this.primary);
     332             : 
     333             :   final Color primary;
     334             : 
     335           0 :   @override
     336             :   Color? resolve(Set<MaterialState> states) {
     337           0 :     if (states.contains(MaterialState.hovered)) {
     338           0 :       return primary.withOpacity(0.04);
     339             :     }
     340           0 :     if (states.contains(MaterialState.focused) ||
     341           0 :         states.contains(MaterialState.pressed)) {
     342           0 :       return primary.withOpacity(0.12);
     343             :     }
     344             :     return null;
     345             :   }
     346             : }
     347             : 
     348             : @immutable
     349             : class _OutlinedButtonDefaultMouseCursor
     350             :     extends MaterialStateProperty<MouseCursor> with Diagnosticable {
     351           0 :   _OutlinedButtonDefaultMouseCursor(this.enabledCursor, this.disabledCursor);
     352             : 
     353             :   final MouseCursor enabledCursor;
     354             :   final MouseCursor disabledCursor;
     355             : 
     356           0 :   @override
     357             :   MouseCursor resolve(Set<MaterialState> states) {
     358           0 :     if (states.contains(MaterialState.disabled)) return disabledCursor;
     359           0 :     return enabledCursor;
     360             :   }
     361             : }
     362             : 
     363             : class _MongolOutlinedButtonWithIcon extends MongolOutlinedButton {
     364           0 :   _MongolOutlinedButtonWithIcon({
     365             :     Key? key,
     366             :     required VoidCallback? onPressed,
     367             :     VoidCallback? onLongPress,
     368             :     ButtonStyle? style,
     369             :     FocusNode? focusNode,
     370             :     bool? autofocus,
     371             :     Clip? clipBehavior,
     372             :     required Widget icon,
     373             :     required Widget label,
     374           0 :   }) : super(
     375             :           key: key,
     376             :           onPressed: onPressed,
     377             :           onLongPress: onLongPress,
     378             :           style: style,
     379             :           focusNode: focusNode,
     380             :           autofocus: autofocus ?? false,
     381             :           clipBehavior: clipBehavior ?? Clip.none,
     382           0 :           child: _MongolOutlinedButtonWithIconChild(icon: icon, label: label),
     383             :         );
     384             : }
     385             : 
     386             : class _MongolOutlinedButtonWithIconChild extends StatelessWidget {
     387           0 :   const _MongolOutlinedButtonWithIconChild({
     388             :     Key? key,
     389             :     required this.label,
     390             :     required this.icon,
     391           0 :   }) : super(key: key);
     392             : 
     393             :   final Widget label;
     394             :   final Widget icon;
     395             : 
     396           0 :   @override
     397             :   Widget build(BuildContext context) {
     398           0 :     final double scale = MediaQuery.maybeOf(context)?.textScaleFactor ?? 1;
     399             :     final double gap =
     400           0 :         scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!;
     401           0 :     return Column(
     402             :       mainAxisSize: MainAxisSize.min,
     403           0 :       children: <Widget>[icon, SizedBox(height: gap), Flexible(child: label)],
     404             :     );
     405             :   }
     406             : }

Generated by: LCOV version 1.15