Unverified Commit bb3b45a7 authored by Hans Muller's avatar Hans Muller Committed by GitHub

Reland "ChipThemeData is now conventional" (#94179)

parent 72d4c72d
......@@ -225,8 +225,15 @@ abstract class DeletableChipAttributes {
/// {@end-tool}
VoidCallback? get onDeleted;
/// The [Color] for the delete icon. The default is based on the ambient
/// [IconThemeData.color].
/// Used to define the delete icon's color with an [IconTheme] that
/// contains the icon.
///
/// The default is `Color(0xde000000)`
/// (slightly transparent black) for light themes, and `Color(0xdeffffff)`
/// (slightly transparent white) for dark themes.
///
/// The delete icon appears if [DeletableChipAttributes.onDeleted] is
/// non-null.
Color? get deleteIconColor;
/// Whether to use a tooltip on the chip's delete button showing the
......@@ -423,7 +430,8 @@ abstract class DisabledChipAttributes {
/// Defaults to true. Cannot be null.
bool get isEnabled;
/// Color to be used for the chip's background indicating that it is disabled.
/// The color used for the chip's background to indicate that it is not
/// enabled.
///
/// The chip is disabled when [isEnabled] is false, or all three of
/// [SelectableChipAttributes.onSelected], [TappableChipAttributes.onPressed],
......@@ -1708,25 +1716,35 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
widget.onPressed?.call();
}
OutlinedBorder _getShape(ChipThemeData theme) {
OutlinedBorder _getShape(ThemeData theme, ChipThemeData chipTheme, ChipThemeData chipDefaults) {
final BorderSide? resolvedSide = MaterialStateProperty.resolveAs<BorderSide?>(widget.side, materialStates)
?? MaterialStateProperty.resolveAs<BorderSide?>(theme.side, materialStates);
?? MaterialStateProperty.resolveAs<BorderSide?>(chipTheme.side, materialStates)
?? MaterialStateProperty.resolveAs<BorderSide?>(chipDefaults.side, materialStates);
final OutlinedBorder resolvedShape = MaterialStateProperty.resolveAs<OutlinedBorder?>(widget.shape, materialStates)
?? MaterialStateProperty.resolveAs<OutlinedBorder?>(theme.shape, materialStates)
?? MaterialStateProperty.resolveAs<OutlinedBorder?>(chipTheme.shape, materialStates)
?? MaterialStateProperty.resolveAs<OutlinedBorder?>(chipDefaults.shape, materialStates)
?? const StadiumBorder();
return resolvedShape.copyWith(side: resolvedSide);
}
/// Picks between three different colors, depending upon the state of two
/// different animations.
Color? getBackgroundColor(ChipThemeData theme) {
Color? _getBackgroundColor(ThemeData theme, ChipThemeData chipTheme, ChipThemeData chipDefaults) {
final ColorTween backgroundTween = ColorTween(
begin: widget.disabledColor ?? theme.disabledColor,
end: widget.backgroundColor ?? theme.backgroundColor,
begin: widget.disabledColor
?? chipTheme.disabledColor
?? theme.disabledColor,
end: widget.backgroundColor
?? chipTheme.backgroundColor
?? theme.chipTheme.backgroundColor
?? chipDefaults.backgroundColor,
);
final ColorTween selectTween = ColorTween(
begin: backgroundTween.evaluate(enableController),
end: widget.selectedColor ?? theme.selectedColor,
end: widget.selectedColor
?? chipTheme.selectedColor
?? theme.chipTheme.selectedColor
?? chipDefaults.selectedColor,
);
return selectTween.evaluate(selectionFade);
}
......@@ -1788,6 +1806,7 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
BuildContext context,
ThemeData theme,
ChipThemeData chipTheme,
ChipThemeData chipDefaults,
) {
if (!hasDeleteButton) {
return null;
......@@ -1796,7 +1815,9 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
container: true,
button: true,
child: _wrapWithTooltip(
tooltip: widget.useDeleteButtonTooltip ? widget.deleteButtonTooltipMessage ?? MaterialLocalizations.of(context).deleteButtonTooltip : null,
tooltip: widget.useDeleteButtonTooltip
? widget.deleteButtonTooltipMessage ?? MaterialLocalizations.of(context).deleteButtonTooltip
: null,
enabled: widget.onDeleted != null,
child: InkWell(
// Radius should be slightly less than the full size of the chip.
......@@ -1806,7 +1827,10 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
onTap: widget.isEnabled ? widget.onDeleted : null,
child: IconTheme(
data: theme.iconTheme.copyWith(
color: widget.deleteIconColor ?? chipTheme.deleteIconColor,
color: widget.deleteIconColor
?? chipTheme.deleteIconColor
?? theme.chipTheme.deleteIconColor
?? chipDefaults.deleteIconColor,
),
child: widget.deleteIcon,
),
......@@ -1838,19 +1862,53 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
final ThemeData theme = Theme.of(context);
final ChipThemeData chipTheme = ChipTheme.of(context);
final Brightness brightness = chipTheme.brightness ?? theme.brightness;
final ChipThemeData chipDefaults = ChipThemeData.fromDefaults(
brightness: brightness,
secondaryColor: brightness == Brightness.dark ? Colors.tealAccent[200]! : theme.primaryColor,
labelStyle: theme.textTheme.bodyText1!,
);
final TextDirection? textDirection = Directionality.maybeOf(context);
final OutlinedBorder resolvedShape = _getShape(chipTheme);
final double elevation = widget.elevation ?? chipTheme.elevation ?? _defaultElevation;
final double pressElevation = widget.pressElevation ?? chipTheme.pressElevation ?? _defaultPressElevation;
final Color shadowColor = widget.shadowColor ?? chipTheme.shadowColor ?? _defaultShadowColor;
final Color selectedShadowColor = widget.selectedShadowColor ?? chipTheme.selectedShadowColor ?? _defaultShadowColor;
final Color? checkmarkColor = widget.checkmarkColor ?? chipTheme.checkmarkColor;
final bool showCheckmark = widget.showCheckmark ?? chipTheme.showCheckmark ?? true;
final TextStyle effectiveLabelStyle = chipTheme.labelStyle.merge(widget.labelStyle);
final OutlinedBorder resolvedShape = _getShape(theme, chipTheme, chipDefaults);
final double elevation = widget.elevation
?? chipTheme.elevation
?? theme.chipTheme.elevation
?? _defaultElevation;
final double pressElevation = widget.pressElevation
?? chipTheme.pressElevation
?? theme.chipTheme.pressElevation
?? _defaultPressElevation;
final Color shadowColor = widget.shadowColor
?? chipTheme.shadowColor
?? theme.chipTheme.shadowColor
?? _defaultShadowColor;
final Color selectedShadowColor = widget.selectedShadowColor
?? chipTheme.selectedShadowColor
?? theme.chipTheme.selectedShadowColor
?? _defaultShadowColor;
final Color? checkmarkColor = widget.checkmarkColor
?? chipTheme.checkmarkColor
?? theme.chipTheme.checkmarkColor;
final bool showCheckmark = widget.showCheckmark
?? chipTheme.showCheckmark
?? theme.chipTheme.showCheckmark
?? true;
final EdgeInsetsGeometry padding = widget.padding
?? chipTheme.padding
?? theme.chipTheme.padding
?? chipDefaults.padding!;
final TextStyle? labelStyle = widget.labelStyle
?? chipTheme.labelStyle
?? theme.chipTheme.labelStyle;
final EdgeInsetsGeometry labelPadding = widget.labelPadding
?? chipTheme.labelPadding
?? theme.chipTheme.labelPadding
?? _defaultLabelPadding;
final TextStyle effectiveLabelStyle = chipDefaults.labelStyle!.merge(labelStyle);
final Color? resolvedLabelColor = MaterialStateProperty.resolveAs<Color?>(effectiveLabelStyle.color, materialStates);
final TextStyle resolvedLabelStyle = effectiveLabelStyle.copyWith(color: resolvedLabelColor);
final EdgeInsetsGeometry labelPadding = widget.labelPadding ?? chipTheme.labelPadding ?? _defaultLabelPadding;
Widget result = Material(
elevation: isTapping ? pressElevation : elevation,
......@@ -1874,7 +1932,7 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
return Container(
decoration: ShapeDecoration(
shape: resolvedShape,
color: getBackgroundColor(chipTheme),
color: _getBackgroundColor(theme, chipTheme, chipDefaults),
),
child: child,
);
......@@ -1900,10 +1958,10 @@ class _RawChipState extends State<RawChip> with MaterialStateMixin, TickerProvid
deleteIcon: AnimatedSwitcher(
duration: _kDrawerDuration,
switchInCurve: Curves.fastOutSlowIn,
child: _buildDeleteIcon(context, theme, chipTheme),
child: _buildDeleteIcon(context, theme, chipTheme, chipDefaults),
),
brightness: chipTheme.brightness,
padding: (widget.padding ?? chipTheme.padding).resolve(textDirection),
brightness: brightness,
padding: padding.resolve(textDirection),
visualDensity: widget.visualDensity ?? theme.visualDensity,
labelPadding: labelPadding.resolve(textDirection),
showAvatar: hasAvatar,
......@@ -2572,6 +2630,7 @@ class _RenderChip extends RenderBox {
overallSize.width + theme.padding.horizontal,
overallSize.height + theme.padding.vertical,
);
return _ChipSizes(
size: constraints.constrain(paddedSize),
overall: overallSize,
......
......@@ -472,11 +472,7 @@ class ThemeData with Diagnosticable {
bottomSheetTheme ??= const BottomSheetThemeData();
buttonBarTheme ??= const ButtonBarThemeData();
cardTheme ??= const CardTheme();
chipTheme ??= ChipThemeData.fromDefaults(
secondaryColor: isDark ? Colors.tealAccent[200]! : primaryColor,
brightness: colorScheme.brightness,
labelStyle: textTheme.bodyText1!,
);
chipTheme ??= const ChipThemeData();
checkboxTheme ??= const CheckboxThemeData();
dataTableTheme ??= const DataTableThemeData();
dialogTheme ??= const DialogTheme();
......
......@@ -270,6 +270,80 @@ Finder findTooltipContainer(String tooltipText) {
}
void main() {
testWidgets('Chip defaults', (WidgetTester tester) async {
Widget buildFrame(Brightness brightness) {
return MaterialApp(
theme: ThemeData(brightness: brightness),
home: Scaffold(
body: Center(
child: Chip(
avatar: const CircleAvatar(child: Text('A')),
label: const Text('Chip A'),
onDeleted: () { },
),
),
),
);
}
await tester.pumpWidget(buildFrame(Brightness.light));
expect(getMaterialBox(tester), paints..path(color: const Color(0x1f000000)));
expect(tester.getSize(find.byType(Chip)), const Size(156.0, 48.0));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, const StadiumBorder());
expect(getIconData(tester).color?.value, 0xffffffff);
expect(getIconData(tester).opacity, null);
expect(getIconData(tester).size, null);
expect(getLabelStyle(tester).style.color?.value, 0xde000000);
await tester.pumpWidget(buildFrame(Brightness.dark));
await tester.pumpAndSettle(); // Theme transition animation
expect(getMaterialBox(tester), paints..path(color: const Color(0x1fffffff)));
expect(tester.getSize(find.byType(Chip)), const Size(156.0, 48.0));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, const StadiumBorder());
expect(getIconData(tester).color?.value, 0xffffffff);
expect(getIconData(tester).opacity, null);
expect(getIconData(tester).size, null);
expect(getLabelStyle(tester).style.color?.value, 0xffffffff);
});
testWidgets('ChoiceChip defaults', (WidgetTester tester) async {
Widget buildFrame(Brightness brightness) {
return MaterialApp(
theme: ThemeData(brightness: brightness),
home: const Scaffold(
body: Center(
child: ChoiceChip(
label: Text('Chip A'),
selected: true,
),
),
),
);
}
await tester.pumpWidget(buildFrame(Brightness.light));
expect(getMaterialBox(tester), paints..path(color: const Color(0x3d000000)));
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, const StadiumBorder());
expect(getLabelStyle(tester).style.color?.value, 0xde000000);
await tester.pumpWidget(buildFrame(Brightness.dark));
await tester.pumpAndSettle(); // Theme transition animation
expect(getMaterialBox(tester), paints..path(color: const Color(0x3dffffff)));
expect(tester.getSize(find.byType(ChoiceChip)), const Size(108.0, 48.0));
expect(getMaterial(tester).color, null);
expect(getMaterial(tester).elevation, 0);
expect(getMaterial(tester).shape, const StadiumBorder());
expect(getLabelStyle(tester).style.color?.value, 0xdeffffff);
});
testWidgets('Chip control test', (WidgetTester tester) async {
final FeedbackTester feedback = FeedbackTester();
final List<String> deletedChipLabels = <String>[];
......@@ -1697,7 +1771,11 @@ void main() {
platform: TargetPlatform.android,
primarySwatch: Colors.blue,
);
final ChipThemeData defaultChipTheme = themeData.chipTheme;
final ChipThemeData defaultChipTheme = ChipThemeData.fromDefaults(
brightness: themeData.brightness,
secondaryColor: Colors.blue,
labelStyle: themeData.textTheme.bodyText1!,
);
bool value = false;
Widget buildApp({
ChipThemeData? chipTheme,
......
......@@ -51,16 +51,6 @@ void main() {
expect(darkTheme.primaryTextTheme.headline6!.color, typography.white.headline6!.color);
});
test('Default chip label style gets a default bodyText1 if textTheme.bodyText1 is null', () {
const TextTheme noBodyText1TextTheme = TextTheme();
final ThemeData lightTheme = ThemeData(brightness: Brightness.light, textTheme: noBodyText1TextTheme);
final ThemeData darkTheme = ThemeData(brightness: Brightness.dark, textTheme: noBodyText1TextTheme);
final Typography typography = Typography.material2018(platform: lightTheme.platform);
expect(lightTheme.chipTheme.labelStyle.color, equals(typography.black.bodyText1!.color!.withAlpha(0xde)));
expect(darkTheme.chipTheme.labelStyle.color, equals(typography.white.bodyText1!.color!.withAlpha(0xde)));
});
test('Default icon theme contrasts with brightness', () {
final ThemeData lightTheme = ThemeData(brightness: Brightness.light);
final ThemeData darkTheme = ThemeData(brightness: Brightness.dark);
......
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