Unverified Commit c089c19f authored by Xilai Zhang's avatar Xilai Zhang Committed by GitHub

Revert "[reland] Add Material 3 support for `ListTile` - Part 1 (#116963)" (#117756)

This reverts commit 57fb36ee.
parent cee9ec52
...@@ -35,7 +35,6 @@ import 'package:gen_defaults/filter_chip_template.dart'; ...@@ -35,7 +35,6 @@ 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/list_tile_template.dart';
import 'package:gen_defaults/menu_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_drawer_template.dart'; import 'package:gen_defaults/navigation_drawer_template.dart';
...@@ -156,7 +155,6 @@ Future<void> main(List<String> args) async { ...@@ -156,7 +155,6 @@ Future<void> main(List<String> args) async {
FilterChipTemplate('FilterChip', '$materialLib/filter_chip.dart', tokens).updateFile(); FilterChipTemplate('FilterChip', '$materialLib/filter_chip.dart', tokens).updateFile();
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();
ListTileTemplate('LisTile', '$materialLib/list_tile.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(); MenuTemplate('Menu', '$materialLib/menu_anchor.dart', tokens).updateFile();
NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile(); NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.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 ListTileTemplate extends TokenTemplate {
const ListTileTemplate(super.blockName, super.fileName, super.tokens);
@override
String generate() => '''
class _${blockName}DefaultsM3 extends ListTileThemeData {
const _${blockName}DefaultsM3(this.context)
: super(shape: ${shape("md.comp.list.list-item.container")});
final BuildContext context;
@override
Color? get tileColor => ${componentColor("md.comp.list.list-item.container")};
@override
TextStyle? get titleTextStyle => ${textStyle("md.comp.list.list-item.label-text")};
@override
TextStyle? get subtitleTextStyle => ${textStyle("md.comp.list.list-item.supporting-text")};
@override
TextStyle? get leadingAndTrailingTextStyle => ${textStyle("md.comp.list.list-item.trailing-supporting-text")};
@override
Color? get selectedColor => ${componentColor('md.comp.list.list-item.selected.trailing-icon')};
@override
Color? get iconColor => ${componentColor('md.comp.list.list-item.unselected.trailing-icon')};
}
''';
}
...@@ -15,7 +15,6 @@ import 'ink_decoration.dart'; ...@@ -15,7 +15,6 @@ import 'ink_decoration.dart';
import 'ink_well.dart'; import 'ink_well.dart';
import 'list_tile_theme.dart'; import 'list_tile_theme.dart';
import 'material_state.dart'; import 'material_state.dart';
import 'text_theme.dart';
import 'theme.dart'; import 'theme.dart';
import 'theme_data.dart'; import 'theme_data.dart';
...@@ -279,9 +278,6 @@ class ListTile extends StatelessWidget { ...@@ -279,9 +278,6 @@ class ListTile extends StatelessWidget {
this.selectedColor, this.selectedColor,
this.iconColor, this.iconColor,
this.textColor, this.textColor,
this.titleTextStyle,
this.subtitleTextStyle,
this.leadingAndTrailingTextStyle,
this.contentPadding, this.contentPadding,
this.enabled = true, this.enabled = true,
this.onTap, this.onTap,
...@@ -368,8 +364,6 @@ class ListTile extends StatelessWidget { ...@@ -368,8 +364,6 @@ class ListTile extends StatelessWidget {
/// If this property is null then its value is based on [ListTileTheme.dense]. /// If this property is null then its value is based on [ListTileTheme.dense].
/// ///
/// Dense list tiles default to a smaller height. /// Dense list tiles default to a smaller height.
///
/// It is not recommended to set [dense] to true when [ThemeData.useMaterial3] is true.
final bool? dense; final bool? dense;
/// Defines how compact the list tile's layout will be. /// Defines how compact the list tile's layout will be.
...@@ -427,28 +421,6 @@ class ListTile extends StatelessWidget { ...@@ -427,28 +421,6 @@ class ListTile extends StatelessWidget {
/// [ListTileThemeData]. /// [ListTileThemeData].
final Color? textColor; final Color? textColor;
/// The text style for ListTile's [title].
///
/// If this property is null, then [ListTileThemeData.titleTextStyle] is used.
/// If that is also null and [ThemeData.useMaterial3] is true, [TextTheme.bodyLarge]
/// will be used. Otherwise, If ListTile style is [ListTileStyle.list],
/// [TextTheme.titleMedium] will be used and if ListTile style is [ListTileStyle.drawer],
/// [TextTheme.bodyLarge] will be used.
final TextStyle? titleTextStyle;
/// The text style for ListTile's [subtitle].
///
/// If this property is null, then [ListTileThemeData.subtitleTextStyle] is used.
/// If that is also null, [TextTheme.bodyMedium] will be used.
final TextStyle? subtitleTextStyle;
/// The text style for ListTile's [leading] and [trailing].
///
/// If this property is null, then [ListTileThemeData.leadingAndTrailingTextStyle] is used.
/// If that is also null and [ThemeData.useMaterial3] is true, [TextTheme.labelSmall]
/// will be used, otherwise [TextTheme.bodyMedium] will be used.
final TextStyle? leadingAndTrailingTextStyle;
/// Defines the font used for the [title]. /// Defines the font used for the [title].
/// ///
/// If this property is null then [ListTileThemeData.style] is used. If that /// If this property is null then [ListTileThemeData.style] is used. If that
...@@ -616,16 +588,91 @@ class ListTile extends StatelessWidget { ...@@ -616,16 +588,91 @@ class ListTile extends StatelessWidget {
]; ];
} }
Color? _iconColor(ThemeData theme, ListTileThemeData tileTheme) {
if (!enabled) {
return theme.disabledColor;
}
if (selected) {
return selectedColor ?? tileTheme.selectedColor ?? theme.listTileTheme.selectedColor ?? theme.colorScheme.primary;
}
final Color? color = iconColor
?? tileTheme.iconColor
?? theme.listTileTheme.iconColor
// If [ThemeData.useMaterial3] is set to true the disabled icon color
// will be set to Theme.colorScheme.onSurface(0.38), if false, defaults to null,
// as described in: https://m3.material.io/components/icon-buttons/specs.
?? (theme.useMaterial3 ? theme.colorScheme.onSurface.withOpacity(0.38) : null);
if (color != null) {
return color;
}
switch (theme.brightness) {
case Brightness.light:
// For the sake of backwards compatibility, the default for unselected
// tiles is Colors.black45 rather than colorScheme.onSurface.withAlpha(0x73).
return Colors.black45;
case Brightness.dark:
return null; // null - use current icon theme color
}
}
Color? _textColor(ThemeData theme, ListTileThemeData tileTheme, Color? defaultColor) {
if (!enabled) {
return theme.disabledColor;
}
if (selected) {
return selectedColor ?? tileTheme.selectedColor ?? theme.listTileTheme.selectedColor ?? theme.colorScheme.primary;
}
return textColor ?? tileTheme.textColor ?? theme.listTileTheme.textColor ?? defaultColor;
}
bool _isDenseLayout(ThemeData theme, ListTileThemeData tileTheme) { bool _isDenseLayout(ThemeData theme, ListTileThemeData tileTheme) {
return dense ?? tileTheme.dense ?? theme.listTileTheme.dense ?? false; return dense ?? tileTheme.dense ?? theme.listTileTheme.dense ?? false;
} }
// TODO(TahaTesser): Refactor this to support list tile states. TextStyle _titleTextStyle(ThemeData theme, ListTileThemeData tileTheme) {
Color _tileBackgroundColor(ThemeData theme, ListTileThemeData tileTheme, ListTileThemeData defaults) { final TextStyle textStyle;
switch(style ?? tileTheme.style ?? theme.listTileTheme.style ?? ListTileStyle.list) {
case ListTileStyle.drawer:
textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyLarge!;
break;
case ListTileStyle.list:
textStyle = theme.useMaterial3 ? theme.textTheme.titleMedium! : theme.textTheme.titleMedium!;
break;
}
final Color? color = _textColor(theme, tileTheme, textStyle.color);
return _isDenseLayout(theme, tileTheme)
? textStyle.copyWith(fontSize: 13.0, color: color)
: textStyle.copyWith(color: color);
}
TextStyle _subtitleTextStyle(ThemeData theme, ListTileThemeData tileTheme) {
final TextStyle textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyMedium!;
final Color? color = _textColor(
theme,
tileTheme,
theme.useMaterial3 ? theme.textTheme.bodySmall!.color : theme.textTheme.bodySmall!.color,
);
return _isDenseLayout(theme, tileTheme)
? textStyle.copyWith(color: color, fontSize: 12.0)
: textStyle.copyWith(color: color);
}
TextStyle _trailingAndLeadingTextStyle(ThemeData theme, ListTileThemeData tileTheme) {
final TextStyle textStyle = theme.useMaterial3 ? theme.textTheme.bodyMedium! : theme.textTheme.bodyMedium!;
final Color? color = _textColor(theme, tileTheme, textStyle.color);
return textStyle.copyWith(color: color);
}
Color _tileBackgroundColor(ThemeData theme, ListTileThemeData tileTheme) {
final Color? color = selected final Color? color = selected
? selectedTileColor ?? tileTheme.selectedTileColor ?? theme.listTileTheme.selectedTileColor ? selectedTileColor ?? tileTheme.selectedTileColor ?? theme.listTileTheme.selectedTileColor
: tileColor ?? tileTheme.tileColor ?? theme.listTileTheme.tileColor; : tileColor ?? tileTheme.tileColor ?? theme.listTileTheme.tileColor;
return color ?? defaults.tileColor!; return color ?? Colors.transparent;
} }
@override @override
...@@ -633,63 +680,23 @@ class ListTile extends StatelessWidget { ...@@ -633,63 +680,23 @@ class ListTile extends StatelessWidget {
assert(debugCheckHasMaterial(context)); assert(debugCheckHasMaterial(context));
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
final ListTileThemeData tileTheme = ListTileTheme.of(context); final ListTileThemeData tileTheme = ListTileTheme.of(context);
final ListTileStyle listTileStyle = style final IconThemeData iconThemeData = IconThemeData(color: _iconColor(theme, tileTheme));
?? tileTheme.style
?? theme.listTileTheme.style
?? ListTileStyle.list;
final ListTileThemeData defaults = theme.useMaterial3
? _LisTileDefaultsM3(context)
: _LisTileDefaultsM2(context, listTileStyle);
final Set<MaterialState> states = <MaterialState>{
if (!enabled) MaterialState.disabled,
if (selected) MaterialState.selected,
};
Color? resolveColor(Color? explicitColor, Color? selectedColor, Color? enabledColor, [Color? disabledColor]) { TextStyle? leadingAndTrailingTextStyle;
return _IndividualOverrides(
explicitColor: explicitColor,
selectedColor: selectedColor,
enabledColor: enabledColor,
disabledColor: disabledColor,
).resolve(states);
}
final Color? effectiveIconColor = resolveColor(iconColor, selectedColor, iconColor)
?? resolveColor(tileTheme.iconColor, tileTheme.selectedColor, tileTheme.iconColor)
?? resolveColor(theme.listTileTheme.iconColor, theme.listTileTheme.selectedColor, theme.listTileTheme.iconColor)
?? resolveColor(defaults.iconColor, defaults.selectedColor, defaults.iconColor, theme.disabledColor);
final Color? effectiveColor = resolveColor(textColor, selectedColor, textColor)
?? resolveColor(tileTheme.textColor, tileTheme.selectedColor, tileTheme.textColor)
?? resolveColor(theme.listTileTheme.textColor, theme.listTileTheme.selectedColor, theme.listTileTheme.textColor)
?? resolveColor(defaults.textColor, defaults.selectedColor, defaults.textColor, theme.disabledColor);
final IconThemeData iconThemeData = IconThemeData(color: effectiveIconColor);
TextStyle? leadingAndTrailingStyle;
if (leading != null || trailing != null) { if (leading != null || trailing != null) {
leadingAndTrailingStyle = leadingAndTrailingTextStyle leadingAndTrailingTextStyle = _trailingAndLeadingTextStyle(theme, tileTheme);
?? tileTheme.leadingAndTrailingTextStyle
?? defaults.leadingAndTrailingTextStyle!;
final Color? leadingAndTrailingTextColor = effectiveColor;
leadingAndTrailingStyle = leadingAndTrailingStyle.copyWith(color: leadingAndTrailingTextColor);
} }
Widget? leadingIcon; Widget? leadingIcon;
if (leading != null) { if (leading != null) {
leadingIcon = AnimatedDefaultTextStyle( leadingIcon = AnimatedDefaultTextStyle(
style: leadingAndTrailingStyle!, style: leadingAndTrailingTextStyle!,
duration: kThemeChangeDuration, duration: kThemeChangeDuration,
child: leading!, child: leading!,
); );
} }
TextStyle titleStyle = titleTextStyle final TextStyle titleStyle = _titleTextStyle(theme, tileTheme);
?? tileTheme.titleTextStyle
?? defaults.titleTextStyle!;
final Color? titleColor = effectiveColor;
titleStyle = titleStyle.copyWith(
color: titleColor,
fontSize: _isDenseLayout(theme, tileTheme) ? 13.0 : null,
);
final Widget titleText = AnimatedDefaultTextStyle( final Widget titleText = AnimatedDefaultTextStyle(
style: titleStyle, style: titleStyle,
duration: kThemeChangeDuration, duration: kThemeChangeDuration,
...@@ -699,14 +706,7 @@ class ListTile extends StatelessWidget { ...@@ -699,14 +706,7 @@ class ListTile extends StatelessWidget {
Widget? subtitleText; Widget? subtitleText;
TextStyle? subtitleStyle; TextStyle? subtitleStyle;
if (subtitle != null) { if (subtitle != null) {
subtitleStyle = subtitleTextStyle subtitleStyle = _subtitleTextStyle(theme, tileTheme);
?? tileTheme.subtitleTextStyle
?? defaults.subtitleTextStyle!;
final Color? subtitleColor = effectiveColor ?? theme.textTheme.bodySmall!.color;
subtitleStyle = subtitleStyle.copyWith(
color: subtitleColor,
fontSize: _isDenseLayout(theme, tileTheme) ? 12.0 : null,
);
subtitleText = AnimatedDefaultTextStyle( subtitleText = AnimatedDefaultTextStyle(
style: subtitleStyle, style: subtitleStyle,
duration: kThemeChangeDuration, duration: kThemeChangeDuration,
...@@ -717,7 +717,7 @@ class ListTile extends StatelessWidget { ...@@ -717,7 +717,7 @@ class ListTile extends StatelessWidget {
Widget? trailingIcon; Widget? trailingIcon;
if (trailing != null) { if (trailing != null) {
trailingIcon = AnimatedDefaultTextStyle( trailingIcon = AnimatedDefaultTextStyle(
style: leadingAndTrailingStyle!, style: leadingAndTrailingTextStyle!,
duration: kThemeChangeDuration, duration: kThemeChangeDuration,
child: trailing!, child: trailing!,
); );
...@@ -728,13 +728,15 @@ class ListTile extends StatelessWidget { ...@@ -728,13 +728,15 @@ class ListTile extends StatelessWidget {
final EdgeInsets resolvedContentPadding = contentPadding?.resolve(textDirection) final EdgeInsets resolvedContentPadding = contentPadding?.resolve(textDirection)
?? tileTheme.contentPadding?.resolve(textDirection) ?? tileTheme.contentPadding?.resolve(textDirection)
?? defaultContentPadding; ?? defaultContentPadding;
// Show basic cursor when ListTile isn't enabled or gesture callbacks are null.
final Set<MaterialState> mouseStates = <MaterialState>{ final Set<MaterialState> states = <MaterialState>{
if (!enabled || (onTap == null && onLongPress == null)) MaterialState.disabled, if (!enabled || (onTap == null && onLongPress == null)) MaterialState.disabled,
if (selected) MaterialState.selected,
}; };
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor?>(mouseCursor, mouseStates)
?? tileTheme.mouseCursor?.resolve(mouseStates) final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor?>(mouseCursor, states)
?? MaterialStateMouseCursor.clickable.resolve(mouseStates); ?? tileTheme.mouseCursor?.resolve(states)
?? MaterialStateMouseCursor.clickable.resolve(states);
return InkWell( return InkWell(
customBorder: shape ?? tileTheme.shape, customBorder: shape ?? tileTheme.shape,
...@@ -755,7 +757,7 @@ class ListTile extends StatelessWidget { ...@@ -755,7 +757,7 @@ class ListTile extends StatelessWidget {
child: Ink( child: Ink(
decoration: ShapeDecoration( decoration: ShapeDecoration(
shape: shape ?? tileTheme.shape ?? const Border(), shape: shape ?? tileTheme.shape ?? const Border(),
color: _tileBackgroundColor(theme, tileTheme, defaults), color: _tileBackgroundColor(theme, tileTheme),
), ),
child: SafeArea( child: SafeArea(
top: false, top: false,
...@@ -772,8 +774,8 @@ class ListTile extends StatelessWidget { ...@@ -772,8 +774,8 @@ class ListTile extends StatelessWidget {
visualDensity: visualDensity ?? tileTheme.visualDensity ?? theme.visualDensity, visualDensity: visualDensity ?? tileTheme.visualDensity ?? theme.visualDensity,
isThreeLine: isThreeLine, isThreeLine: isThreeLine,
textDirection: textDirection, textDirection: textDirection,
titleBaselineType: titleStyle.textBaseline ?? defaults.titleTextStyle!.textBaseline!, titleBaselineType: titleStyle.textBaseline!,
subtitleBaselineType: subtitleStyle?.textBaseline ?? defaults.subtitleTextStyle!.textBaseline!, subtitleBaselineType: subtitleStyle?.textBaseline,
horizontalTitleGap: horizontalTitleGap ?? tileTheme.horizontalTitleGap ?? 16, horizontalTitleGap: horizontalTitleGap ?? tileTheme.horizontalTitleGap ?? 16,
minVerticalPadding: minVerticalPadding ?? tileTheme.minVerticalPadding ?? 4, minVerticalPadding: minVerticalPadding ?? tileTheme.minVerticalPadding ?? 4,
minLeadingWidth: minLeadingWidth ?? tileTheme.minLeadingWidth ?? 40, minLeadingWidth: minLeadingWidth ?? tileTheme.minLeadingWidth ?? 40,
...@@ -819,36 +821,6 @@ class ListTile extends StatelessWidget { ...@@ -819,36 +821,6 @@ class ListTile extends StatelessWidget {
} }
} }
class _IndividualOverrides extends MaterialStateProperty<Color?> {
_IndividualOverrides({
this.explicitColor,
this.enabledColor,
this.selectedColor,
this.disabledColor,
});
final Color? explicitColor;
final Color? enabledColor;
final Color? selectedColor;
final Color? disabledColor;
@override
Color? resolve(Set<MaterialState> states) {
if (explicitColor is MaterialStateColor) {
return MaterialStateProperty.resolveAs<Color?>(explicitColor, states);
}
if (states.contains(MaterialState.disabled)) {
return disabledColor;
}
if (states.contains(MaterialState.selected)) {
return selectedColor;
}
return enabledColor;
}
}
// Identifies the children of a _ListTileElement. // Identifies the children of a _ListTileElement.
enum _ListTileSlot { enum _ListTileSlot {
leading, leading,
...@@ -1371,87 +1343,3 @@ class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_ ...@@ -1371,87 +1343,3 @@ class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_
return false; return false;
} }
} }
class _LisTileDefaultsM2 extends ListTileThemeData {
_LisTileDefaultsM2(this.context, ListTileStyle style)
: _themeData = Theme.of(context),
_textTheme = Theme.of(context).textTheme,
super(
shape: const Border(),
style: style,
);
final BuildContext context;
final ThemeData _themeData;
final TextTheme _textTheme;
@override
Color? get tileColor => Colors.transparent;
@override
TextStyle? get titleTextStyle {
switch (style!) {
case ListTileStyle.drawer:
return _textTheme.bodyLarge;
case ListTileStyle.list:
return _textTheme.titleMedium;
}
}
@override
TextStyle? get subtitleTextStyle => _textTheme.bodyMedium;
@override
TextStyle? get leadingAndTrailingTextStyle => _textTheme.bodyMedium;
@override
Color? get selectedColor => _themeData.colorScheme.primary;
@override
Color? get iconColor {
switch (_themeData.brightness) {
case Brightness.light:
// For the sake of backwards compatibility, the default for unselected
// tiles is Colors.black45 rather than colorScheme.onSurface.withAlpha(0x73).
return Colors.black45;
case Brightness.dark:
return null; // null, Use current icon theme color
}
}
}
// BEGIN GENERATED TOKEN PROPERTIES - LisTile
// 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.
// Token database version: v0_143
class _LisTileDefaultsM3 extends ListTileThemeData {
const _LisTileDefaultsM3(this.context)
: super(shape: const RoundedRectangleBorder());
final BuildContext context;
@override
Color? get tileColor => Theme.of(context).colorScheme.surface;
@override
TextStyle? get titleTextStyle => Theme.of(context).textTheme.bodyLarge;
@override
TextStyle? get subtitleTextStyle => Theme.of(context).textTheme.bodyMedium;
@override
TextStyle? get leadingAndTrailingTextStyle => Theme.of(context).textTheme.labelSmall;
@override
Color? get selectedColor => Theme.of(context).colorScheme.primary;
@override
Color? get iconColor => Theme.of(context).colorScheme.onSurface;
}
// END GENERATED TOKEN PROPERTIES - LisTile
...@@ -51,9 +51,6 @@ class ListTileThemeData with Diagnosticable { ...@@ -51,9 +51,6 @@ class ListTileThemeData with Diagnosticable {
this.selectedColor, this.selectedColor,
this.iconColor, this.iconColor,
this.textColor, this.textColor,
this.titleTextStyle,
this.subtitleTextStyle,
this.leadingAndTrailingTextStyle,
this.contentPadding, this.contentPadding,
this.tileColor, this.tileColor,
this.selectedTileColor, this.selectedTileColor,
...@@ -83,15 +80,6 @@ class ListTileThemeData with Diagnosticable { ...@@ -83,15 +80,6 @@ class ListTileThemeData with Diagnosticable {
/// Overrides the default value of [ListTile.textColor]. /// Overrides the default value of [ListTile.textColor].
final Color? textColor; final Color? textColor;
/// Overrides the default value of [ListTile.titleTextStyle].
final TextStyle? titleTextStyle;
/// Overrides the default value of [ListTile.subtitleTextStyle].
final TextStyle? subtitleTextStyle;
/// Overrides the default value of [ListTile.leadingAndTrailingTextStyle].
final TextStyle? leadingAndTrailingTextStyle;
/// Overrides the default value of [ListTile.contentPadding]. /// Overrides the default value of [ListTile.contentPadding].
final EdgeInsetsGeometry? contentPadding; final EdgeInsetsGeometry? contentPadding;
...@@ -128,9 +116,6 @@ class ListTileThemeData with Diagnosticable { ...@@ -128,9 +116,6 @@ class ListTileThemeData with Diagnosticable {
Color? selectedColor, Color? selectedColor,
Color? iconColor, Color? iconColor,
Color? textColor, Color? textColor,
TextStyle? titleTextStyle,
TextStyle? subtitleTextStyle,
TextStyle? leadingAndTrailingTextStyle,
EdgeInsetsGeometry? contentPadding, EdgeInsetsGeometry? contentPadding,
Color? tileColor, Color? tileColor,
Color? selectedTileColor, Color? selectedTileColor,
...@@ -149,9 +134,6 @@ class ListTileThemeData with Diagnosticable { ...@@ -149,9 +134,6 @@ class ListTileThemeData with Diagnosticable {
selectedColor: selectedColor ?? this.selectedColor, selectedColor: selectedColor ?? this.selectedColor,
iconColor: iconColor ?? this.iconColor, iconColor: iconColor ?? this.iconColor,
textColor: textColor ?? this.textColor, textColor: textColor ?? this.textColor,
titleTextStyle: titleTextStyle ?? this.titleTextStyle,
subtitleTextStyle: titleTextStyle ?? this.subtitleTextStyle,
leadingAndTrailingTextStyle: titleTextStyle ?? this.leadingAndTrailingTextStyle,
contentPadding: contentPadding ?? this.contentPadding, contentPadding: contentPadding ?? this.contentPadding,
tileColor: tileColor ?? this.tileColor, tileColor: tileColor ?? this.tileColor,
selectedTileColor: selectedTileColor ?? this.selectedTileColor, selectedTileColor: selectedTileColor ?? this.selectedTileColor,
...@@ -177,9 +159,6 @@ class ListTileThemeData with Diagnosticable { ...@@ -177,9 +159,6 @@ class ListTileThemeData with Diagnosticable {
selectedColor: Color.lerp(a?.selectedColor, b?.selectedColor, t), selectedColor: Color.lerp(a?.selectedColor, b?.selectedColor, t),
iconColor: Color.lerp(a?.iconColor, b?.iconColor, t), iconColor: Color.lerp(a?.iconColor, b?.iconColor, t),
textColor: Color.lerp(a?.textColor, b?.textColor, t), textColor: Color.lerp(a?.textColor, b?.textColor, t),
titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t),
subtitleTextStyle: TextStyle.lerp(a?.subtitleTextStyle, b?.subtitleTextStyle, t),
leadingAndTrailingTextStyle: TextStyle.lerp(a?.leadingAndTrailingTextStyle, b?.leadingAndTrailingTextStyle, t),
contentPadding: EdgeInsetsGeometry.lerp(a?.contentPadding, b?.contentPadding, t), contentPadding: EdgeInsetsGeometry.lerp(a?.contentPadding, b?.contentPadding, t),
tileColor: Color.lerp(a?.tileColor, b?.tileColor, t), tileColor: Color.lerp(a?.tileColor, b?.tileColor, t),
selectedTileColor: Color.lerp(a?.selectedTileColor, b?.selectedTileColor, t), selectedTileColor: Color.lerp(a?.selectedTileColor, b?.selectedTileColor, t),
...@@ -200,9 +179,6 @@ class ListTileThemeData with Diagnosticable { ...@@ -200,9 +179,6 @@ class ListTileThemeData with Diagnosticable {
selectedColor, selectedColor,
iconColor, iconColor,
textColor, textColor,
titleTextStyle,
subtitleTextStyle,
leadingAndTrailingTextStyle,
contentPadding, contentPadding,
tileColor, tileColor,
selectedTileColor, selectedTileColor,
...@@ -228,9 +204,6 @@ class ListTileThemeData with Diagnosticable { ...@@ -228,9 +204,6 @@ class ListTileThemeData with Diagnosticable {
&& other.style == style && other.style == style
&& other.selectedColor == selectedColor && other.selectedColor == selectedColor
&& other.iconColor == iconColor && other.iconColor == iconColor
&& other.titleTextStyle == titleTextStyle
&& other.subtitleTextStyle == subtitleTextStyle
&& other.leadingAndTrailingTextStyle == leadingAndTrailingTextStyle
&& other.textColor == textColor && other.textColor == textColor
&& other.contentPadding == contentPadding && other.contentPadding == contentPadding
&& other.tileColor == tileColor && other.tileColor == tileColor
...@@ -252,9 +225,6 @@ class ListTileThemeData with Diagnosticable { ...@@ -252,9 +225,6 @@ class ListTileThemeData with Diagnosticable {
properties.add(ColorProperty('selectedColor', selectedColor, defaultValue: null)); properties.add(ColorProperty('selectedColor', selectedColor, defaultValue: null));
properties.add(ColorProperty('iconColor', iconColor, defaultValue: null)); properties.add(ColorProperty('iconColor', iconColor, defaultValue: null));
properties.add(ColorProperty('textColor', textColor, defaultValue: null)); properties.add(ColorProperty('textColor', textColor, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('subtitleTextStyle', subtitleTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('leadingAndTrailingTextStyle', leadingAndTrailingTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('contentPadding', contentPadding, defaultValue: null)); properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('contentPadding', contentPadding, defaultValue: null));
properties.add(ColorProperty('tileColor', tileColor, defaultValue: null)); properties.add(ColorProperty('tileColor', tileColor, defaultValue: null));
properties.add(ColorProperty('selectedTileColor', selectedTileColor, defaultValue: null)); properties.add(ColorProperty('selectedTileColor', selectedTileColor, defaultValue: null));
......
...@@ -1578,11 +1578,10 @@ void main() { ...@@ -1578,11 +1578,10 @@ void main() {
testWidgets('ListTile default tile color', (WidgetTester tester) async { testWidgets('ListTile default tile color', (WidgetTester tester) async {
bool isSelected = false; bool isSelected = false;
final ThemeData theme = ThemeData(useMaterial3: true); const Color defaultColor = Colors.transparent;
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
theme: theme,
home: Material( home: Material(
child: Center( child: Center(
child: StatefulBuilder( child: StatefulBuilder(
...@@ -1601,13 +1600,13 @@ void main() { ...@@ -1601,13 +1600,13 @@ void main() {
), ),
); );
expect(find.byType(Material), paints..rect(color: theme.colorScheme.surface)); expect(find.byType(Material), paints..rect(color: defaultColor));
// Tap on tile to change isSelected. // Tap on tile to change isSelected.
await tester.tap(find.byType(ListTile)); await tester.tap(find.byType(ListTile));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.byType(Material), paints..rect(color: theme.colorScheme.surface)); expect(find.byType(Material), paints..rect(color: defaultColor));
}); });
testWidgets('ListTile layout at zero size', (WidgetTester tester) async { testWidgets('ListTile layout at zero size', (WidgetTester tester) async {
...@@ -2063,15 +2062,18 @@ void main() { ...@@ -2063,15 +2062,18 @@ void main() {
expect(textColor(trailingKey), theme.disabledColor); expect(textColor(trailingKey), theme.disabledColor);
}); });
testWidgets('selected, enabled ListTile default icon color', (WidgetTester tester) async { testWidgets('selected, enabled ListTile default icon color, light and dark themes', (WidgetTester tester) async {
final ThemeData theme = ThemeData(useMaterial3: true); const ColorScheme lightColorScheme = ColorScheme.light();
final ColorScheme colorScheme = theme.colorScheme; const ColorScheme darkColorScheme = ColorScheme.dark();
final Key leadingKey = UniqueKey(); final Key leadingKey = UniqueKey();
final Key titleKey = UniqueKey(); final Key titleKey = UniqueKey();
final Key subtitleKey = UniqueKey(); final Key subtitleKey = UniqueKey();
final Key trailingKey = UniqueKey(); final Key trailingKey = UniqueKey();
Widget buildFrame({required bool selected }) { Widget buildFrame({ required Brightness brightness, required bool selected }) {
final ThemeData theme = brightness == Brightness.light
? ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: true)
: ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: true);
return MaterialApp( return MaterialApp(
theme: theme, theme: theme,
home: Material( home: Material(
...@@ -2090,32 +2092,56 @@ void main() { ...@@ -2090,32 +2092,56 @@ void main() {
Color iconColor(Key key) => tester.state<TestIconState>(find.byKey(key)).iconTheme.color!; Color iconColor(Key key) => tester.state<TestIconState>(find.byKey(key)).iconTheme.color!;
await tester.pumpWidget(buildFrame(selected: true)); await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: true));
expect(iconColor(leadingKey), colorScheme.primary); expect(iconColor(leadingKey), lightColorScheme.primary);
expect(iconColor(titleKey), colorScheme.primary); expect(iconColor(titleKey), lightColorScheme.primary);
expect(iconColor(subtitleKey), colorScheme.primary); expect(iconColor(subtitleKey), lightColorScheme.primary);
expect(iconColor(trailingKey), colorScheme.primary); expect(iconColor(trailingKey), lightColorScheme.primary);
await tester.pumpWidget(buildFrame(selected: false)); await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: false));
expect(iconColor(leadingKey), colorScheme.onSurface); expect(iconColor(leadingKey), lightColorScheme.onSurface.withOpacity(0.38));
expect(iconColor(titleKey), colorScheme.onSurface); expect(iconColor(titleKey), lightColorScheme.onSurface.withOpacity(0.38));
expect(iconColor(subtitleKey), colorScheme.onSurface); expect(iconColor(subtitleKey), lightColorScheme.onSurface.withOpacity(0.38));
expect(iconColor(trailingKey), colorScheme.onSurface); expect(iconColor(trailingKey), lightColorScheme.onSurface.withOpacity(0.38));
await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: true));
await tester.pumpAndSettle(); // Animated theme change
expect(iconColor(leadingKey), darkColorScheme.primary);
expect(iconColor(titleKey), darkColorScheme.primary);
expect(iconColor(subtitleKey), darkColorScheme.primary);
expect(iconColor(trailingKey), darkColorScheme.primary);
// For this configuration, ListTile defers to the default IconTheme.
// The default dark theme's IconTheme has color:white
await tester.pumpWidget(buildFrame(brightness: Brightness.dark, selected: false));
expect(iconColor(leadingKey), darkColorScheme.onSurface.withOpacity(0.38));
expect(iconColor(titleKey), darkColorScheme.onSurface.withOpacity(0.38));
expect(iconColor(subtitleKey), darkColorScheme.onSurface.withOpacity(0.38));
expect(iconColor(trailingKey), darkColorScheme.onSurface.withOpacity(0.38));
}); });
testWidgets('ListTile font size', (WidgetTester tester) async { testWidgets('ListTile font size', (WidgetTester tester) async {
Widget buildFrame() { Widget buildFrame({
bool dense = false,
bool enabled = true,
bool selected = false,
ListTileStyle? style,
}) {
return MaterialApp( return MaterialApp(
theme: ThemeData(useMaterial3: true), theme: ThemeData(useMaterial3: true),
home: Material( home: Material(
child: Center( child: Center(
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
return const ListTile( return ListTile(
leading: TestText('leading'), dense: dense,
title: TestText('title'), enabled: enabled,
subtitle: TestText('subtitle') , selected: selected,
trailing: TestText('trailing'), style: style,
leading: const TestText('leading'),
title: const TestText('title'),
subtitle: const TestText('subtitle') ,
trailing: const TestText('trailing'),
); );
}, },
), ),
...@@ -2124,31 +2150,76 @@ void main() { ...@@ -2124,31 +2150,76 @@ void main() {
); );
} }
// ListTile default text sizes. // ListTile - ListTileStyle.list (default).
await tester.pumpWidget(buildFrame()); await tester.pumpWidget(buildFrame());
final RenderParagraph leading = _getTextRenderObject(tester, 'leading'); RenderParagraph leading = _getTextRenderObject(tester, 'leading');
expect(leading.text.style!.fontSize, 11.0); expect(leading.text.style!.fontSize, 14.0);
final RenderParagraph title = _getTextRenderObject(tester, 'title'); RenderParagraph title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.fontSize, 16.0); expect(title.text.style!.fontSize, 16.0);
final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle'); RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle');
expect(subtitle.text.style!.fontSize, 14.0);
RenderParagraph trailing = _getTextRenderObject(tester, 'trailing');
expect(trailing.text.style!.fontSize, 14.0);
// ListTile - Densed - ListTileStyle.list (default).
await tester.pumpWidget(buildFrame(dense: true));
await tester.pumpAndSettle();
leading = _getTextRenderObject(tester, 'leading');
expect(leading.text.style!.fontSize, 14.0);
title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.fontSize, 13.0);
subtitle = _getTextRenderObject(tester, 'subtitle');
expect(subtitle.text.style!.fontSize, 12.0);
trailing = _getTextRenderObject(tester, 'trailing');
expect(trailing.text.style!.fontSize, 14.0);
// ListTile - ListTileStyle.drawer.
await tester.pumpWidget(buildFrame(style: ListTileStyle.drawer));
await tester.pumpAndSettle();
leading = _getTextRenderObject(tester, 'leading');
expect(leading.text.style!.fontSize, 14.0);
title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.fontSize, 14.0);
subtitle = _getTextRenderObject(tester, 'subtitle');
expect(subtitle.text.style!.fontSize, 14.0); expect(subtitle.text.style!.fontSize, 14.0);
final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); trailing = _getTextRenderObject(tester, 'trailing');
expect(trailing.text.style!.fontSize, 11.0); expect(trailing.text.style!.fontSize, 14.0);
// ListTile - Densed - ListTileStyle.drawer.
await tester.pumpWidget(buildFrame(dense: true, style: ListTileStyle.drawer));
await tester.pumpAndSettle();
leading = _getTextRenderObject(tester, 'leading');
expect(leading.text.style!.fontSize, 14.0);
title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.fontSize, 13.0);
subtitle = _getTextRenderObject(tester, 'subtitle');
expect(subtitle.text.style!.fontSize, 12.0);
trailing = _getTextRenderObject(tester, 'trailing');
expect(trailing.text.style!.fontSize, 14.0);
}); });
testWidgets('ListTile text color', (WidgetTester tester) async { testWidgets('ListTile text color', (WidgetTester tester) async {
Widget buildFrame() { Widget buildFrame({
bool dense = false,
bool enabled = true,
bool selected = false,
ListTileStyle? style,
}) {
return MaterialApp( return MaterialApp(
theme: ThemeData(useMaterial3: true), theme: ThemeData(useMaterial3: true),
home: Material( home: Material(
child: Center( child: Center(
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
return const ListTile( return ListTile(
leading: TestText('leading'), dense: dense,
title: TestText('title'), enabled: enabled,
subtitle: TestText('subtitle') , selected: selected,
trailing: TestText('trailing'), style: style,
leading: const TestText('leading'),
title: const TestText('title'),
subtitle: const TestText('subtitle') ,
trailing: const TestText('trailing'),
); );
}, },
), ),
...@@ -2159,16 +2230,28 @@ void main() { ...@@ -2159,16 +2230,28 @@ void main() {
final ThemeData theme = ThemeData(useMaterial3: true); final ThemeData theme = ThemeData(useMaterial3: true);
// ListTile default text colors. // ListTile - ListTileStyle.list (default).
await tester.pumpWidget(buildFrame()); await tester.pumpWidget(buildFrame());
final RenderParagraph leading = _getTextRenderObject(tester, 'leading'); RenderParagraph leading = _getTextRenderObject(tester, 'leading');
expect(leading.text.style!.color, theme.textTheme.labelSmall!.color); expect(leading.text.style!.color, theme.textTheme.bodyMedium!.color);
final RenderParagraph title = _getTextRenderObject(tester, 'title'); RenderParagraph title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.color, theme.textTheme.titleMedium!.color);
RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle');
expect(subtitle.text.style!.color, theme.textTheme.bodySmall!.color);
RenderParagraph trailing = _getTextRenderObject(tester, 'trailing');
expect(trailing.text.style!.color, theme.textTheme.bodyMedium!.color);
// ListTile - ListTileStyle.drawer.
await tester.pumpWidget(buildFrame(style: ListTileStyle.drawer));
await tester.pumpAndSettle();
leading = _getTextRenderObject(tester, 'leading');
expect(leading.text.style!.color, theme.textTheme.bodyMedium!.color);
title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.color, theme.textTheme.bodyLarge!.color); expect(title.text.style!.color, theme.textTheme.bodyLarge!.color);
final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle'); subtitle = _getTextRenderObject(tester, 'subtitle');
expect(subtitle.text.style!.color, theme.textTheme.bodyMedium!.color); expect(subtitle.text.style!.color, theme.textTheme.bodySmall!.color);
final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); trailing = _getTextRenderObject(tester, 'trailing');
expect(trailing.text.style!.color, theme.textTheme.labelSmall!.color); expect(trailing.text.style!.color, theme.textTheme.bodyMedium!.color);
}); });
testWidgets('Default ListTile debugFillProperties', (WidgetTester tester) async { testWidgets('Default ListTile debugFillProperties', (WidgetTester tester) async {
...@@ -2248,149 +2331,6 @@ void main() { ...@@ -2248,149 +2331,6 @@ void main() {
); );
}); });
testWidgets('ListTile.textColor respects MaterialStateColor', (WidgetTester tester) async {
bool enabled = false;
bool selected = false;
const Color defaultColor = Colors.blue;
const Color selectedColor = Colors.green;
const Color disabledColor = Colors.red;
Widget buildFrame() {
return MaterialApp(
theme: ThemeData(useMaterial3: true),
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return ListTile(
enabled: enabled,
selected: selected,
textColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledColor;
}
if (states.contains(MaterialState.selected)) {
return selectedColor;
}
return defaultColor;
}),
title: const TestText('title'),
subtitle: const TestText('subtitle') ,
);
},
),
),
),
);
}
// Test disabled state.
await tester.pumpWidget(buildFrame());
RenderParagraph title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.color, disabledColor);
// Test enabled state.
enabled = true;
await tester.pumpWidget(buildFrame());
await tester.pumpAndSettle();
title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.color, defaultColor);
// Test selected state.
selected = true;
await tester.pumpWidget(buildFrame());
await tester.pumpAndSettle();
title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.color, selectedColor);
});
testWidgets('ListTile.iconColor respects MaterialStateColor', (WidgetTester tester) async {
bool enabled = false;
bool selected = false;
const Color defaultColor = Colors.blue;
const Color selectedColor = Colors.green;
const Color disabledColor = Colors.red;
final Key leadingKey = UniqueKey();
Widget buildFrame() {
return MaterialApp(
theme: ThemeData(useMaterial3: true),
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return ListTile(
enabled: enabled,
selected: selected,
iconColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledColor;
}
if (states.contains(MaterialState.selected)) {
return selectedColor;
}
return defaultColor;
}),
leading: TestIcon(key: leadingKey),
);
},
),
),
),
);
}
Color iconColor(Key key) => tester.state<TestIconState>(find.byKey(key)).iconTheme.color!;
// Test disabled state.
await tester.pumpWidget(buildFrame());
expect(iconColor(leadingKey), disabledColor);
// Test enabled state.
enabled = true;
await tester.pumpWidget(buildFrame());
await tester.pumpAndSettle();
expect(iconColor(leadingKey), defaultColor);
// Test selected state.
selected = true;
await tester.pumpWidget(buildFrame());
await tester.pumpAndSettle();
expect(iconColor(leadingKey), selectedColor);
});
testWidgets('ListTile.dense does not throw assertion', (WidgetTester tester) async {
// This is a regression test for https://github.com/flutter/flutter/pull/116908
Widget buildFrame({required bool useMaterial3}) {
return MaterialApp(
theme: ThemeData(useMaterial3: useMaterial3),
home: Material(
child: Center(
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return const ListTile(
dense: true,
title: Text('Title'),
);
},
),
),
),
);
}
await tester.pumpWidget(buildFrame(useMaterial3: false));
expect(tester.takeException(), isNull);
await tester.pumpWidget(buildFrame(useMaterial3: true));
expect(tester.takeException(), isNull);
});
group('Material 2', () { group('Material 2', () {
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3 // Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
// is turned on by default, these tests can be removed. // is turned on by default, these tests can be removed.
...@@ -2403,7 +2343,6 @@ void main() { ...@@ -2403,7 +2343,6 @@ void main() {
ListTileStyle? style, ListTileStyle? style,
}) { }) {
return MaterialApp( return MaterialApp(
theme: ThemeData(useMaterial3: false),
home: Material( home: Material(
child: Center( child: Center(
child: Builder( child: Builder(
...@@ -2481,7 +2420,6 @@ void main() { ...@@ -2481,7 +2420,6 @@ void main() {
ListTileStyle? style, ListTileStyle? style,
}) { }) {
return MaterialApp( return MaterialApp(
theme: ThemeData(useMaterial3: false),
home: Material( home: Material(
child: Center( child: Center(
child: Builder( child: Builder(
...@@ -2541,8 +2479,8 @@ void main() { ...@@ -2541,8 +2479,8 @@ void main() {
Widget buildFrame({ required Brightness brightness, required bool selected }) { Widget buildFrame({ required Brightness brightness, required bool selected }) {
final ThemeData theme = brightness == Brightness.light final ThemeData theme = brightness == Brightness.light
? ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: false) ? ThemeData.from(colorScheme: const ColorScheme.light())
: ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: false); : ThemeData.from(colorScheme: const ColorScheme.dark());
return MaterialApp( return MaterialApp(
theme: theme, theme: theme,
home: Material( home: Material(
...@@ -2588,40 +2526,6 @@ void main() { ...@@ -2588,40 +2526,6 @@ void main() {
expect(iconColor(subtitleKey), Colors.white); expect(iconColor(subtitleKey), Colors.white);
expect(iconColor(trailingKey), Colors.white); expect(iconColor(trailingKey), Colors.white);
}); });
testWidgets('ListTile default tile color', (WidgetTester tester) async {
bool isSelected = false;
const Color defaultColor = Colors.transparent;
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(useMaterial3: false),
home: Material(
child: Center(
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return ListTile(
selected: isSelected,
onTap: () {
setState(()=> isSelected = !isSelected);
},
title: const Text('Title'),
);
},
),
),
),
),
);
expect(find.byType(Material), paints..rect(color: defaultColor));
// Tap on tile to change isSelected.
await tester.tap(find.byType(ListTile));
await tester.pumpAndSettle();
expect(find.byType(Material), paints..rect(color: defaultColor));
});
}); });
} }
......
...@@ -59,9 +59,6 @@ void main() { ...@@ -59,9 +59,6 @@ void main() {
expect(themeData.selectedColor, null); expect(themeData.selectedColor, null);
expect(themeData.iconColor, null); expect(themeData.iconColor, null);
expect(themeData.textColor, null); expect(themeData.textColor, null);
expect(themeData.titleTextStyle, null);
expect(themeData.subtitleTextStyle, null);
expect(themeData.leadingAndTrailingTextStyle, null);
expect(themeData.contentPadding, null); expect(themeData.contentPadding, null);
expect(themeData.tileColor, null); expect(themeData.tileColor, null);
expect(themeData.selectedTileColor, null); expect(themeData.selectedTileColor, null);
...@@ -94,12 +91,9 @@ void main() { ...@@ -94,12 +91,9 @@ void main() {
selectedColor: Color(0x00000001), selectedColor: Color(0x00000001),
iconColor: Color(0x00000002), iconColor: Color(0x00000002),
textColor: Color(0x00000003), textColor: Color(0x00000003),
titleTextStyle: TextStyle(color: Color(0x00000004)),
subtitleTextStyle: TextStyle(color: Color(0x00000005)),
leadingAndTrailingTextStyle: TextStyle(color: Color(0x00000006)),
contentPadding: EdgeInsets.all(100), contentPadding: EdgeInsets.all(100),
tileColor: Color(0x00000007), tileColor: Color(0x00000004),
selectedTileColor: Color(0x00000008), selectedTileColor: Color(0x00000005),
horizontalTitleGap: 200, horizontalTitleGap: 200,
minVerticalPadding: 300, minVerticalPadding: 300,
minLeadingWidth: 400, minLeadingWidth: 400,
...@@ -122,12 +116,9 @@ void main() { ...@@ -122,12 +116,9 @@ void main() {
'selectedColor: Color(0x00000001)', 'selectedColor: Color(0x00000001)',
'iconColor: Color(0x00000002)', 'iconColor: Color(0x00000002)',
'textColor: Color(0x00000003)', 'textColor: Color(0x00000003)',
'titleTextStyle: TextStyle(inherit: true, color: Color(0x00000004))',
'subtitleTextStyle: TextStyle(inherit: true, color: Color(0x00000005))',
'leadingAndTrailingTextStyle: TextStyle(inherit: true, color: Color(0x00000006))',
'contentPadding: EdgeInsets.all(100.0)', 'contentPadding: EdgeInsets.all(100.0)',
'tileColor: Color(0x00000007)', 'tileColor: Color(0x00000004)',
'selectedTileColor: Color(0x00000008)', 'selectedTileColor: Color(0x00000005)',
'horizontalTitleGap: 200.0', 'horizontalTitleGap: 200.0',
'minVerticalPadding: 300.0', 'minVerticalPadding: 300.0',
'minLeadingWidth: 400.0', 'minLeadingWidth: 400.0',
...@@ -374,99 +365,6 @@ void main() { ...@@ -374,99 +365,6 @@ void main() {
expect(textColor(trailingKey), theme.disabledColor); expect(textColor(trailingKey), theme.disabledColor);
}); });
testWidgets(
"ListTile respects ListTileTheme's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle",
(WidgetTester tester) async {
final ThemeData theme = ThemeData(
useMaterial3: true,
listTileTheme: const ListTileThemeData(
titleTextStyle: TextStyle(fontSize: 20.0),
subtitleTextStyle: TextStyle(fontSize: 17.5),
leadingAndTrailingTextStyle: TextStyle(fontSize: 15.0),
),
);
Widget buildFrame() {
return MaterialApp(
theme: theme,
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return const ListTile(
leading: TestText('leading'),
title: TestText('title'),
subtitle: TestText('subtitle') ,
trailing: TestText('trailing'),
);
},
),
),
),
);
}
await tester.pumpWidget(buildFrame());
final RenderParagraph leading = _getTextRenderObject(tester, 'leading');
expect(leading.text.style!.fontSize, 15.0);
final RenderParagraph title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.fontSize, 20.0);
final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle');
expect(subtitle.text.style!.fontSize, 17.5);
final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing');
expect(trailing.text.style!.fontSize, 15.0);
});
testWidgets(
"ListTile's titleTextStyle, subtitleTextStyle & leadingAndTrailingTextStyle are overridden by ListTile properties",
(WidgetTester tester) async {
final ThemeData theme = ThemeData(
useMaterial3: true,
listTileTheme: const ListTileThemeData(
titleTextStyle: TextStyle(fontSize: 20.0),
subtitleTextStyle: TextStyle(fontSize: 17.5),
leadingAndTrailingTextStyle: TextStyle(fontSize: 15.0),
),
);
const TextStyle titleTextStyle = TextStyle(fontSize: 23.0);
const TextStyle subtitleTextStyle = TextStyle(fontSize: 20.0);
const TextStyle leadingAndTrailingTextStyle = TextStyle(fontSize: 18.0);
Widget buildFrame() {
return MaterialApp(
theme: theme,
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return const ListTile(
titleTextStyle: titleTextStyle,
subtitleTextStyle: subtitleTextStyle,
leadingAndTrailingTextStyle: leadingAndTrailingTextStyle,
leading: TestText('leading'),
title: TestText('title'),
subtitle: TestText('subtitle') ,
trailing: TestText('trailing'),
);
},
),
),
),
);
}
await tester.pumpWidget(buildFrame());
final RenderParagraph leading = _getTextRenderObject(tester, 'leading');
expect(leading.text.style!.fontSize, 18.0);
final RenderParagraph title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.fontSize, 23.0);
final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle');
expect(subtitle.text.style!.fontSize, 20.0);
final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing');
expect(trailing.text.style!.fontSize, 18.0);
});
testWidgets("ListTile respects ListTileTheme's tileColor & selectedTileColor", (WidgetTester tester) async { testWidgets("ListTile respects ListTileTheme's tileColor & selectedTileColor", (WidgetTester tester) async {
late ListTileThemeData theme; late ListTileThemeData theme;
bool isSelected = false; bool isSelected = false;
...@@ -581,134 +479,4 @@ void main() { ...@@ -581,134 +479,4 @@ void main() {
// Test shape. // Test shape.
expect(inkWellBorder, shapeBorder); expect(inkWellBorder, shapeBorder);
}); });
testWidgets('ListTile respects MaterialStateColor LisTileTheme.textColor', (WidgetTester tester) async {
bool enabled = false;
bool selected = false;
const Color defaultColor = Colors.blue;
const Color selectedColor = Colors.green;
const Color disabledColor = Colors.red;
final ThemeData theme = ThemeData(
listTileTheme: ListTileThemeData(
textColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledColor;
}
if (states.contains(MaterialState.selected)) {
return selectedColor;
}
return defaultColor;
}),
),
);
Widget buildFrame() {
return MaterialApp(
theme: theme,
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return ListTile(
enabled: enabled,
selected: selected,
title: const TestText('title'),
subtitle: const TestText('subtitle') ,
);
},
),
),
),
);
}
// Test disabled state.
await tester.pumpWidget(buildFrame());
RenderParagraph title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.color, disabledColor);
// Test enabled state.
enabled = true;
await tester.pumpWidget(buildFrame());
await tester.pumpAndSettle();
title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.color, defaultColor);
// Test selected state.
selected = true;
await tester.pumpWidget(buildFrame());
await tester.pumpAndSettle();
title = _getTextRenderObject(tester, 'title');
expect(title.text.style!.color, selectedColor);
});
testWidgets('ListTile respects MaterialStateColor LisTileTheme.iconColor', (WidgetTester tester) async {
bool enabled = false;
bool selected = false;
const Color defaultColor = Colors.blue;
const Color selectedColor = Colors.green;
const Color disabledColor = Colors.red;
final Key leadingKey = UniqueKey();
final ThemeData theme = ThemeData(
listTileTheme: ListTileThemeData(
iconColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
if (states.contains(MaterialState.disabled)) {
return disabledColor;
}
if (states.contains(MaterialState.selected)) {
return selectedColor;
}
return defaultColor;
}),
),
);
Widget buildFrame() {
return MaterialApp(
theme: theme,
home: Material(
child: Center(
child: Builder(
builder: (BuildContext context) {
return ListTile(
enabled: enabled,
selected: selected,
leading: TestIcon(key: leadingKey),
);
},
),
),
),
);
}
Color iconColor(Key key) => tester.state<TestIconState>(find.byKey(key)).iconTheme.color!;
// Test disabled state.
await tester.pumpWidget(buildFrame());
expect(iconColor(leadingKey), disabledColor);
// Test enabled state.
enabled = true;
await tester.pumpWidget(buildFrame());
await tester.pumpAndSettle();
expect(iconColor(leadingKey), defaultColor);
// Test selected state.
selected = true;
await tester.pumpWidget(buildFrame());
await tester.pumpAndSettle();
expect(iconColor(leadingKey), selectedColor);
});
}
RenderParagraph _getTextRenderObject(WidgetTester tester, String text) {
return tester.renderObject(find.descendant(
of: find.byType(ListTile),
matching: find.text(text),
));
} }
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