878 lines
30 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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:ui' show lerpDouble;
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'button_style.dart';
import 'button_style_button.dart';
import 'color_scheme.dart';
import 'colors.dart';
import 'constants.dart';
import 'filled_button_theme.dart';
import 'ink_well.dart';
import 'material_state.dart';
import 'theme.dart';
import 'theme_data.dart';
enum _FilledButtonVariant { filled, tonal }
/// A Material Design filled button.
///
/// Filled buttons have the most visual impact after the [FloatingActionButton],
/// and should be used for important, final actions that complete a flow,
/// like **Save**, **Join now**, or **Confirm**.
///
/// A filled button is a label [child] displayed on a [Material]
/// widget. The label's [Text] and [Icon] widgets are displayed in
/// [style]'s [ButtonStyle.foregroundColor] and the button's filled
/// background is the [ButtonStyle.backgroundColor].
///
/// The filled button's default style is defined by
/// [defaultStyleOf]. The style of this filled button can be
/// overridden with its [style] parameter. The style of all filled
/// buttons in a subtree can be overridden with the
/// [FilledButtonTheme], and the style of all of the filled
/// buttons in an app can be overridden with the [Theme]'s
/// [ThemeData.filledButtonTheme] property.
///
/// The static [styleFrom] method is a convenient way to create a
/// filled button [ButtonStyle] from simple values.
///
/// If [onPressed] and [onLongPress] callbacks are null, then the
/// button will be disabled.
///
/// To create a 'filled tonal' button, use [FilledButton.tonal].
///
/// {@tool dartpad}
/// This sample produces enabled and disabled filled and filled tonal
/// buttons.
///
/// ** See code in examples/api/lib/material/filled_button/filled_button.0.dart **
/// {@end-tool}
///
/// See also:
///
/// * [ElevatedButton], a filled button whose material elevates when pressed.
/// * [OutlinedButton], a button with an outlined border and no fill color.
/// * [TextButton], a button with no outline or fill color.
/// * <https://material.io/design/components/buttons.html>
/// * <https://m3.material.io/components/buttons>
class FilledButton extends ButtonStyleButton {
/// Create a FilledButton.
const FilledButton({
super.key,
required super.onPressed,
super.onLongPress,
super.onHover,
super.onFocusChange,
super.style,
super.focusNode,
super.autofocus = false,
super.clipBehavior = Clip.none,
super.statesController,
required super.child,
super.iconAlignment,
}) : _variant = _FilledButtonVariant.filled;
/// Create a filled button from [icon] and [label].
///
/// The icon and label are arranged in a row with padding at the start and end
/// and a gap between them.
///
/// If [icon] is null, will create a [FilledButton] instead.
///
/// {@macro flutter.material.ButtonStyleButton.iconAlignment}
///
factory FilledButton.icon({
Key? key,
required VoidCallback? onPressed,
VoidCallback? onLongPress,
ValueChanged<bool>? onHover,
ValueChanged<bool>? onFocusChange,
ButtonStyle? style,
FocusNode? focusNode,
bool? autofocus,
Clip? clipBehavior,
MaterialStatesController? statesController,
Widget? icon,
required Widget label,
IconAlignment iconAlignment = IconAlignment.start,
}) {
if (icon == null) {
return FilledButton(
key: key,
onPressed: onPressed,
onLongPress: onLongPress,
onHover: onHover,
onFocusChange: onFocusChange,
style: style,
focusNode: focusNode,
autofocus: autofocus ?? false,
clipBehavior: clipBehavior ?? Clip.none,
statesController: statesController,
child: label,
);
}
return _FilledButtonWithIcon(
key: key,
onPressed: onPressed,
onLongPress: onLongPress,
onHover: onHover,
onFocusChange: onFocusChange,
style: style,
focusNode: focusNode,
autofocus: autofocus ?? false,
clipBehavior: clipBehavior ?? Clip.none,
statesController: statesController,
icon: icon,
label: label,
iconAlignment: iconAlignment,
);
}
/// Create a tonal variant of FilledButton.
///
/// A filled tonal button is an alternative middle ground between
/// [FilledButton] and [OutlinedButton]. Theyre useful in contexts where
/// a lower-priority button requires slightly more emphasis than an
/// outline would give, such as "Next" in an onboarding flow.
const FilledButton.tonal({
super.key,
required super.onPressed,
super.onLongPress,
super.onHover,
super.onFocusChange,
super.style,
super.focusNode,
super.autofocus = false,
super.clipBehavior = Clip.none,
super.statesController,
required super.child,
}) : _variant = _FilledButtonVariant.tonal;
/// Create a filled tonal button from [icon] and [label].
///
/// The [icon] and [label] are arranged in a row with padding at the start and
/// end and a gap between them.
///
/// If [icon] is null, will create a [FilledButton.tonal] instead.
factory FilledButton.tonalIcon({
Key? key,
required VoidCallback? onPressed,
VoidCallback? onLongPress,
ValueChanged<bool>? onHover,
ValueChanged<bool>? onFocusChange,
ButtonStyle? style,
FocusNode? focusNode,
bool? autofocus,
Clip? clipBehavior,
MaterialStatesController? statesController,
Widget? icon,
required Widget label,
IconAlignment iconAlignment = IconAlignment.start,
}) {
if (icon == null) {
return FilledButton.tonal(
key: key,
onPressed: onPressed,
onLongPress: onLongPress,
onHover: onHover,
onFocusChange: onFocusChange,
style: style,
focusNode: focusNode,
autofocus: autofocus ?? false,
clipBehavior: clipBehavior ?? Clip.none,
statesController: statesController,
child: label,
);
}
return _FilledButtonWithIcon.tonal(
key: key,
onPressed: onPressed,
onLongPress: onLongPress,
onHover: onHover,
onFocusChange: onFocusChange,
style: style,
focusNode: focusNode,
autofocus: autofocus,
clipBehavior: clipBehavior,
statesController: statesController,
icon: icon,
label: label,
iconAlignment: iconAlignment,
);
}
/// A static convenience method that constructs a filled button
/// [ButtonStyle] given simple values.
///
/// The [foregroundColor] and [disabledForegroundColor] colors are used
/// to create a [MaterialStateProperty] [ButtonStyle.foregroundColor], and
/// a derived [ButtonStyle.overlayColor] if [overlayColor] isn't specified.
///
/// If [overlayColor] is specified and its value is [Colors.transparent]
/// then the pressed/focused/hovered highlights are effectively defeated.
/// Otherwise a [MaterialStateProperty] with the same opacities as the
/// default is created.
///
/// Similarly, the [enabledMouseCursor] and [disabledMouseCursor]
/// parameters are used to construct [ButtonStyle.mouseCursor].
///
/// The button's elevations are defined relative to the [elevation]
/// parameter. The disabled elevation is the same as the parameter
/// value, [elevation] + 2 is used when the button is hovered
/// or focused, and elevation + 6 is used when the button is pressed.
///
/// All of the other parameters are either used directly or used to
/// create a [MaterialStateProperty] with a single value for all
/// states.
///
/// All parameters default to null, by default this method returns
/// a [ButtonStyle] that doesn't override anything.
///
/// For example, to override the default text and icon colors for a
/// [FilledButton], as well as its overlay color, with all of the
/// standard opacity adjustments for the pressed, focused, and
/// hovered states, one could write:
///
/// ```dart
/// FilledButton(
/// style: FilledButton.styleFrom(foregroundColor: Colors.green),
/// onPressed: () {},
/// child: const Text('Filled button'),
/// );
/// ```
///
/// or for a Filled tonal variant:
/// ```dart
/// FilledButton.tonal(
/// style: FilledButton.styleFrom(foregroundColor: Colors.green),
/// onPressed: () {},
/// child: const Text('Filled tonal button'),
/// );
/// ```
static ButtonStyle styleFrom({
Color? foregroundColor,
Color? backgroundColor,
Color? disabledForegroundColor,
Color? disabledBackgroundColor,
Color? shadowColor,
Color? surfaceTintColor,
Color? iconColor,
Color? disabledIconColor,
Color? overlayColor,
double? elevation,
TextStyle? textStyle,
EdgeInsetsGeometry? padding,
Size? minimumSize,
Size? fixedSize,
Size? maximumSize,
BorderSide? side,
OutlinedBorder? shape,
MouseCursor? enabledMouseCursor,
MouseCursor? disabledMouseCursor,
VisualDensity? visualDensity,
MaterialTapTargetSize? tapTargetSize,
Duration? animationDuration,
bool? enableFeedback,
AlignmentGeometry? alignment,
InteractiveInkFeatureFactory? splashFactory,
ButtonLayerBuilder? backgroundBuilder,
ButtonLayerBuilder? foregroundBuilder,
}) {
final MaterialStateProperty<Color?>? foregroundColorProp = switch ((foregroundColor, disabledForegroundColor)) {
(null, null) => null,
(_, _) => _FilledButtonDefaultColor(foregroundColor, disabledForegroundColor),
};
final MaterialStateProperty<Color?>? backgroundColorProp = switch ((backgroundColor, disabledBackgroundColor)) {
(null, null) => null,
(_, _) => _FilledButtonDefaultColor(backgroundColor, disabledBackgroundColor),
};
final MaterialStateProperty<Color?>? iconColorProp = switch ((iconColor, disabledIconColor)) {
(null, null) => null,
(_, _) => _FilledButtonDefaultColor(iconColor, disabledIconColor),
};
final MaterialStateProperty<Color?>? overlayColorProp = switch ((foregroundColor, overlayColor)) {
(null, null) => null,
(_, final Color overlayColor) when overlayColor.value == 0 => const MaterialStatePropertyAll<Color?>(Colors.transparent),
(_, _) => _FilledButtonDefaultOverlay((overlayColor ?? foregroundColor)!),
};
final MaterialStateProperty<MouseCursor?> mouseCursor = _FilledButtonDefaultMouseCursor(enabledMouseCursor, disabledMouseCursor);
return ButtonStyle(
textStyle: MaterialStatePropertyAll<TextStyle?>(textStyle),
backgroundColor: backgroundColorProp,
foregroundColor: foregroundColorProp,
overlayColor: overlayColorProp,
shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor),
surfaceTintColor: ButtonStyleButton.allOrNull<Color>(surfaceTintColor),
iconColor: iconColorProp,
elevation: ButtonStyleButton.allOrNull(elevation),
padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding),
minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize),
fixedSize: ButtonStyleButton.allOrNull<Size>(fixedSize),
maximumSize: ButtonStyleButton.allOrNull<Size>(maximumSize),
side: ButtonStyleButton.allOrNull<BorderSide>(side),
shape: ButtonStyleButton.allOrNull<OutlinedBorder>(shape),
mouseCursor: mouseCursor,
visualDensity: visualDensity,
tapTargetSize: tapTargetSize,
animationDuration: animationDuration,
enableFeedback: enableFeedback,
alignment: alignment,
splashFactory: splashFactory,
backgroundBuilder: backgroundBuilder,
foregroundBuilder: foregroundBuilder,
);
}
final _FilledButtonVariant _variant;
/// Defines the button's default appearance.
///
/// The button [child]'s [Text] and [Icon] widgets are rendered with
/// the [ButtonStyle]'s foreground color. The button's [InkWell] adds
/// the style's overlay color when the button is focused, hovered
/// or pressed. The button's background color becomes its [Material]
/// color.
///
/// All of the ButtonStyle's defaults appear below. In this list
/// "Theme.foo" is shorthand for `Theme.of(context).foo`. Color
/// scheme values like "onSurface(0.38)" are shorthand for
/// `onSurface.withOpacity(0.38)`. [MaterialStateProperty] valued
/// properties that are not followed by a sublist have the same
/// value for all states, otherwise the values are as specified for
/// each state, and "others" means all other states.
///
/// {@macro flutter.material.elevated_button.default_font_size}
///
/// The color of the [ButtonStyle.textStyle] is not used, the
/// [ButtonStyle.foregroundColor] color is used instead.
///
/// * `textStyle` - Theme.textTheme.labelLarge
/// * `backgroundColor`
/// * disabled - Theme.colorScheme.onSurface(0.12)
/// * others - Theme.colorScheme.secondaryContainer
/// * `foregroundColor`
/// * disabled - Theme.colorScheme.onSurface(0.38)
/// * others - Theme.colorScheme.onSecondaryContainer
/// * `overlayColor`
/// * hovered - Theme.colorScheme.onSecondaryContainer(0.08)
/// * focused or pressed - Theme.colorScheme.onSecondaryContainer(0.12)
/// * `shadowColor` - Theme.colorScheme.shadow
/// * `surfaceTintColor` - null
/// * `elevation`
/// * disabled - 0
/// * default - 0
/// * hovered - 1
/// * focused or pressed - 0
/// * `padding`
/// * `default font size <= 14` - horizontal(16)
/// * `14 < default font size <= 28` - lerp(horizontal(16), horizontal(8))
/// * `28 < default font size <= 36` - lerp(horizontal(8), horizontal(4))
/// * `36 < default font size` - horizontal(4)
/// * `minimumSize` - Size(64, 40)
/// * `fixedSize` - null
/// * `maximumSize` - Size.infinite
/// * `side` - null
/// * `shape` - StadiumBorder()
/// * `mouseCursor`
/// * disabled - SystemMouseCursors.basic
/// * others - SystemMouseCursors.click
/// * `visualDensity` - Theme.visualDensity
/// * `tapTargetSize` - Theme.materialTapTargetSize
/// * `animationDuration` - kThemeChangeDuration
/// * `enableFeedback` - true
/// * `alignment` - Alignment.center
/// * `splashFactory` - Theme.splashFactory
///
/// The default padding values for the [FilledButton.icon] factory are slightly different:
///
/// * `padding`
/// * `default font size <= 14` - start(12) end(16)
/// * `14 < default font size <= 28` - lerp(start(12) end(16), horizontal(8))
/// * `28 < default font size <= 36` - lerp(horizontal(8), horizontal(4))
/// * `36 < default font size` - horizontal(4)
///
/// The default value for `side`, which defines the appearance of the button's
/// outline, is null. That means that the outline is defined by the button
/// shape's [OutlinedBorder.side]. Typically the default value of an
/// [OutlinedBorder]'s side is [BorderSide.none], so an outline is not drawn.
///
/// ## Material 3 defaults
///
/// If [ThemeData.useMaterial3] is set to true the following defaults will
/// be used:
///
/// * `textStyle` - Theme.textTheme.labelLarge
/// * `backgroundColor`
/// * disabled - Theme.colorScheme.onSurface(0.12)
/// * others - Theme.colorScheme.secondaryContainer
/// * `foregroundColor`
/// * disabled - Theme.colorScheme.onSurface(0.38)
/// * others - Theme.colorScheme.onSecondaryContainer
/// * `overlayColor`
/// * hovered - Theme.colorScheme.onSecondaryContainer(0.08)
/// * focused or pressed - Theme.colorScheme.onSecondaryContainer(0.1)
/// * `shadowColor` - Theme.colorScheme.shadow
/// * `surfaceTintColor` - Colors.transparent
/// * `elevation`
/// * disabled - 0
/// * default - 1
/// * hovered - 3
/// * focused or pressed - 1
/// * `padding`
/// * `default font size <= 14` - horizontal(24)
/// * `14 < default font size <= 28` - lerp(horizontal(24), horizontal(12))
/// * `28 < default font size <= 36` - lerp(horizontal(12), horizontal(6))
/// * `36 < default font size` - horizontal(6)
/// * `minimumSize` - Size(64, 40)
/// * `fixedSize` - null
/// * `maximumSize` - Size.infinite
/// * `side` - null
/// * `shape` - StadiumBorder()
/// * `mouseCursor`
/// * disabled - SystemMouseCursors.basic
/// * others - SystemMouseCursors.click
/// * `visualDensity` - Theme.visualDensity
/// * `tapTargetSize` - Theme.materialTapTargetSize
/// * `animationDuration` - kThemeChangeDuration
/// * `enableFeedback` - true
/// * `alignment` - Alignment.center
/// * `splashFactory` - Theme.splashFactory
///
/// For the [FilledButton.icon] factory, the start (generally the left) value of
/// [padding] is reduced from 24 to 16.
@override
ButtonStyle defaultStyleOf(BuildContext context) {
return switch (_variant) {
_FilledButtonVariant.filled => _FilledButtonDefaultsM3(context),
_FilledButtonVariant.tonal => _FilledTonalButtonDefaultsM3(context),
};
}
/// Returns the [FilledButtonThemeData.style] of the closest
/// [FilledButtonTheme] ancestor.
@override
ButtonStyle? themeStyleOf(BuildContext context) {
return FilledButtonTheme.of(context).style;
}
}
EdgeInsetsGeometry _scaledPadding(BuildContext context) {
final ThemeData theme = Theme.of(context);
final double defaultFontSize = theme.textTheme.labelLarge?.fontSize ?? 14.0;
final double effectiveTextScale = MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0;
final double padding1x = theme.useMaterial3 ? 24.0 : 16.0;
return ButtonStyleButton.scaledPadding(
EdgeInsets.symmetric(horizontal: padding1x),
EdgeInsets.symmetric(horizontal: padding1x / 2),
EdgeInsets.symmetric(horizontal: padding1x / 2 / 2),
effectiveTextScale,
);
}
@immutable
class _FilledButtonDefaultColor extends MaterialStateProperty<Color?> with Diagnosticable {
_FilledButtonDefaultColor(this.color, this.disabled);
final Color? color;
final Color? disabled;
@override
Color? resolve(Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabled;
}
return color;
}
}
@immutable
class _FilledButtonDefaultOverlay extends MaterialStateProperty<Color?> with Diagnosticable {
_FilledButtonDefaultOverlay(this.overlay);
final Color overlay;
@override
Color? resolve(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return overlay.withOpacity(0.1);
}
if (states.contains(MaterialState.hovered)) {
return overlay.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return overlay.withOpacity(0.1);
}
return null;
}
}
@immutable
class _FilledButtonDefaultMouseCursor extends MaterialStateProperty<MouseCursor?> with Diagnosticable {
_FilledButtonDefaultMouseCursor(this.enabledCursor, this.disabledCursor);
final MouseCursor? enabledCursor;
final MouseCursor? disabledCursor;
@override
MouseCursor? resolve(Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledCursor;
}
return enabledCursor;
}
}
class _FilledButtonWithIcon extends FilledButton {
_FilledButtonWithIcon({
super.key,
required super.onPressed,
super.onLongPress,
super.onHover,
super.onFocusChange,
super.style,
super.focusNode,
bool? autofocus,
super.clipBehavior,
super.statesController,
required Widget icon,
required Widget label,
super.iconAlignment,
}) : super(
autofocus: autofocus ?? false,
child: _FilledButtonWithIconChild(
icon: icon,
label: label,
buttonStyle: style,
iconAlignment: iconAlignment,
),
);
_FilledButtonWithIcon.tonal({
super.key,
required super.onPressed,
super.onLongPress,
super.onHover,
super.onFocusChange,
super.style,
super.focusNode,
bool? autofocus,
super.clipBehavior,
super.statesController,
required Widget icon,
required Widget label,
required IconAlignment iconAlignment,
}) : super.tonal(
autofocus: autofocus ?? false,
child: _FilledButtonWithIconChild(
icon: icon,
label: label,
buttonStyle: style,
iconAlignment: iconAlignment,
),
);
@override
ButtonStyle defaultStyleOf(BuildContext context) {
final bool useMaterial3 = Theme.of(context).useMaterial3;
final ButtonStyle buttonStyle = super.defaultStyleOf(context);
final double defaultFontSize = buttonStyle.textStyle?.resolve(const <MaterialState>{})?.fontSize ?? 14.0;
final double effectiveTextScale = MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0;
final EdgeInsetsGeometry scaledPadding = useMaterial3
? ButtonStyleButton.scaledPadding(
const EdgeInsetsDirectional.fromSTEB(16, 0, 24, 0),
const EdgeInsetsDirectional.fromSTEB(8, 0, 12, 0),
const EdgeInsetsDirectional.fromSTEB(4, 0, 6, 0),
effectiveTextScale,
) : ButtonStyleButton.scaledPadding(
const EdgeInsetsDirectional.fromSTEB(12, 0, 16, 0),
const EdgeInsets.symmetric(horizontal: 8),
const EdgeInsetsDirectional.fromSTEB(8, 0, 4, 0),
effectiveTextScale,
);
return buttonStyle.copyWith(
padding: MaterialStatePropertyAll<EdgeInsetsGeometry>(scaledPadding),
);
}
}
class _FilledButtonWithIconChild extends StatelessWidget {
const _FilledButtonWithIconChild({
required this.label,
required this.icon,
required this.buttonStyle,
required this.iconAlignment,
});
final Widget label;
final Widget icon;
final ButtonStyle? buttonStyle;
final IconAlignment iconAlignment;
@override
Widget build(BuildContext context) {
final double defaultFontSize = buttonStyle?.textStyle?.resolve(const <MaterialState>{})?.fontSize ?? 14.0;
final double scale = clampDouble(MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0, 1.0, 2.0) - 1.0;
// Adjust the gap based on the text scale factor. Start at 8, and lerp
// to 4 based on how large the text is.
final double gap = lerpDouble(8, 4, scale)!;
return Row(
mainAxisSize: MainAxisSize.min,
children: iconAlignment == IconAlignment.start
? <Widget>[icon, SizedBox(width: gap), Flexible(child: label)]
: <Widget>[Flexible(child: label), SizedBox(width: gap), icon],
);
}
}
// BEGIN GENERATED TOKEN PROPERTIES - FilledButton
// Do not edit by hand. The code between the "BEGIN GENERATED" and
// "END GENERATED" comments are generated from data in the Material
// Design token database by the script:
// dev/tools/gen_defaults/bin/gen_defaults.dart.
class _FilledButtonDefaultsM3 extends ButtonStyle {
_FilledButtonDefaultsM3(this.context)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
final BuildContext context;
late final ColorScheme _colors = Theme.of(context).colorScheme;
@override
MaterialStateProperty<TextStyle?> get textStyle =>
MaterialStatePropertyAll<TextStyle?>(Theme.of(context).textTheme.labelLarge);
@override
MaterialStateProperty<Color?>? get backgroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.12);
}
return _colors.primary;
});
@override
MaterialStateProperty<Color?>? get foregroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.38);
}
return _colors.onPrimary;
});
@override
MaterialStateProperty<Color?>? get overlayColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return _colors.onPrimary.withOpacity(0.1);
}
if (states.contains(MaterialState.hovered)) {
return _colors.onPrimary.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onPrimary.withOpacity(0.1);
}
return null;
});
@override
MaterialStateProperty<Color>? get shadowColor =>
MaterialStatePropertyAll<Color>(_colors.shadow);
@override
MaterialStateProperty<Color>? get surfaceTintColor =>
const MaterialStatePropertyAll<Color>(Colors.transparent);
@override
MaterialStateProperty<double>? get elevation =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return 0.0;
}
if (states.contains(MaterialState.pressed)) {
return 0.0;
}
if (states.contains(MaterialState.hovered)) {
return 1.0;
}
if (states.contains(MaterialState.focused)) {
return 0.0;
}
return 0.0;
});
@override
MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
MaterialStatePropertyAll<EdgeInsetsGeometry>(_scaledPadding(context));
@override
MaterialStateProperty<Size>? get minimumSize =>
const MaterialStatePropertyAll<Size>(Size(64.0, 40.0));
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize =>
const MaterialStatePropertyAll<Size>(Size.infinite);
// No default side
@override
MaterialStateProperty<OutlinedBorder>? get shape =>
const MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder());
@override
MaterialStateProperty<MouseCursor?>? get mouseCursor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
});
@override
VisualDensity? get visualDensity => Theme.of(context).visualDensity;
@override
MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize;
@override
InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory;
}
// END GENERATED TOKEN PROPERTIES - FilledButton
// BEGIN GENERATED TOKEN PROPERTIES - FilledTonalButton
// Do not edit by hand. The code between the "BEGIN GENERATED" and
// "END GENERATED" comments are generated from data in the Material
// Design token database by the script:
// dev/tools/gen_defaults/bin/gen_defaults.dart.
class _FilledTonalButtonDefaultsM3 extends ButtonStyle {
_FilledTonalButtonDefaultsM3(this.context)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
final BuildContext context;
late final ColorScheme _colors = Theme.of(context).colorScheme;
@override
MaterialStateProperty<TextStyle?> get textStyle =>
MaterialStatePropertyAll<TextStyle?>(Theme.of(context).textTheme.labelLarge);
@override
MaterialStateProperty<Color?>? get backgroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.12);
}
return _colors.secondaryContainer;
});
@override
MaterialStateProperty<Color?>? get foregroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.38);
}
return _colors.onSecondaryContainer;
});
@override
MaterialStateProperty<Color?>? get overlayColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return _colors.onSecondaryContainer.withOpacity(0.1);
}
if (states.contains(MaterialState.hovered)) {
return _colors.onSecondaryContainer.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onSecondaryContainer.withOpacity(0.1);
}
return null;
});
@override
MaterialStateProperty<Color>? get shadowColor =>
MaterialStatePropertyAll<Color>(_colors.shadow);
@override
MaterialStateProperty<Color>? get surfaceTintColor =>
const MaterialStatePropertyAll<Color>(Colors.transparent);
@override
MaterialStateProperty<double>? get elevation =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return 0.0;
}
if (states.contains(MaterialState.pressed)) {
return 0.0;
}
if (states.contains(MaterialState.hovered)) {
return 1.0;
}
if (states.contains(MaterialState.focused)) {
return 0.0;
}
return 0.0;
});
@override
MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
MaterialStatePropertyAll<EdgeInsetsGeometry>(_scaledPadding(context));
@override
MaterialStateProperty<Size>? get minimumSize =>
const MaterialStatePropertyAll<Size>(Size(64.0, 40.0));
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize =>
const MaterialStatePropertyAll<Size>(Size.infinite);
// No default side
@override
MaterialStateProperty<OutlinedBorder>? get shape =>
const MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder());
@override
MaterialStateProperty<MouseCursor?>? get mouseCursor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
});
@override
VisualDensity? get visualDensity => Theme.of(context).visualDensity;
@override
MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize;
@override
InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory;
}
// END GENERATED TOKEN PROPERTIES - FilledTonalButton