Migrate IconButton to Material 3 - Part 1 (#105176)

* Added standard IconButton for M3 with new ButtonStyle field

* Added IconButton examples for standard, filled, filled_tonal, and outlined types

Co-authored-by: Qun Cheng <quncheng@google.com>
This commit is contained in:
Qun Cheng 2022-06-07 12:39:22 -07:00 committed by GitHub
parent 1718519188
commit 66a84d1fed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 1305 additions and 191 deletions

View file

@ -22,6 +22,7 @@ import 'package:gen_defaults/button_template.dart';
import 'package:gen_defaults/card_template.dart';
import 'package:gen_defaults/dialog_template.dart';
import 'package:gen_defaults/fab_template.dart';
import 'package:gen_defaults/icon_button_template.dart';
import 'package:gen_defaults/navigation_bar_template.dart';
import 'package:gen_defaults/navigation_rail_template.dart';
import 'package:gen_defaults/surface_tint.dart';
@ -55,6 +56,9 @@ Future<void> main(List<String> args) async {
'fab_large_primary.json',
'fab_primary.json',
'fab_small_primary.json',
'icon_button.json',
'icon_button_filled.json',
'icon_button_filled_tonal.json',
'motion.json',
'navigation_bar.json',
'navigation_rail.json',
@ -86,6 +90,7 @@ Future<void> main(List<String> args) async {
CardTemplate('$materialLib/card.dart', tokens).updateFile();
DialogTemplate('$materialLib/dialog.dart', tokens).updateFile();
FABTemplate('$materialLib/floating_action_button.dart', tokens).updateFile();
IconButtonTemplate('$materialLib/icon_button.dart', tokens).updateFile();
NavigationBarTemplate('$materialLib/navigation_bar.dart', tokens).updateFile();
NavigationRailTemplate('$materialLib/navigation_rail.dart', tokens).updateFile();
SurfaceTintTemplate('$materialLib/elevation_overlay.dart', tokens).updateFile();

View file

@ -0,0 +1,99 @@
// 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 'template.dart';
class IconButtonTemplate extends TokenTemplate {
const IconButtonTemplate(super.fileName, super.tokens)
: super(colorSchemePrefix: '_colors.',
);
@override
String generate() => '''
// Generated version ${tokens["version"]}
class _TokenDefaultsM3 extends ButtonStyle {
_TokenDefaultsM3(this.context)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
final BuildContext context;
late final ColorScheme _colors = Theme.of(context).colorScheme;
// No default text style
@override
MaterialStateProperty<Color?>? get backgroundColor =>
ButtonStyleButton.allOrNull<Color>(Colors.transparent);
@override
MaterialStateProperty<Color?>? get foregroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled))
return ${componentColor('md.comp.icon-button.disabled.icon')};
return ${componentColor('md.comp.icon-button.unselected.icon')};
});
@override
MaterialStateProperty<Color?>? get overlayColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered))
return ${componentColor('md.comp.icon-button.unselected.hover.state-layer')};
if (states.contains(MaterialState.focused))
return ${componentColor('md.comp.icon-button.unselected.focus.state-layer')};
if (states.contains(MaterialState.pressed))
return ${componentColor('md.comp.icon-button.unselected.pressed.state-layer')};
return null;
});
// No default shadow color
// No default surface tint color
@override
MaterialStateProperty<double>? get elevation =>
ButtonStyleButton.allOrNull<double>(0.0);
@override
MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(const EdgeInsets.all(8.0));
@override
MaterialStateProperty<Size>? get minimumSize =>
ButtonStyleButton.allOrNull<Size>(const Size(${tokens["md.comp.icon-button.state-layer.size"]}, ${tokens["md.comp.icon-button.state-layer.size"]}));
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize =>
ButtonStyleButton.allOrNull<Size>(Size.infinite);
// No default side
@override
MaterialStateProperty<OutlinedBorder>? get shape =>
ButtonStyleButton.allOrNull<OutlinedBorder>(${shape("md.comp.icon-button.state-layer")});
@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;
}
''';
}

View file

@ -0,0 +1,118 @@
// 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.
// Flutter code sample for IconButton
import 'package:flutter/material.dart';
void main() {
runApp(const IconButtonApp());
}
class IconButtonApp extends StatelessWidget {
const IconButtonApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true),
title: 'Icon Button Types',
home: const Scaffold(
body: ButtonTypesExample(),
),
);
}
}
class ButtonTypesExample extends StatelessWidget {
const ButtonTypesExample({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: Row(
children: const <Widget>[
Spacer(),
ButtonTypesGroup(enabled: true),
ButtonTypesGroup(enabled: false),
Spacer(),
],
),
);
}
}
class ButtonTypesGroup extends StatelessWidget {
const ButtonTypesGroup({ super.key, required this.enabled });
final bool enabled;
@override
Widget build(BuildContext context) {
final VoidCallback? onPressed = enabled ? () {} : null;
final ColorScheme colors = Theme.of(context).colorScheme;
return Padding(
padding: const EdgeInsets.all(4.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(icon: const Icon(Icons.filter_drama), onPressed: onPressed),
// Use a standard IconButton with specific style to implement the
// 'Filled' type.
IconButton(
icon: const Icon(Icons.filter_drama),
onPressed: onPressed,
style: IconButton.styleFrom(
foregroundColor: colors.onPrimary,
backgroundColor: colors.primary,
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
hoverColor: colors.onPrimary.withOpacity(0.08),
focusColor: colors.onPrimary.withOpacity(0.12),
highlightColor: colors.onPrimary.withOpacity(0.12),
)
),
// Use a standard IconButton with specific style to implement the
// 'Filled Tonal' type.
IconButton(
icon: const Icon(Icons.filter_drama),
onPressed: onPressed,
style: IconButton.styleFrom(
foregroundColor: colors.onSecondaryContainer,
backgroundColor: colors.secondaryContainer,
disabledBackgroundColor: colors.onSurface.withOpacity(0.12),
hoverColor: colors.onSecondaryContainer.withOpacity(0.08),
focusColor: colors.onSecondaryContainer.withOpacity(0.12),
highlightColor: colors.onSecondaryContainer.withOpacity(0.12),
),
),
// Use a standard IconButton with specific style to implement the
// 'Outlined' type.
IconButton(
icon: const Icon(Icons.filter_drama),
onPressed: onPressed,
style: IconButton.styleFrom(
focusColor: colors.onSurfaceVariant.withOpacity(0.12),
highlightColor: colors.onSurface.withOpacity(0.12),
side: onPressed == null
? BorderSide(color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12))
: BorderSide(color: colors.outline),
).copyWith(
foregroundColor: MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return colors.onSurface;
}
return null;
}),
),
),
],
),
);
}
}

View file

@ -8,11 +8,16 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.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 'debug.dart';
import 'icons.dart';
import 'ink_well.dart';
import 'material.dart';
import 'material_state.dart';
import 'theme.dart';
import 'theme_data.dart';
import 'tooltip.dart';
@ -92,6 +97,17 @@ const double _kMinButtonSize = kMinInteractiveDimension;
/// ** See code in examples/api/lib/material/icon_button/icon_button.1.dart **
/// {@end-tool}
///
/// Material Design 3 introduced new types (standard and contained) of [IconButton]s.
/// The default [IconButton] is the standard type, and contained icon buttons can be produced
/// by configuring the [IconButton] widget's properties.
///
/// {@tool dartpad}
/// This sample shows creation of [IconButton] widgets for standard, filled,
/// filled tonal and outlined types, as described in: https://m3.material.io/components/icon-buttons/overview
///
/// ** See code in examples/api/lib/material/icon_button/icon_button.2.dart **
/// {@end-tool}
///
/// See also:
///
/// * [Icons], the library of Material Icons.
@ -134,6 +150,7 @@ class IconButton extends StatelessWidget {
this.tooltip,
this.enableFeedback = true,
this.constraints,
this.style,
required this.icon,
}) : assert(padding != null),
assert(alignment != null),
@ -184,6 +201,8 @@ class IconButton extends StatelessWidget {
/// The splash radius.
///
/// If [ThemeData.useMaterial3] is set to true, this will not be used.
///
/// If null, default splash radius of [Material.defaultSplashRadius] is used.
final double? splashRadius;
@ -230,6 +249,8 @@ class IconButton extends StatelessWidget {
/// 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.
///
/// If [ThemeData.useMaterial3] is set to true, this will not be used.
///
/// Defaults to the Theme's splash color, [ThemeData.splashColor].
final Color? splashColor;
@ -301,10 +322,125 @@ class IconButton extends StatelessWidget {
/// and `Theme.of(context).visualDensity` otherwise.
final BoxConstraints? constraints;
/// Customizes this button's appearance.
///
/// Non-null properties of this style override the corresponding
/// properties in [_IconButtonM3.themeStyleOf] and [_IconButtonM3.defaultStyleOf].
/// [MaterialStateProperty]s that resolve to non-null values will similarly
/// override the corresponding [MaterialStateProperty]s in [_IconButtonM3.themeStyleOf]
/// and [_IconButtonM3.defaultStyleOf].
///
/// The [style] is only used for Material 3 [IconButton]. If [ThemeData.useMaterial3]
/// is set to true, [style] is preferred for icon button customization, and any
/// parameters defined in [style] will override the same parameters in [IconButton].
///
/// For example, if [IconButton]'s [visualDensity] is set to [VisualDensity.standard]
/// and [style]'s [visualDensity] is set to [VisualDensity.compact],
/// the icon button will have [VisualDensity.compact] to define the button's layout.
///
/// Null by default.
final ButtonStyle? style;
/// A static convenience method that constructs an icon button
/// [ButtonStyle] given simple values. This method is only used for Material 3.
///
/// The [foregroundColor] color is used to create a [MaterialStateProperty]
/// [ButtonStyle.foregroundColor] value. Specify a value for [foregroundColor]
/// to specify the color of the button's icons. The [hoverColor], [focusColor]
/// and [highlightColor] colors are used to indicate the hover, focus,
/// and pressed states. Use [backgroundColor] for the button's background
/// fill color. Use [disabledForegroundColor] and [disabledBackgroundColor]
/// to specify the button's disabled icon and fill color.
///
/// Similarly, the [enabledMouseCursor] and [disabledMouseCursor]
/// parameters are used to construct [ButtonStyle].mouseCursor.
///
/// 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 icon color for a
/// [IconButton], as well as its overlay color, with all of the
/// standard opacity adjustments for the pressed, focused, and
/// hovered states, one could write:
///
/// ```dart
/// IconButton(
/// style: IconButton.styleFrom(foregroundColor: Colors.green),
/// )
/// ```
static ButtonStyle styleFrom({
Color? foregroundColor,
Color? backgroundColor,
Color? disabledForegroundColor,
Color? disabledBackgroundColor,
Color? focusColor,
Color? hoverColor,
Color? highlightColor,
Color? shadowColor,
Color? surfaceTintColor,
double? elevation,
Size? minimumSize,
Size? fixedSize,
Size? maximumSize,
BorderSide? side,
OutlinedBorder? shape,
EdgeInsetsGeometry? padding,
MouseCursor? enabledMouseCursor,
MouseCursor? disabledMouseCursor,
VisualDensity? visualDensity,
MaterialTapTargetSize? tapTargetSize,
Duration? animationDuration,
bool? enableFeedback,
AlignmentGeometry? alignment,
InteractiveInkFeatureFactory? splashFactory,
}) {
final MaterialStateProperty<Color?>? buttonBackgroundColor = (backgroundColor == null && disabledBackgroundColor == null)
? null
: _IconButtonDefaultBackground(backgroundColor, disabledBackgroundColor);
final MaterialStateProperty<Color?>? buttonForegroundColor = (foregroundColor == null && disabledForegroundColor == null)
? null
: _IconButtonDefaultForeground(foregroundColor, disabledForegroundColor);
final MaterialStateProperty<Color?>? overlayColor = (foregroundColor == null && hoverColor == null && focusColor == null && highlightColor == null)
? null
: _IconButtonDefaultOverlay(foregroundColor, focusColor, hoverColor, highlightColor);
final MaterialStateProperty<MouseCursor>? mouseCursor = (enabledMouseCursor == null && disabledMouseCursor == null)
? null
: _IconButtonDefaultMouseCursor(enabledMouseCursor!, disabledMouseCursor!);
return ButtonStyle(
backgroundColor: buttonBackgroundColor,
foregroundColor: buttonForegroundColor,
overlayColor: overlayColor,
shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor),
surfaceTintColor: ButtonStyleButton.allOrNull<Color>(surfaceTintColor),
elevation: ButtonStyleButton.allOrNull<double>(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,
);
}
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterial(context));
final ThemeData theme = Theme.of(context);
if (!theme.useMaterial3) {
assert(debugCheckHasMaterial(context));
}
Color? currentColor;
if (onPressed != null) {
currentColor = color;
@ -321,6 +457,55 @@ class IconButton extends StatelessWidget {
final BoxConstraints adjustedConstraints = effectiveVisualDensity.effectiveConstraints(unadjustedConstraints);
final double effectiveIconSize = iconSize ?? IconTheme.of(context).size ?? 24.0;
if (theme.useMaterial3) {
final Size? minSize = constraints == null
? null
: Size(constraints!.minWidth, constraints!.minHeight);
final Size? maxSize = constraints == null
? null
: Size(constraints!.maxWidth, constraints!.maxHeight);
ButtonStyle adjustedStyle = styleFrom(
visualDensity: visualDensity,
foregroundColor: color,
disabledForegroundColor: disabledColor,
focusColor: focusColor,
hoverColor: hoverColor,
highlightColor: highlightColor,
padding: padding,
minimumSize: minSize,
maximumSize: maxSize,
alignment: alignment,
enabledMouseCursor: mouseCursor,
disabledMouseCursor: mouseCursor,
enableFeedback: enableFeedback,
);
if (style != null) {
adjustedStyle = style!.merge(adjustedStyle);
}
Widget iconButton = IconTheme.merge(
data: IconThemeData(
size: effectiveIconSize,
),
child: icon,
);
if (tooltip != null) {
iconButton = Tooltip(
message: tooltip,
child: iconButton,
);
}
return _IconButtonM3(
key: key,
style: adjustedStyle,
onPressed: onPressed,
autofocus: autofocus,
focusNode: focusNode,
child: iconButton,
);
}
Widget result = ConstrainedBox(
constraints: adjustedConstraints,
child: Padding(
@ -389,3 +574,245 @@ class IconButton extends StatelessWidget {
properties.add(DiagnosticsProperty<FocusNode>('focusNode', focusNode, defaultValue: null));
}
}
class _IconButtonM3 extends ButtonStyleButton {
const _IconButtonM3({
super.key,
required super.onPressed,
super.style,
super.focusNode,
super.autofocus = false,
required Widget super.child,
}) : super(
onLongPress: null,
onHover: null,
onFocusChange: null,
clipBehavior: Clip.none);
/// ## Material 3 defaults
///
/// If [ThemeData.useMaterial3] is set to true the following defaults will
/// be used:
///
/// * `textStyle` - null
/// * `backgroundColor` - transparent
/// * `foregroundColor`
/// * disabled - Theme.colorScheme.onSurface(0.38)
/// * others - Theme.colorScheme.onSurfaceVariant
/// * `overlayColor`
/// * hovered or focused - Theme.colorScheme.onSurfaceVariant(0.08)
/// * pressed - Theme.colorScheme.onSurfaceVariant(0.12)
/// * others - null
/// * `shadowColor` - null
/// * `surfaceTintColor` - null
/// * `elevation` - 0
/// * `padding` - all(8)
/// * `minimumSize` - Size(40, 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
@override
ButtonStyle defaultStyleOf(BuildContext context) {
return _TokenDefaultsM3(context);
}
/// Returns null because [IconButton] doesn't have its component theme.
@override
ButtonStyle? themeStyleOf(BuildContext context) {
return null;
}
}
@immutable
class _IconButtonDefaultBackground extends MaterialStateProperty<Color?> {
_IconButtonDefaultBackground(this.background, this.disabledBackground);
final Color? background;
final Color? disabledBackground;
@override
Color? resolve(Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledBackground;
}
return background;
}
@override
String toString() {
return '{disabled: $disabledBackground, otherwise: $background}';
}
}
@immutable
class _IconButtonDefaultForeground extends MaterialStateProperty<Color?> {
_IconButtonDefaultForeground(this.foregroundColor, this.disabledForegroundColor);
final Color? foregroundColor;
final Color? disabledForegroundColor;
@override
Color? resolve(Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledForegroundColor;
}
return foregroundColor;
}
@override
String toString() {
return '{disabled: $disabledForegroundColor, otherwise: $foregroundColor}';
}
}
@immutable
class _IconButtonDefaultOverlay extends MaterialStateProperty<Color?> {
_IconButtonDefaultOverlay(this.foregroundColor, this.focusColor, this.hoverColor, this.highlightColor);
final Color? foregroundColor;
final Color? focusColor;
final Color? hoverColor;
final Color? highlightColor;
@override
Color? resolve(Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return hoverColor ?? foregroundColor?.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return focusColor ?? foregroundColor?.withOpacity(0.08);
}
if (states.contains(MaterialState.pressed)) {
return highlightColor ?? foregroundColor?.withOpacity(0.12);
}
return null;
}
@override
String toString() {
return '{hovered: $hoverColor, focused: $focusColor, pressed: $highlightColor, otherwise: null}';
}
}
@immutable
class _IconButtonDefaultMouseCursor extends MaterialStateProperty<MouseCursor> with Diagnosticable {
_IconButtonDefaultMouseCursor(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;
}
}
// BEGIN GENERATED TOKEN PROPERTIES
// Generated code to the end of this file. Do not edit by hand.
// These defaults are generated from the Material Design Token
// database by the script dev/tools/gen_defaults/bin/gen_defaults.dart.
// Generated version v0_98
class _TokenDefaultsM3 extends ButtonStyle {
_TokenDefaultsM3(this.context)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: Alignment.center,
);
final BuildContext context;
late final ColorScheme _colors = Theme.of(context).colorScheme;
// No default text style
@override
MaterialStateProperty<Color?>? get backgroundColor =>
ButtonStyleButton.allOrNull<Color>(Colors.transparent);
@override
MaterialStateProperty<Color?>? get foregroundColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return _colors.onSurface.withOpacity(0.38);
}
return _colors.onSurfaceVariant;
});
@override
MaterialStateProperty<Color?>? get overlayColor =>
MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.hovered)) {
return _colors.onSurfaceVariant.withOpacity(0.08);
}
if (states.contains(MaterialState.focused)) {
return _colors.onSurfaceVariant.withOpacity(0.08);
}
if (states.contains(MaterialState.pressed)) {
return _colors.onSurfaceVariant.withOpacity(0.12);
}
return null;
});
// No default shadow color
// No default surface tint color
@override
MaterialStateProperty<double>? get elevation =>
ButtonStyleButton.allOrNull<double>(0.0);
@override
MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(const EdgeInsets.all(8.0));
@override
MaterialStateProperty<Size>? get minimumSize =>
ButtonStyleButton.allOrNull<Size>(const Size(40.0, 40.0));
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize =>
ButtonStyleButton.allOrNull<Size>(Size.infinite);
// No default side
@override
MaterialStateProperty<OutlinedBorder>? get shape =>
ButtonStyleButton.allOrNull<OutlinedBorder>(const 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

File diff suppressed because it is too large Load diff