diff --git a/dev/tools/gen_defaults/bin/gen_defaults.dart b/dev/tools/gen_defaults/bin/gen_defaults.dart index fa156d82f8f4..6bda89e0a56e 100644 --- a/dev/tools/gen_defaults/bin/gen_defaults.dart +++ b/dev/tools/gen_defaults/bin/gen_defaults.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/input_chip_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/navigation_bar_template.dart'; import 'package:gen_defaults/navigation_drawer_template.dart'; @@ -156,7 +155,6 @@ Future main(List args) async { FilterChipTemplate('FilterChip', '$materialLib/filter_chip.dart', tokens).updateFile(); IconButtonTemplate('IconButton', '$materialLib/icon_button.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(); MenuTemplate('Menu', '$materialLib/menu_anchor.dart', tokens).updateFile(); NavigationBarTemplate('NavigationBar', '$materialLib/navigation_bar.dart', tokens).updateFile(); diff --git a/dev/tools/gen_defaults/lib/list_tile_template.dart b/dev/tools/gen_defaults/lib/list_tile_template.dart deleted file mode 100644 index d2dc15e241d6..000000000000 --- a/dev/tools/gen_defaults/lib/list_tile_template.dart +++ /dev/null @@ -1,37 +0,0 @@ -// 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')}; -} -'''; -} diff --git a/packages/flutter/lib/src/material/list_tile.dart b/packages/flutter/lib/src/material/list_tile.dart index 65f63c3a8fec..b4ddd2166b63 100644 --- a/packages/flutter/lib/src/material/list_tile.dart +++ b/packages/flutter/lib/src/material/list_tile.dart @@ -15,7 +15,6 @@ import 'ink_decoration.dart'; import 'ink_well.dart'; import 'list_tile_theme.dart'; import 'material_state.dart'; -import 'text_theme.dart'; import 'theme.dart'; import 'theme_data.dart'; @@ -279,9 +278,6 @@ class ListTile extends StatelessWidget { this.selectedColor, this.iconColor, this.textColor, - this.titleTextStyle, - this.subtitleTextStyle, - this.leadingAndTrailingTextStyle, this.contentPadding, this.enabled = true, this.onTap, @@ -368,8 +364,6 @@ class ListTile extends StatelessWidget { /// If this property is null then its value is based on [ListTileTheme.dense]. /// /// 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; /// Defines how compact the list tile's layout will be. @@ -427,28 +421,6 @@ class ListTile extends StatelessWidget { /// [ListTileThemeData]. 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]. /// /// If this property is null then [ListTileThemeData.style] is used. If that @@ -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) { return dense ?? tileTheme.dense ?? theme.listTileTheme.dense ?? false; } - // TODO(TahaTesser): Refactor this to support list tile states. - Color _tileBackgroundColor(ThemeData theme, ListTileThemeData tileTheme, ListTileThemeData defaults) { + TextStyle _titleTextStyle(ThemeData theme, ListTileThemeData tileTheme) { + 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 ? selectedTileColor ?? tileTheme.selectedTileColor ?? theme.listTileTheme.selectedTileColor : tileColor ?? tileTheme.tileColor ?? theme.listTileTheme.tileColor; - return color ?? defaults.tileColor!; + return color ?? Colors.transparent; } @override @@ -633,63 +680,23 @@ class ListTile extends StatelessWidget { assert(debugCheckHasMaterial(context)); final ThemeData theme = Theme.of(context); final ListTileThemeData tileTheme = ListTileTheme.of(context); - final ListTileStyle listTileStyle = style - ?? tileTheme.style - ?? theme.listTileTheme.style - ?? ListTileStyle.list; - final ListTileThemeData defaults = theme.useMaterial3 - ? _LisTileDefaultsM3(context) - : _LisTileDefaultsM2(context, listTileStyle); - final Set states = { - if (!enabled) MaterialState.disabled, - if (selected) MaterialState.selected, - }; + final IconThemeData iconThemeData = IconThemeData(color: _iconColor(theme, tileTheme)); - Color? resolveColor(Color? explicitColor, Color? selectedColor, Color? enabledColor, [Color? disabledColor]) { - 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; + TextStyle? leadingAndTrailingTextStyle; if (leading != null || trailing != null) { - leadingAndTrailingStyle = leadingAndTrailingTextStyle - ?? tileTheme.leadingAndTrailingTextStyle - ?? defaults.leadingAndTrailingTextStyle!; - final Color? leadingAndTrailingTextColor = effectiveColor; - leadingAndTrailingStyle = leadingAndTrailingStyle.copyWith(color: leadingAndTrailingTextColor); + leadingAndTrailingTextStyle = _trailingAndLeadingTextStyle(theme, tileTheme); } Widget? leadingIcon; if (leading != null) { leadingIcon = AnimatedDefaultTextStyle( - style: leadingAndTrailingStyle!, + style: leadingAndTrailingTextStyle!, duration: kThemeChangeDuration, child: leading!, ); } - TextStyle titleStyle = titleTextStyle - ?? tileTheme.titleTextStyle - ?? defaults.titleTextStyle!; - final Color? titleColor = effectiveColor; - titleStyle = titleStyle.copyWith( - color: titleColor, - fontSize: _isDenseLayout(theme, tileTheme) ? 13.0 : null, - ); + final TextStyle titleStyle = _titleTextStyle(theme, tileTheme); final Widget titleText = AnimatedDefaultTextStyle( style: titleStyle, duration: kThemeChangeDuration, @@ -699,14 +706,7 @@ class ListTile extends StatelessWidget { Widget? subtitleText; TextStyle? subtitleStyle; if (subtitle != null) { - subtitleStyle = subtitleTextStyle - ?? tileTheme.subtitleTextStyle - ?? defaults.subtitleTextStyle!; - final Color? subtitleColor = effectiveColor ?? theme.textTheme.bodySmall!.color; - subtitleStyle = subtitleStyle.copyWith( - color: subtitleColor, - fontSize: _isDenseLayout(theme, tileTheme) ? 12.0 : null, - ); + subtitleStyle = _subtitleTextStyle(theme, tileTheme); subtitleText = AnimatedDefaultTextStyle( style: subtitleStyle, duration: kThemeChangeDuration, @@ -717,7 +717,7 @@ class ListTile extends StatelessWidget { Widget? trailingIcon; if (trailing != null) { trailingIcon = AnimatedDefaultTextStyle( - style: leadingAndTrailingStyle!, + style: leadingAndTrailingTextStyle!, duration: kThemeChangeDuration, child: trailing!, ); @@ -728,13 +728,15 @@ class ListTile extends StatelessWidget { final EdgeInsets resolvedContentPadding = contentPadding?.resolve(textDirection) ?? tileTheme.contentPadding?.resolve(textDirection) ?? defaultContentPadding; - // Show basic cursor when ListTile isn't enabled or gesture callbacks are null. - final Set mouseStates = { + + final Set states = { if (!enabled || (onTap == null && onLongPress == null)) MaterialState.disabled, + if (selected) MaterialState.selected, }; - final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs(mouseCursor, mouseStates) - ?? tileTheme.mouseCursor?.resolve(mouseStates) - ?? MaterialStateMouseCursor.clickable.resolve(mouseStates); + + final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs(mouseCursor, states) + ?? tileTheme.mouseCursor?.resolve(states) + ?? MaterialStateMouseCursor.clickable.resolve(states); return InkWell( customBorder: shape ?? tileTheme.shape, @@ -755,7 +757,7 @@ class ListTile extends StatelessWidget { child: Ink( decoration: ShapeDecoration( shape: shape ?? tileTheme.shape ?? const Border(), - color: _tileBackgroundColor(theme, tileTheme, defaults), + color: _tileBackgroundColor(theme, tileTheme), ), child: SafeArea( top: false, @@ -772,8 +774,8 @@ class ListTile extends StatelessWidget { visualDensity: visualDensity ?? tileTheme.visualDensity ?? theme.visualDensity, isThreeLine: isThreeLine, textDirection: textDirection, - titleBaselineType: titleStyle.textBaseline ?? defaults.titleTextStyle!.textBaseline!, - subtitleBaselineType: subtitleStyle?.textBaseline ?? defaults.subtitleTextStyle!.textBaseline!, + titleBaselineType: titleStyle.textBaseline!, + subtitleBaselineType: subtitleStyle?.textBaseline, horizontalTitleGap: horizontalTitleGap ?? tileTheme.horizontalTitleGap ?? 16, minVerticalPadding: minVerticalPadding ?? tileTheme.minVerticalPadding ?? 4, minLeadingWidth: minLeadingWidth ?? tileTheme.minLeadingWidth ?? 40, @@ -819,36 +821,6 @@ class ListTile extends StatelessWidget { } } -class _IndividualOverrides extends MaterialStateProperty { - _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 states) { - if (explicitColor is MaterialStateColor) { - return MaterialStateProperty.resolveAs(explicitColor, states); - } - - if (states.contains(MaterialState.disabled)) { - return disabledColor; - } - if (states.contains(MaterialState.selected)) { - return selectedColor; - } - - return enabledColor; - } -} - // Identifies the children of a _ListTileElement. enum _ListTileSlot { leading, @@ -1371,87 +1343,3 @@ class _RenderListTile extends RenderBox with SlottedContainerRenderObjectMixin<_ 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 diff --git a/packages/flutter/lib/src/material/list_tile_theme.dart b/packages/flutter/lib/src/material/list_tile_theme.dart index b5e421708b81..501a608dd511 100644 --- a/packages/flutter/lib/src/material/list_tile_theme.dart +++ b/packages/flutter/lib/src/material/list_tile_theme.dart @@ -51,9 +51,6 @@ class ListTileThemeData with Diagnosticable { this.selectedColor, this.iconColor, this.textColor, - this.titleTextStyle, - this.subtitleTextStyle, - this.leadingAndTrailingTextStyle, this.contentPadding, this.tileColor, this.selectedTileColor, @@ -83,15 +80,6 @@ class ListTileThemeData with Diagnosticable { /// Overrides the default value of [ListTile.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]. final EdgeInsetsGeometry? contentPadding; @@ -128,9 +116,6 @@ class ListTileThemeData with Diagnosticable { Color? selectedColor, Color? iconColor, Color? textColor, - TextStyle? titleTextStyle, - TextStyle? subtitleTextStyle, - TextStyle? leadingAndTrailingTextStyle, EdgeInsetsGeometry? contentPadding, Color? tileColor, Color? selectedTileColor, @@ -149,9 +134,6 @@ class ListTileThemeData with Diagnosticable { selectedColor: selectedColor ?? this.selectedColor, iconColor: iconColor ?? this.iconColor, textColor: textColor ?? this.textColor, - titleTextStyle: titleTextStyle ?? this.titleTextStyle, - subtitleTextStyle: titleTextStyle ?? this.subtitleTextStyle, - leadingAndTrailingTextStyle: titleTextStyle ?? this.leadingAndTrailingTextStyle, contentPadding: contentPadding ?? this.contentPadding, tileColor: tileColor ?? this.tileColor, selectedTileColor: selectedTileColor ?? this.selectedTileColor, @@ -177,9 +159,6 @@ class ListTileThemeData with Diagnosticable { selectedColor: Color.lerp(a?.selectedColor, b?.selectedColor, t), iconColor: Color.lerp(a?.iconColor, b?.iconColor, 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), tileColor: Color.lerp(a?.tileColor, b?.tileColor, t), selectedTileColor: Color.lerp(a?.selectedTileColor, b?.selectedTileColor, t), @@ -200,9 +179,6 @@ class ListTileThemeData with Diagnosticable { selectedColor, iconColor, textColor, - titleTextStyle, - subtitleTextStyle, - leadingAndTrailingTextStyle, contentPadding, tileColor, selectedTileColor, @@ -228,9 +204,6 @@ class ListTileThemeData with Diagnosticable { && other.style == style && other.selectedColor == selectedColor && other.iconColor == iconColor - && other.titleTextStyle == titleTextStyle - && other.subtitleTextStyle == subtitleTextStyle - && other.leadingAndTrailingTextStyle == leadingAndTrailingTextStyle && other.textColor == textColor && other.contentPadding == contentPadding && other.tileColor == tileColor @@ -252,9 +225,6 @@ class ListTileThemeData with Diagnosticable { properties.add(ColorProperty('selectedColor', selectedColor, defaultValue: null)); properties.add(ColorProperty('iconColor', iconColor, defaultValue: null)); properties.add(ColorProperty('textColor', textColor, defaultValue: null)); - properties.add(DiagnosticsProperty('titleTextStyle', titleTextStyle, defaultValue: null)); - properties.add(DiagnosticsProperty('subtitleTextStyle', subtitleTextStyle, defaultValue: null)); - properties.add(DiagnosticsProperty('leadingAndTrailingTextStyle', leadingAndTrailingTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty('contentPadding', contentPadding, defaultValue: null)); properties.add(ColorProperty('tileColor', tileColor, defaultValue: null)); properties.add(ColorProperty('selectedTileColor', selectedTileColor, defaultValue: null)); diff --git a/packages/flutter/test/material/list_tile_test.dart b/packages/flutter/test/material/list_tile_test.dart index f0789b4e0f2d..67398114ed68 100644 --- a/packages/flutter/test/material/list_tile_test.dart +++ b/packages/flutter/test/material/list_tile_test.dart @@ -1578,11 +1578,10 @@ void main() { testWidgets('ListTile default tile color', (WidgetTester tester) async { bool isSelected = false; - final ThemeData theme = ThemeData(useMaterial3: true); + const Color defaultColor = Colors.transparent; await tester.pumpWidget( MaterialApp( - theme: theme, home: Material( child: Center( child: StatefulBuilder( @@ -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. await tester.tap(find.byType(ListTile)); 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 { @@ -2063,15 +2062,18 @@ void main() { expect(textColor(trailingKey), theme.disabledColor); }); - testWidgets('selected, enabled ListTile default icon color', (WidgetTester tester) async { - final ThemeData theme = ThemeData(useMaterial3: true); - final ColorScheme colorScheme = theme.colorScheme; + testWidgets('selected, enabled ListTile default icon color, light and dark themes', (WidgetTester tester) async { + const ColorScheme lightColorScheme = ColorScheme.light(); + const ColorScheme darkColorScheme = ColorScheme.dark(); final Key leadingKey = UniqueKey(); final Key titleKey = UniqueKey(); final Key subtitleKey = 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( theme: theme, home: Material( @@ -2090,32 +2092,56 @@ void main() { Color iconColor(Key key) => tester.state(find.byKey(key)).iconTheme.color!; - await tester.pumpWidget(buildFrame(selected: true)); - expect(iconColor(leadingKey), colorScheme.primary); - expect(iconColor(titleKey), colorScheme.primary); - expect(iconColor(subtitleKey), colorScheme.primary); - expect(iconColor(trailingKey), colorScheme.primary); - - await tester.pumpWidget(buildFrame(selected: false)); - expect(iconColor(leadingKey), colorScheme.onSurface); - expect(iconColor(titleKey), colorScheme.onSurface); - expect(iconColor(subtitleKey), colorScheme.onSurface); - expect(iconColor(trailingKey), colorScheme.onSurface); + await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: true)); + expect(iconColor(leadingKey), lightColorScheme.primary); + expect(iconColor(titleKey), lightColorScheme.primary); + expect(iconColor(subtitleKey), lightColorScheme.primary); + expect(iconColor(trailingKey), lightColorScheme.primary); + + await tester.pumpWidget(buildFrame(brightness: Brightness.light, selected: false)); + expect(iconColor(leadingKey), lightColorScheme.onSurface.withOpacity(0.38)); + expect(iconColor(titleKey), lightColorScheme.onSurface.withOpacity(0.38)); + expect(iconColor(subtitleKey), lightColorScheme.onSurface.withOpacity(0.38)); + 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 { - Widget buildFrame() { + Widget buildFrame({ + bool dense = false, + bool enabled = true, + bool selected = false, + ListTileStyle? style, + }) { return MaterialApp( theme: ThemeData(useMaterial3: true), home: Material( child: Center( child: Builder( builder: (BuildContext context) { - return const ListTile( - leading: TestText('leading'), - title: TestText('title'), - subtitle: TestText('subtitle') , - trailing: TestText('trailing'), + return ListTile( + dense: dense, + enabled: enabled, + selected: selected, + style: style, + leading: const TestText('leading'), + title: const TestText('title'), + subtitle: const TestText('subtitle') , + trailing: const TestText('trailing'), ); }, ), @@ -2124,31 +2150,76 @@ void main() { ); } - // ListTile default text sizes. + // ListTile - ListTileStyle.list (default). await tester.pumpWidget(buildFrame()); - final RenderParagraph leading = _getTextRenderObject(tester, 'leading'); - expect(leading.text.style!.fontSize, 11.0); - final RenderParagraph title = _getTextRenderObject(tester, 'title'); + RenderParagraph leading = _getTextRenderObject(tester, 'leading'); + expect(leading.text.style!.fontSize, 14.0); + RenderParagraph title = _getTextRenderObject(tester, 'title'); 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); - final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); - expect(trailing.text.style!.fontSize, 11.0); + trailing = _getTextRenderObject(tester, 'trailing'); + 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 { - Widget buildFrame() { + Widget buildFrame({ + bool dense = false, + bool enabled = true, + bool selected = false, + ListTileStyle? style, + }) { return MaterialApp( theme: ThemeData(useMaterial3: true), home: Material( child: Center( child: Builder( builder: (BuildContext context) { - return const ListTile( - leading: TestText('leading'), - title: TestText('title'), - subtitle: TestText('subtitle') , - trailing: TestText('trailing'), + return ListTile( + dense: dense, + enabled: enabled, + selected: selected, + style: style, + leading: const TestText('leading'), + title: const TestText('title'), + subtitle: const TestText('subtitle') , + trailing: const TestText('trailing'), ); }, ), @@ -2159,16 +2230,28 @@ void main() { final ThemeData theme = ThemeData(useMaterial3: true); - // ListTile default text colors. + // ListTile - ListTileStyle.list (default). await tester.pumpWidget(buildFrame()); - final RenderParagraph leading = _getTextRenderObject(tester, 'leading'); - expect(leading.text.style!.color, theme.textTheme.labelSmall!.color); - final RenderParagraph title = _getTextRenderObject(tester, 'title'); + RenderParagraph leading = _getTextRenderObject(tester, 'leading'); + expect(leading.text.style!.color, theme.textTheme.bodyMedium!.color); + 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); - final RenderParagraph subtitle = _getTextRenderObject(tester, 'subtitle'); - expect(subtitle.text.style!.color, theme.textTheme.bodyMedium!.color); - final RenderParagraph trailing = _getTextRenderObject(tester, 'trailing'); - expect(trailing.text.style!.color, theme.textTheme.labelSmall!.color); + subtitle = _getTextRenderObject(tester, 'subtitle'); + expect(subtitle.text.style!.color, theme.textTheme.bodySmall!.color); + trailing = _getTextRenderObject(tester, 'trailing'); + expect(trailing.text.style!.color, theme.textTheme.bodyMedium!.color); }); testWidgets('Default ListTile debugFillProperties', (WidgetTester tester) async { @@ -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 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 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(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', () { // Tests that are only relevant for Material 2. Once ThemeData.useMaterial3 // is turned on by default, these tests can be removed. @@ -2403,7 +2343,6 @@ void main() { ListTileStyle? style, }) { return MaterialApp( - theme: ThemeData(useMaterial3: false), home: Material( child: Center( child: Builder( @@ -2481,7 +2420,6 @@ void main() { ListTileStyle? style, }) { return MaterialApp( - theme: ThemeData(useMaterial3: false), home: Material( child: Center( child: Builder( @@ -2541,8 +2479,8 @@ void main() { Widget buildFrame({ required Brightness brightness, required bool selected }) { final ThemeData theme = brightness == Brightness.light - ? ThemeData.from(colorScheme: const ColorScheme.light(), useMaterial3: false) - : ThemeData.from(colorScheme: const ColorScheme.dark(), useMaterial3: false); + ? ThemeData.from(colorScheme: const ColorScheme.light()) + : ThemeData.from(colorScheme: const ColorScheme.dark()); return MaterialApp( theme: theme, home: Material( @@ -2588,40 +2526,6 @@ void main() { expect(iconColor(subtitleKey), 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)); - }); }); } diff --git a/packages/flutter/test/material/list_tile_theme_test.dart b/packages/flutter/test/material/list_tile_theme_test.dart index dd1cfc459018..89d43e840189 100644 --- a/packages/flutter/test/material/list_tile_theme_test.dart +++ b/packages/flutter/test/material/list_tile_theme_test.dart @@ -59,9 +59,6 @@ void main() { expect(themeData.selectedColor, null); expect(themeData.iconColor, null); expect(themeData.textColor, null); - expect(themeData.titleTextStyle, null); - expect(themeData.subtitleTextStyle, null); - expect(themeData.leadingAndTrailingTextStyle, null); expect(themeData.contentPadding, null); expect(themeData.tileColor, null); expect(themeData.selectedTileColor, null); @@ -94,12 +91,9 @@ void main() { selectedColor: Color(0x00000001), iconColor: Color(0x00000002), textColor: Color(0x00000003), - titleTextStyle: TextStyle(color: Color(0x00000004)), - subtitleTextStyle: TextStyle(color: Color(0x00000005)), - leadingAndTrailingTextStyle: TextStyle(color: Color(0x00000006)), contentPadding: EdgeInsets.all(100), - tileColor: Color(0x00000007), - selectedTileColor: Color(0x00000008), + tileColor: Color(0x00000004), + selectedTileColor: Color(0x00000005), horizontalTitleGap: 200, minVerticalPadding: 300, minLeadingWidth: 400, @@ -122,12 +116,9 @@ void main() { 'selectedColor: Color(0x00000001)', 'iconColor: Color(0x00000002)', '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)', - 'tileColor: Color(0x00000007)', - 'selectedTileColor: Color(0x00000008)', + 'tileColor: Color(0x00000004)', + 'selectedTileColor: Color(0x00000005)', 'horizontalTitleGap: 200.0', 'minVerticalPadding: 300.0', 'minLeadingWidth: 400.0', @@ -374,99 +365,6 @@ void main() { 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 { late ListTileThemeData theme; bool isSelected = false; @@ -581,134 +479,4 @@ void main() { // Test shape. 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 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 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(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), - )); }