Unverified Commit 3ce88d38 authored by Qun Cheng's avatar Qun Cheng Committed by GitHub

Replace menu defaults with tokens (#113963)

parent af34b104
...@@ -31,6 +31,7 @@ import 'package:gen_defaults/filter_chip_template.dart'; ...@@ -31,6 +31,7 @@ import 'package:gen_defaults/filter_chip_template.dart';
import 'package:gen_defaults/icon_button_template.dart'; import 'package:gen_defaults/icon_button_template.dart';
import 'package:gen_defaults/input_chip_template.dart'; import 'package:gen_defaults/input_chip_template.dart';
import 'package:gen_defaults/input_decorator_template.dart'; import 'package:gen_defaults/input_decorator_template.dart';
import 'package:gen_defaults/menu_template.dart';
import 'package:gen_defaults/navigation_bar_template.dart'; import 'package:gen_defaults/navigation_bar_template.dart';
import 'package:gen_defaults/navigation_rail_template.dart'; import 'package:gen_defaults/navigation_rail_template.dart';
import 'package:gen_defaults/popup_menu_template.dart'; import 'package:gen_defaults/popup_menu_template.dart';
...@@ -135,6 +136,7 @@ Future<void> main(List<String> args) async { ...@@ -135,6 +136,7 @@ Future<void> main(List<String> args) async {
IconButtonTemplate('IconButton', '$materialLib/icon_button.dart', tokens).updateFile(); IconButtonTemplate('IconButton', '$materialLib/icon_button.dart', tokens).updateFile();
InputChipTemplate('InputChip', '$materialLib/input_chip.dart', tokens).updateFile(); InputChipTemplate('InputChip', '$materialLib/input_chip.dart', tokens).updateFile();
InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile(); InputDecoratorTemplate('InputDecorator', '$materialLib/input_decorator.dart', tokens).updateFile();
MenuTemplate('Menu', '$materialLib/menu_anchor.dart', tokens).updateFile();
NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile(); NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile();
NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile(); NavigationRailTemplate('NavigationRail', '$materialLib/navigation_rail.dart', tokens).updateFile();
PopupMenuTemplate('PopupMenu', '$materialLib/popup_menu.dart', tokens).updateFile(); PopupMenuTemplate('PopupMenu', '$materialLib/popup_menu.dart', tokens).updateFile();
......
// 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 MenuTemplate extends TokenTemplate {
const MenuTemplate(super.blockName, super.fileName, super.tokens, {
super.colorSchemePrefix = '_colors.',
});
@override
String generate() => '''
class _MenuBarDefaultsM3 extends MenuStyle {
_MenuBarDefaultsM3(this.context)
: super(
elevation: const MaterialStatePropertyAll<double?>(${elevation('md.comp.menu.container')}),
shape: const MaterialStatePropertyAll<OutlinedBorder>(_defaultMenuBorder),
alignment: AlignmentDirectional.bottomStart,
);
static const RoundedRectangleBorder _defaultMenuBorder =
${shape('md.comp.menu.container', '')};
final BuildContext context;
late final ColorScheme _colors = Theme.of(context).colorScheme;
@override
MaterialStateProperty<Color?> get backgroundColor {
return MaterialStatePropertyAll<Color?>(${componentColor('md.comp.menu.container')});
}
@override
MaterialStateProperty<Color?>? get shadowColor {
return MaterialStatePropertyAll<Color?>(${color('md.comp.menu.container.shadow-color')});
}
@override
MaterialStateProperty<Color?>? get surfaceTintColor {
return MaterialStatePropertyAll<Color?>(${componentColor('md.comp.menu.container.surface-tint-layer')});
}
@override
MaterialStateProperty<EdgeInsetsGeometry?>? get padding {
return MaterialStatePropertyAll<EdgeInsetsGeometry>(
EdgeInsetsDirectional.symmetric(
horizontal: math.max(
_kTopLevelMenuHorizontalMinPadding,
2 + Theme.of(context).visualDensity.baseSizeAdjustment.dx,
),
),
);
}
}
class _MenuButtonDefaultsM3 extends ButtonStyle {
_MenuButtonDefaultsM3(this.context)
: super(
animationDuration: kThemeChangeDuration,
enableFeedback: true,
alignment: AlignmentDirectional.centerStart,
);
final BuildContext context;
late final ColorScheme _colors = Theme.of(context).colorScheme;
@override
MaterialStateProperty<Color?>? get backgroundColor {
return ButtonStyleButton.allOrNull<Color>(Colors.transparent);
}
// No default shadow color
// No default surface tint color
@override
MaterialStateProperty<double>? get elevation {
return ButtonStyleButton.allOrNull<double>(0.0);
}
@override
MaterialStateProperty<Color?>? get foregroundColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return ${componentColor('md.comp.menu.list-item.disabled.label-text')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.menu.list-item.pressed.label-text')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.menu.list-item.hover.label-text')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.menu.list-item.focus.label-text')};
}
return ${componentColor('md.comp.menu.list-item.label-text')};
});
}
@override
MaterialStateProperty<Color?>? get iconColor {
return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return ${componentColor('md.comp.menu.list-item.with-leading-icon.disabled.leading-icon')};
}
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.menu.list-item.with-leading-icon.pressed.icon')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.menu.list-item.with-leading-icon.hover.icon')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.menu.list-item.with-leading-icon.focus.icon')};
}
return ${componentColor('md.comp.menu.list-item.with-leading-icon.leading-icon')};
});
}
// No default fixedSize
@override
MaterialStateProperty<Size>? get maximumSize {
return ButtonStyleButton.allOrNull<Size>(Size.infinite);
}
@override
MaterialStateProperty<Size>? get minimumSize {
return ButtonStyleButton.allOrNull<Size>(const Size(64.0, ${tokens['md.comp.menu.list-item.container.height']}));
}
@override
MaterialStateProperty<MouseCursor?>? get mouseCursor {
return MaterialStateProperty.resolveWith(
(Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return SystemMouseCursors.basic;
}
return SystemMouseCursors.click;
},
);
}
@override
MaterialStateProperty<Color?>? get overlayColor {
return MaterialStateProperty.resolveWith(
(Set<MaterialState> states) {
if (states.contains(MaterialState.pressed)) {
return ${componentColor('md.comp.menu.list-item.pressed.state-layer')};
}
if (states.contains(MaterialState.hovered)) {
return ${componentColor('md.comp.menu.list-item.hover.state-layer')};
}
if (states.contains(MaterialState.focused)) {
return ${componentColor('md.comp.menu.list-item.focus.state-layer')};
}
return Colors.transparent;
},
);
}
@override
MaterialStateProperty<EdgeInsetsGeometry>? get padding {
return ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(_scaledPadding(context));
}
// No default side
@override
MaterialStateProperty<OutlinedBorder>? get shape {
return ButtonStyleButton.allOrNull<OutlinedBorder>(const RoundedRectangleBorder());
}
@override
InteractiveInkFeatureFactory? get splashFactory => Theme.of(context).splashFactory;
@override
MaterialTapTargetSize? get tapTargetSize => Theme.of(context).materialTapTargetSize;
@override
MaterialStateProperty<TextStyle?> get textStyle {
return MaterialStatePropertyAll<TextStyle?>(${textStyle('md.comp.menu.list-item.label-text')});
}
@override
VisualDensity? get visualDensity => Theme.of(context).visualDensity;
// The horizontal padding number comes from the spec.
EdgeInsetsGeometry _scaledPadding(BuildContext context) {
return ButtonStyleButton.scaledPadding(
const EdgeInsets.symmetric(horizontal: 12),
const EdgeInsets.symmetric(horizontal: 8),
const EdgeInsets.symmetric(horizontal: 4),
MediaQuery.maybeOf(context)?.textScaleFactor ?? 1,
);
}
}
class _MenuDefaultsM3 extends MenuStyle {
_MenuDefaultsM3(this.context)
: super(
elevation: const MaterialStatePropertyAll<double?>(${elevation('md.comp.menu.container')}),
shape: const MaterialStatePropertyAll<OutlinedBorder>(_defaultMenuBorder),
alignment: AlignmentDirectional.topEnd,
);
static const RoundedRectangleBorder _defaultMenuBorder =
${shape('md.comp.menu.container', '')};
final BuildContext context;
late final ColorScheme _colors = Theme.of(context).colorScheme;
@override
MaterialStateProperty<Color?> get backgroundColor {
return MaterialStatePropertyAll<Color?>(${componentColor('md.comp.menu.container')});
}
@override
MaterialStateProperty<Color?>? get surfaceTintColor {
return MaterialStatePropertyAll<Color?>(${componentColor('md.comp.menu.container.surface-tint-layer')});
}
@override
MaterialStateProperty<Color?>? get shadowColor {
return MaterialStatePropertyAll<Color?>(${color('md.comp.menu.container.shadow-color')});
}
@override
MaterialStateProperty<EdgeInsetsGeometry?>? get padding {
return MaterialStatePropertyAll<EdgeInsetsGeometry>(
EdgeInsetsDirectional.symmetric(
vertical: math.max(
_kMenuVerticalMinPadding,
2 + Theme.of(context).visualDensity.baseSizeAdjustment.dy,
),
),
);
}
}
''';
}
...@@ -21,14 +21,14 @@ void main() { ...@@ -21,14 +21,14 @@ void main() {
await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight); await tester.sendKeyDownEvent(LogicalKeyboardKey.controlRight);
await tester.tapAt(const Offset(100, 200)); await tester.tapAt(const Offset(100, 200));
await tester.pump(); await tester.pump();
expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(100.0, 200.0, 404.0, 352.0))); expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(100.0, 200.0, 388.0, 360.0)));
// Make sure tapping in a different place causes the menu to move. // Make sure tapping in a different place causes the menu to move.
await tester.tapAt(const Offset(200, 100)); await tester.tapAt(const Offset(200, 100));
await tester.pump(); await tester.pump();
await tester.sendKeyUpEvent(LogicalKeyboardKey.controlRight); await tester.sendKeyUpEvent(LogicalKeyboardKey.controlRight);
expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(200.0, 100.0, 504.0, 252.0))); expect(tester.getRect(findMenu()), equals(const Rect.fromLTRB(200.0, 100.0, 488.0, 260.0)));
expect(find.text(example.MenuEntry.about.label), findsOneWidget); expect(find.text(example.MenuEntry.about.label), findsOneWidget);
expect(find.text(example.MenuEntry.showMessage.label), findsOneWidget); expect(find.text(example.MenuEntry.showMessage.label), findsOneWidget);
......
...@@ -151,6 +151,7 @@ class ButtonStyle with Diagnosticable { ...@@ -151,6 +151,7 @@ class ButtonStyle with Diagnosticable {
this.minimumSize, this.minimumSize,
this.fixedSize, this.fixedSize,
this.maximumSize, this.maximumSize,
this.iconColor,
this.iconSize, this.iconSize,
this.side, this.side,
this.shape, this.shape,
...@@ -230,6 +231,11 @@ class ButtonStyle with Diagnosticable { ...@@ -230,6 +231,11 @@ class ButtonStyle with Diagnosticable {
/// This value must be greater than or equal to [minimumSize]. /// This value must be greater than or equal to [minimumSize].
final MaterialStateProperty<Size?>? maximumSize; final MaterialStateProperty<Size?>? maximumSize;
/// The icon's color inside of the button.
///
/// If this is null, the icon color will be [foregroundColor].
final MaterialStateProperty<Color?>? iconColor;
/// The icon's size inside of the button. /// The icon's size inside of the button.
final MaterialStateProperty<double?>? iconSize; final MaterialStateProperty<double?>? iconSize;
...@@ -323,6 +329,7 @@ class ButtonStyle with Diagnosticable { ...@@ -323,6 +329,7 @@ class ButtonStyle with Diagnosticable {
MaterialStateProperty<Size?>? minimumSize, MaterialStateProperty<Size?>? minimumSize,
MaterialStateProperty<Size?>? fixedSize, MaterialStateProperty<Size?>? fixedSize,
MaterialStateProperty<Size?>? maximumSize, MaterialStateProperty<Size?>? maximumSize,
MaterialStateProperty<Color?>? iconColor,
MaterialStateProperty<double?>? iconSize, MaterialStateProperty<double?>? iconSize,
MaterialStateProperty<BorderSide?>? side, MaterialStateProperty<BorderSide?>? side,
MaterialStateProperty<OutlinedBorder?>? shape, MaterialStateProperty<OutlinedBorder?>? shape,
...@@ -346,6 +353,7 @@ class ButtonStyle with Diagnosticable { ...@@ -346,6 +353,7 @@ class ButtonStyle with Diagnosticable {
minimumSize: minimumSize ?? this.minimumSize, minimumSize: minimumSize ?? this.minimumSize,
fixedSize: fixedSize ?? this.fixedSize, fixedSize: fixedSize ?? this.fixedSize,
maximumSize: maximumSize ?? this.maximumSize, maximumSize: maximumSize ?? this.maximumSize,
iconColor: iconColor ?? this.iconColor,
iconSize: iconSize ?? this.iconSize, iconSize: iconSize ?? this.iconSize,
side: side ?? this.side, side: side ?? this.side,
shape: shape ?? this.shape, shape: shape ?? this.shape,
...@@ -380,6 +388,7 @@ class ButtonStyle with Diagnosticable { ...@@ -380,6 +388,7 @@ class ButtonStyle with Diagnosticable {
minimumSize: minimumSize ?? style.minimumSize, minimumSize: minimumSize ?? style.minimumSize,
fixedSize: fixedSize ?? style.fixedSize, fixedSize: fixedSize ?? style.fixedSize,
maximumSize: maximumSize ?? style.maximumSize, maximumSize: maximumSize ?? style.maximumSize,
iconColor: iconColor ?? style.iconColor,
iconSize: iconSize ?? style.iconSize, iconSize: iconSize ?? style.iconSize,
side: side ?? style.side, side: side ?? style.side,
shape: shape ?? style.shape, shape: shape ?? style.shape,
...@@ -407,6 +416,7 @@ class ButtonStyle with Diagnosticable { ...@@ -407,6 +416,7 @@ class ButtonStyle with Diagnosticable {
minimumSize, minimumSize,
fixedSize, fixedSize,
maximumSize, maximumSize,
iconColor,
iconSize, iconSize,
side, side,
shape, shape,
...@@ -441,6 +451,7 @@ class ButtonStyle with Diagnosticable { ...@@ -441,6 +451,7 @@ class ButtonStyle with Diagnosticable {
&& other.minimumSize == minimumSize && other.minimumSize == minimumSize
&& other.fixedSize == fixedSize && other.fixedSize == fixedSize
&& other.maximumSize == maximumSize && other.maximumSize == maximumSize
&& other.iconColor == iconColor
&& other.iconSize == iconSize && other.iconSize == iconSize
&& other.side == side && other.side == side
&& other.shape == shape && other.shape == shape
...@@ -467,6 +478,7 @@ class ButtonStyle with Diagnosticable { ...@@ -467,6 +478,7 @@ class ButtonStyle with Diagnosticable {
properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('minimumSize', minimumSize, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('minimumSize', minimumSize, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('fixedSize', fixedSize, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('fixedSize', fixedSize, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('maximumSize', maximumSize, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Size?>>('maximumSize', maximumSize, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('iconColor', iconColor, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<double?>>('iconSize', iconSize, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<double?>>('iconSize', iconSize, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<BorderSide?>>('side', side, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<BorderSide?>>('side', side, defaultValue: null));
properties.add(DiagnosticsProperty<MaterialStateProperty<OutlinedBorder?>>('shape', shape, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<OutlinedBorder?>>('shape', shape, defaultValue: null));
...@@ -496,6 +508,7 @@ class ButtonStyle with Diagnosticable { ...@@ -496,6 +508,7 @@ class ButtonStyle with Diagnosticable {
minimumSize: MaterialStateProperty.lerp<Size?>(a?.minimumSize, b?.minimumSize, t, Size.lerp), minimumSize: MaterialStateProperty.lerp<Size?>(a?.minimumSize, b?.minimumSize, t, Size.lerp),
fixedSize: MaterialStateProperty.lerp<Size?>(a?.fixedSize, b?.fixedSize, t, Size.lerp), fixedSize: MaterialStateProperty.lerp<Size?>(a?.fixedSize, b?.fixedSize, t, Size.lerp),
maximumSize: MaterialStateProperty.lerp<Size?>(a?.maximumSize, b?.maximumSize, t, Size.lerp), maximumSize: MaterialStateProperty.lerp<Size?>(a?.maximumSize, b?.maximumSize, t, Size.lerp),
iconColor: MaterialStateProperty.lerp<Color?>(a?.iconColor, b?.iconColor, t, Color.lerp),
iconSize: MaterialStateProperty.lerp<double?>(a?.iconSize, b?.iconSize, t, lerpDouble), iconSize: MaterialStateProperty.lerp<double?>(a?.iconSize, b?.iconSize, t, lerpDouble),
side: _lerpSides(a?.side, b?.side, t), side: _lerpSides(a?.side, b?.side, t),
shape: MaterialStateProperty.lerp<OutlinedBorder?>(a?.shape, b?.shape, t, OutlinedBorder.lerp), shape: MaterialStateProperty.lerp<OutlinedBorder?>(a?.shape, b?.shape, t, OutlinedBorder.lerp),
......
...@@ -287,6 +287,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat ...@@ -287,6 +287,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
final Size? resolvedMinimumSize = resolve<Size?>((ButtonStyle? style) => style?.minimumSize); final Size? resolvedMinimumSize = resolve<Size?>((ButtonStyle? style) => style?.minimumSize);
final Size? resolvedFixedSize = resolve<Size?>((ButtonStyle? style) => style?.fixedSize); final Size? resolvedFixedSize = resolve<Size?>((ButtonStyle? style) => style?.fixedSize);
final Size? resolvedMaximumSize = resolve<Size?>((ButtonStyle? style) => style?.maximumSize); final Size? resolvedMaximumSize = resolve<Size?>((ButtonStyle? style) => style?.maximumSize);
final Color? resolvedIconColor = resolve<Color?>((ButtonStyle? style) => style?.iconColor);
final double? resolvedIconSize = resolve<double?>((ButtonStyle? style) => style?.iconSize); final double? resolvedIconSize = resolve<double?>((ButtonStyle? style) => style?.iconSize);
final BorderSide? resolvedSide = resolve<BorderSide?>((ButtonStyle? style) => style?.side); final BorderSide? resolvedSide = resolve<BorderSide?>((ButtonStyle? style) => style?.side);
final OutlinedBorder? resolvedShape = resolve<OutlinedBorder?>((ButtonStyle? style) => style?.shape); final OutlinedBorder? resolvedShape = resolve<OutlinedBorder?>((ButtonStyle? style) => style?.shape);
...@@ -400,7 +401,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat ...@@ -400,7 +401,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
customBorder: resolvedShape.copyWith(side: resolvedSide), customBorder: resolvedShape.copyWith(side: resolvedSide),
statesController: statesController, statesController: statesController,
child: IconTheme.merge( child: IconTheme.merge(
data: IconThemeData(color: resolvedForegroundColor, size: resolvedIconSize), data: IconThemeData(color: resolvedIconColor ?? resolvedForegroundColor, size: resolvedIconSize),
child: Padding( child: Padding(
padding: padding, padding: padding,
child: Align( child: Align(
......
...@@ -153,6 +153,8 @@ class TextButton extends ButtonStyleButton { ...@@ -153,6 +153,8 @@ class TextButton extends ButtonStyleButton {
Color? disabledBackgroundColor, Color? disabledBackgroundColor,
Color? shadowColor, Color? shadowColor,
Color? surfaceTintColor, Color? surfaceTintColor,
Color? iconColor,
Color? disabledIconColor,
double? elevation, double? elevation,
TextStyle? textStyle, TextStyle? textStyle,
EdgeInsetsGeometry? padding, EdgeInsetsGeometry? padding,
...@@ -193,6 +195,11 @@ class TextButton extends ButtonStyleButton { ...@@ -193,6 +195,11 @@ class TextButton extends ButtonStyleButton {
final MaterialStateProperty<Color?>? overlayColor = (foreground == null) final MaterialStateProperty<Color?>? overlayColor = (foreground == null)
? null ? null
: _TextButtonDefaultOverlay(foreground); : _TextButtonDefaultOverlay(foreground);
final MaterialStateProperty<Color?>? iconColorProp = (iconColor == null && disabledIconColor == null)
? null
: disabledIconColor == null
? ButtonStyleButton.allOrNull<Color?>(iconColor)
: _TextButtonDefaultIconColor(iconColor, disabledIconColor);
final MaterialStateProperty<MouseCursor>? mouseCursor = (enabledMouseCursor == null && disabledMouseCursor == null) final MaterialStateProperty<MouseCursor>? mouseCursor = (enabledMouseCursor == null && disabledMouseCursor == null)
? null ? null
: _TextButtonDefaultMouseCursor(enabledMouseCursor!, disabledMouseCursor!); : _TextButtonDefaultMouseCursor(enabledMouseCursor!, disabledMouseCursor!);
...@@ -204,6 +211,7 @@ class TextButton extends ButtonStyleButton { ...@@ -204,6 +211,7 @@ class TextButton extends ButtonStyleButton {
overlayColor: overlayColor, overlayColor: overlayColor,
shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor), shadowColor: ButtonStyleButton.allOrNull<Color>(shadowColor),
surfaceTintColor: ButtonStyleButton.allOrNull<Color>(surfaceTintColor), surfaceTintColor: ButtonStyleButton.allOrNull<Color>(surfaceTintColor),
iconColor: iconColorProp,
elevation: ButtonStyleButton.allOrNull<double>(elevation), elevation: ButtonStyleButton.allOrNull<double>(elevation),
padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding), padding: ButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding),
minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize), minimumSize: ButtonStyleButton.allOrNull<Size>(minimumSize),
...@@ -422,6 +430,27 @@ class _TextButtonDefaultOverlay extends MaterialStateProperty<Color?> { ...@@ -422,6 +430,27 @@ class _TextButtonDefaultOverlay extends MaterialStateProperty<Color?> {
} }
} }
@immutable
class _TextButtonDefaultIconColor extends MaterialStateProperty<Color?> {
_TextButtonDefaultIconColor(this.iconColor, this.disabledIconColor);
final Color? iconColor;
final Color? disabledIconColor;
@override
Color? resolve(Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledIconColor;
}
return iconColor;
}
@override
String toString() {
return '{disabled: $disabledIconColor, color: $iconColor}';
}
}
@immutable @immutable
class _TextButtonDefaultMouseCursor extends MaterialStateProperty<MouseCursor> with Diagnosticable { class _TextButtonDefaultMouseCursor extends MaterialStateProperty<MouseCursor> with Diagnosticable {
_TextButtonDefaultMouseCursor(this.enabledCursor, this.disabledCursor); _TextButtonDefaultMouseCursor(this.enabledCursor, this.disabledCursor);
......
...@@ -27,6 +27,7 @@ void main() { ...@@ -27,6 +27,7 @@ void main() {
expect(style.minimumSize, null); expect(style.minimumSize, null);
expect(style.fixedSize, null); expect(style.fixedSize, null);
expect(style.maximumSize, null); expect(style.maximumSize, null);
expect(style.iconColor, null);
expect(style.iconSize, null); expect(style.iconSize, null);
expect(style.side, null); expect(style.side, null);
expect(style.shape, null); expect(style.shape, null);
...@@ -63,6 +64,7 @@ void main() { ...@@ -63,6 +64,7 @@ void main() {
minimumSize: MaterialStatePropertyAll<Size>(Size(1.0, 2.0)), minimumSize: MaterialStatePropertyAll<Size>(Size(1.0, 2.0)),
side: MaterialStatePropertyAll<BorderSide>(BorderSide(width: 4.0, color: Color(0xfffffff6))), side: MaterialStatePropertyAll<BorderSide>(BorderSide(width: 4.0, color: Color(0xfffffff6))),
maximumSize: MaterialStatePropertyAll<Size>(Size(100.0, 200.0)), maximumSize: MaterialStatePropertyAll<Size>(Size(100.0, 200.0)),
iconColor: MaterialStatePropertyAll<Color>(Color(0xfffffff6)),
iconSize: MaterialStatePropertyAll<double>(48.1), iconSize: MaterialStatePropertyAll<double>(48.1),
shape: MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder()), shape: MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder()),
mouseCursor: MaterialStatePropertyAll<MouseCursor>(SystemMouseCursors.forbidden), mouseCursor: MaterialStatePropertyAll<MouseCursor>(SystemMouseCursors.forbidden),
...@@ -87,6 +89,7 @@ void main() { ...@@ -87,6 +89,7 @@ void main() {
'padding: MaterialStatePropertyAll(EdgeInsets.all(1.0))', 'padding: MaterialStatePropertyAll(EdgeInsets.all(1.0))',
'minimumSize: MaterialStatePropertyAll(Size(1.0, 2.0))', 'minimumSize: MaterialStatePropertyAll(Size(1.0, 2.0))',
'maximumSize: MaterialStatePropertyAll(Size(100.0, 200.0))', 'maximumSize: MaterialStatePropertyAll(Size(100.0, 200.0))',
'iconColor: MaterialStatePropertyAll(Color(0xfffffff6))',
'iconSize: MaterialStatePropertyAll(48.1)', 'iconSize: MaterialStatePropertyAll(48.1)',
'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff6), width: 4.0))', 'side: MaterialStatePropertyAll(BorderSide(color: Color(0xfffffff6), width: 4.0))',
'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))', 'shape: MaterialStatePropertyAll(StadiumBorder(BorderSide(width: 0.0, style: none)))',
...@@ -109,6 +112,7 @@ void main() { ...@@ -109,6 +112,7 @@ void main() {
const MaterialStateProperty<Size> minimumSize = MaterialStatePropertyAll<Size>(Size(1, 2)); const MaterialStateProperty<Size> minimumSize = MaterialStatePropertyAll<Size>(Size(1, 2));
const MaterialStateProperty<Size> fixedSize = MaterialStatePropertyAll<Size>(Size(3, 4)); const MaterialStateProperty<Size> fixedSize = MaterialStatePropertyAll<Size>(Size(3, 4));
const MaterialStateProperty<Size> maximumSize = MaterialStatePropertyAll<Size>(Size(5, 6)); const MaterialStateProperty<Size> maximumSize = MaterialStatePropertyAll<Size>(Size(5, 6));
const MaterialStateProperty<Color> iconColor = MaterialStatePropertyAll<Color>(Color(0xfffffff6));
const MaterialStateProperty<double> iconSize = MaterialStatePropertyAll<double>(48.0); const MaterialStateProperty<double> iconSize = MaterialStatePropertyAll<double>(48.0);
const MaterialStateProperty<BorderSide> side = MaterialStatePropertyAll<BorderSide>(BorderSide()); const MaterialStateProperty<BorderSide> side = MaterialStatePropertyAll<BorderSide>(BorderSide());
const MaterialStateProperty<OutlinedBorder> shape = MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder()); const MaterialStateProperty<OutlinedBorder> shape = MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder());
...@@ -130,6 +134,7 @@ void main() { ...@@ -130,6 +134,7 @@ void main() {
minimumSize: minimumSize, minimumSize: minimumSize,
fixedSize: fixedSize, fixedSize: fixedSize,
maximumSize: maximumSize, maximumSize: maximumSize,
iconColor: iconColor,
iconSize: iconSize, iconSize: iconSize,
side: side, side: side,
shape: shape, shape: shape,
...@@ -154,6 +159,7 @@ void main() { ...@@ -154,6 +159,7 @@ void main() {
minimumSize: minimumSize, minimumSize: minimumSize,
fixedSize: fixedSize, fixedSize: fixedSize,
maximumSize: maximumSize, maximumSize: maximumSize,
iconColor: iconColor,
iconSize: iconSize, iconSize: iconSize,
side: side, side: side,
shape: shape, shape: shape,
......
...@@ -87,13 +87,13 @@ void main() { ...@@ -87,13 +87,13 @@ void main() {
// Open a test menu. // Open a test menu.
await tester.tap(find.text(TestMenu.mainMenu1.label)); await tester.tap(find.text(TestMenu.mainMenu1.label));
await tester.pump(); await tester.pump();
expect(tester.getRect(findMenuBarPanel().first), equals(const Rect.fromLTRB(240.0, 0.0, 560.0, 68.0))); expect(tester.getRect(findMenuBarPanel().first), equals(const Rect.fromLTRB(228.0, 0.0, 572.0, 68.0)));
final Material menuBarMaterial = getMenuBarPanelMaterial(tester); final Material menuBarMaterial = getMenuBarPanelMaterial(tester);
expect(menuBarMaterial.elevation, equals(15)); expect(menuBarMaterial.elevation, equals(15));
expect(menuBarMaterial.color, equals(Colors.red)); expect(menuBarMaterial.color, equals(Colors.red));
final Material subMenuMaterial = getSubmenuPanelMaterial(tester); final Material subMenuMaterial = getSubmenuPanelMaterial(tester);
expect(tester.getRect(findSubmenuPanel()), equals(const Rect.fromLTRB(350.0, 58.0, 580.0, 210.0))); expect(tester.getRect(findSubmenuPanel()), equals(const Rect.fromLTRB(346.0, 58.0, 560.0, 218.0)));
expect(subMenuMaterial.elevation, equals(20)); expect(subMenuMaterial.elevation, equals(20));
expect(subMenuMaterial.color, equals(Colors.green)); expect(subMenuMaterial.color, equals(Colors.green));
}); });
...@@ -160,19 +160,19 @@ void main() { ...@@ -160,19 +160,19 @@ void main() {
await tester.tap(find.text(TestMenu.mainMenu1.label)); await tester.tap(find.text(TestMenu.mainMenu1.label));
await tester.pump(); await tester.pump();
expect(tester.getRect(findMenuBarPanel().first), equals(const Rect.fromLTRB(238.0, 0.0, 562.0, 72.0))); expect(tester.getRect(findMenuBarPanel().first), equals(const Rect.fromLTRB(226.0, 0.0, 574.0, 72.0)));
final Material menuBarMaterial = getMenuBarPanelMaterial(tester); final Material menuBarMaterial = getMenuBarPanelMaterial(tester);
expect(menuBarMaterial.elevation, equals(10.0)); expect(menuBarMaterial.elevation, equals(10.0));
expect(menuBarMaterial.color, equals(Colors.blue)); expect(menuBarMaterial.color, equals(Colors.blue));
final Material subMenuMaterial = getSubmenuPanelMaterial(tester); final Material subMenuMaterial = getSubmenuPanelMaterial(tester);
expect(tester.getRect(findSubmenuPanel()), equals(const Rect.fromLTRB(336.0, 60.0, 594.0, 232.0))); expect(tester.getRect(findSubmenuPanel()), equals(const Rect.fromLTRB(332.0, 60.0, 574.0, 232.0)));
expect(subMenuMaterial.elevation, equals(18)); expect(subMenuMaterial.elevation, equals(18));
expect(subMenuMaterial.color, equals(Colors.cyan)); expect(subMenuMaterial.color, equals(Colors.cyan));
expect(subMenuMaterial.shape, equals(const BeveledRectangleBorder())); expect(subMenuMaterial.shape, equals(const BeveledRectangleBorder()));
final Finder menuItem = findSubMenuItem(); final Finder menuItem = findSubMenuItem();
expect(tester.getRect(menuItem.first), equals(const Rect.fromLTRB(350.0, 74.0, 580.0, 122.0))); expect(tester.getRect(menuItem.first), equals(const Rect.fromLTRB(346.0, 74.0, 560.0, 122.0)));
final Material menuItemMaterial = tester.widget<Material>( final Material menuItemMaterial = tester.widget<Material>(
find.ancestor(of: find.text(TestMenu.subMenu10.label), matching: find.byType(Material)).first); find.ancestor(of: find.text(TestMenu.subMenu10.label), matching: find.byType(Material)).first);
expect(menuItemMaterial.color, equals(Colors.amber)); expect(menuItemMaterial.color, equals(Colors.amber));
......
...@@ -261,20 +261,20 @@ void main() { ...@@ -261,20 +261,20 @@ void main() {
); );
await tester.pump(); await tester.pump();
expect(tester.getRect(find.byType(MenuBar)), equals(const Rect.fromLTRB(240.0, 0.0, 560.0, 48.0))); expect(tester.getRect(find.byType(MenuBar)), equals(const Rect.fromLTRB(228.0, 0.0, 572.0, 48.0)));
// Open and make sure things are the right size. // Open and make sure things are the right size.
await tester.tap(find.text(TestMenu.mainMenu1.label)); await tester.tap(find.text(TestMenu.mainMenu1.label));
await tester.pump(); await tester.pump();
expect(tester.getRect(find.byType(MenuBar)), equals(const Rect.fromLTRB(240.0, 0.0, 560.0, 48.0))); expect(tester.getRect(find.byType(MenuBar)), equals(const Rect.fromLTRB(228.0, 0.0, 572.0, 48.0)));
expect( expect(
tester.getRect(find.text(TestMenu.subMenu10.label)), tester.getRect(find.text(TestMenu.subMenu10.label)),
equals(const Rect.fromLTRB(366.0, 64.0, 520.0, 78.0)), equals(const Rect.fromLTRB(366.0, 68.0, 520.0, 82.0)),
); );
expect( expect(
tester.getRect(find.ancestor(of: find.text(TestMenu.subMenu10.label), matching: find.byType(Material)).at(1)), tester.getRect(find.ancestor(of: find.text(TestMenu.subMenu10.label), matching: find.byType(Material)).at(1)),
equals(const Rect.fromLTRB(350.0, 48.0, 602.0, 178.0)), equals(const Rect.fromLTRB(346.0, 48.0, 579.0, 186.0)),
); );
}); });
}); });
......
...@@ -87,13 +87,13 @@ void main() { ...@@ -87,13 +87,13 @@ void main() {
// Open a test menu. // Open a test menu.
await tester.tap(find.text(TestMenu.mainMenu1.label)); await tester.tap(find.text(TestMenu.mainMenu1.label));
await tester.pump(); await tester.pump();
expect(tester.getRect(findMenuBarPanel().first), equals(const Rect.fromLTRB(246.0, 0.0, 554.0, 48.0))); expect(tester.getRect(findMenuBarPanel().first), equals(const Rect.fromLTRB(234.0, 0.0, 566.0, 48.0)));
final Material menuBarMaterial = getMenuBarPanelMaterial(tester); final Material menuBarMaterial = getMenuBarPanelMaterial(tester);
expect(menuBarMaterial.elevation, equals(20)); expect(menuBarMaterial.elevation, equals(20));
expect(menuBarMaterial.color, equals(Colors.green)); expect(menuBarMaterial.color, equals(Colors.green));
final Material subMenuMaterial = getSubmenuPanelMaterial(tester); final Material subMenuMaterial = getSubmenuPanelMaterial(tester);
expect(tester.getRect(findSubmenuPanel()), equals(const Rect.fromLTRB(340.0, 48.0, 590.0, 212.0))); expect(tester.getRect(findSubmenuPanel()), equals(const Rect.fromLTRB(336.0, 48.0, 570.0, 212.0)));
expect(subMenuMaterial.elevation, equals(15)); expect(subMenuMaterial.elevation, equals(15));
expect(subMenuMaterial.color, equals(Colors.red)); expect(subMenuMaterial.color, equals(Colors.red));
}); });
...@@ -160,19 +160,19 @@ void main() { ...@@ -160,19 +160,19 @@ void main() {
await tester.tap(find.text(TestMenu.mainMenu1.label)); await tester.tap(find.text(TestMenu.mainMenu1.label));
await tester.pump(); await tester.pump();
expect(tester.getRect(findMenuBarPanel().first), equals(const Rect.fromLTRB(238.0, 0.0, 562.0, 72.0))); expect(tester.getRect(findMenuBarPanel().first), equals(const Rect.fromLTRB(226.0, 0.0, 574.0, 72.0)));
final Material menuBarMaterial = getMenuBarPanelMaterial(tester); final Material menuBarMaterial = getMenuBarPanelMaterial(tester);
expect(menuBarMaterial.elevation, equals(10.0)); expect(menuBarMaterial.elevation, equals(10.0));
expect(menuBarMaterial.color, equals(Colors.blue)); expect(menuBarMaterial.color, equals(Colors.blue));
final Material subMenuMaterial = getSubmenuPanelMaterial(tester); final Material subMenuMaterial = getSubmenuPanelMaterial(tester);
expect(tester.getRect(findSubmenuPanel()), equals(const Rect.fromLTRB(336.0, 60.0, 594.0, 232.0))); expect(tester.getRect(findSubmenuPanel()), equals(const Rect.fromLTRB(332.0, 60.0, 574.0, 232.0)));
expect(subMenuMaterial.elevation, equals(18)); expect(subMenuMaterial.elevation, equals(18));
expect(subMenuMaterial.color, equals(Colors.cyan)); expect(subMenuMaterial.color, equals(Colors.cyan));
expect(subMenuMaterial.shape, equals(const BeveledRectangleBorder())); expect(subMenuMaterial.shape, equals(const BeveledRectangleBorder()));
final Finder menuItem = findSubMenuItem(); final Finder menuItem = findSubMenuItem();
expect(tester.getRect(menuItem.first), equals(const Rect.fromLTRB(350.0, 74.0, 580.0, 122.0))); expect(tester.getRect(menuItem.first), equals(const Rect.fromLTRB(346.0, 74.0, 560.0, 122.0)));
final Material menuItemMaterial = tester.widget<Material>( final Material menuItemMaterial = tester.widget<Material>(
find.ancestor(of: find.text(TestMenu.subMenu10.label), matching: find.byType(Material)).first); find.ancestor(of: find.text(TestMenu.subMenu10.label), matching: find.byType(Material)).first);
expect(menuItemMaterial.color, equals(Colors.amber)); expect(menuItemMaterial.color, equals(Colors.amber));
......
...@@ -1685,6 +1685,62 @@ void main() { ...@@ -1685,6 +1685,62 @@ void main() {
expect(controller.value, <MaterialState>{MaterialState.disabled}); expect(controller.value, <MaterialState>{MaterialState.disabled});
expect(count, 1); expect(count, 1);
}); });
testWidgets('icon color can be different from the text color', (WidgetTester tester) async {
final Key iconButtonKey = UniqueKey();
const ColorScheme colorScheme = ColorScheme.light();
final ThemeData theme = ThemeData.from(colorScheme: colorScheme);
await tester.pumpWidget(
MaterialApp(
theme: theme,
home: Center(
child: TextButton.icon(
key: iconButtonKey,
style: TextButton.styleFrom(iconColor: Colors.red),
icon: const Icon(Icons.add),
onPressed: () {},
label: const Text('button'),
),
),
),
);
Finder buttonMaterial = find.descendant(
of: find.byKey(iconButtonKey),
matching: find.byType(Material),
);
Material material = tester.widget<Material>(buttonMaterial);
expect(material.textStyle!.color, colorScheme.primary);
Color? iconColor() => _iconStyle(tester, Icons.add)?.color;
expect(iconColor(), equals(Colors.red));
// disabled button
await tester.pumpWidget(
MaterialApp(
theme: theme,
home: Center(
child: TextButton.icon(
key: iconButtonKey,
style: TextButton.styleFrom(iconColor: Colors.red, disabledIconColor: Colors.blue),
icon: const Icon(Icons.add),
onPressed: null,
label: const Text('button'),
),
),
),
);
buttonMaterial = find.descendant(
of: find.byKey(iconButtonKey),
matching: find.byType(Material),
);
material = tester.widget<Material>(buttonMaterial);
expect(material.textStyle!.color, colorScheme.onSurface.withOpacity(0.38));
expect(iconColor(), equals(Colors.blue));
});
} }
TextStyle? _iconStyle(WidgetTester tester, IconData icon) { TextStyle? _iconStyle(WidgetTester tester, IconData icon) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment