Unverified Commit 672859a0 authored by Viren Khatri's avatar Viren Khatri Committed by GitHub

feat: add icon to AlertDialog (#104920)

parent e649210f
...@@ -25,6 +25,9 @@ class _TokenDefaultsM3 extends DialogTheme { ...@@ -25,6 +25,9 @@ class _TokenDefaultsM3 extends DialogTheme {
late final ColorScheme _colors = Theme.of(context).colorScheme; late final ColorScheme _colors = Theme.of(context).colorScheme;
late final TextTheme _textTheme = Theme.of(context).textTheme; late final TextTheme _textTheme = Theme.of(context).textTheme;
@override
Color? get iconColor => _colors.secondary;
// TODO(darrenaustin): overlay should be handled by Material widget: https://github.com/flutter/flutter/issues/9160 // TODO(darrenaustin): overlay should be handled by Material widget: https://github.com/flutter/flutter/issues/9160
@override @override
Color? get backgroundColor => ElevationOverlay.colorWithOverlay(${componentColor("md.comp.dialog.container")}, _colors.primary, ${elevation("md.comp.dialog.container")}); Color? get backgroundColor => ElevationOverlay.colorWithOverlay(${componentColor("md.comp.dialog.container")}, _colors.primary, ${elevation("md.comp.dialog.container")});
......
...@@ -257,16 +257,19 @@ class AlertDialog extends StatelessWidget { ...@@ -257,16 +257,19 @@ class AlertDialog extends StatelessWidget {
/// ///
/// Typically used in conjunction with [showDialog]. /// Typically used in conjunction with [showDialog].
/// ///
/// The [contentPadding] must not be null. The [titlePadding] defaults to /// The [titlePadding] and [contentPadding] default to null, which implies a
/// null, which implies a default that depends on the values of the other /// default that depends on the values of the other properties. See the
/// properties. See the documentation of [titlePadding] for details. /// documentation of [titlePadding] and [contentPadding] for details.
const AlertDialog({ const AlertDialog({
super.key, super.key,
this.icon,
this.iconPadding,
this.iconColor,
this.title, this.title,
this.titlePadding, this.titlePadding,
this.titleTextStyle, this.titleTextStyle,
this.content, this.content,
this.contentPadding = const EdgeInsets.fromLTRB(24.0, 20.0, 24.0, 24.0), this.contentPadding,
this.contentTextStyle, this.contentTextStyle,
this.actions, this.actions,
this.actionsPadding, this.actionsPadding,
...@@ -283,11 +286,35 @@ class AlertDialog extends StatelessWidget { ...@@ -283,11 +286,35 @@ class AlertDialog extends StatelessWidget {
this.shape, this.shape,
this.alignment, this.alignment,
this.scrollable = false, this.scrollable = false,
}) : assert(contentPadding != null), }) : assert(clipBehavior != null);
assert(clipBehavior != null);
/// An optional icon to display at the top of the dialog.
///
/// Typically, an [Icon] widget. Providing an icon centers the [title]'s text.
final Widget? icon;
/// Color for the [Icon] in the [icon] of this [AlertDialog].
///
/// If null, [DialogTheme.iconColor] is used. If that is null, defaults to
/// color scheme's [ColorScheme.secondary] if [ThemeData.useMaterial3] is
/// true, black otherwise.
final Color? iconColor;
/// Padding around the [icon].
///
/// If there is no [icon], no padding will be provided. Otherwise, this
/// padding is used.
///
/// This property defaults to providing 24 pixels on the top, left, and right
/// of the [icon]. If [title] is _not_ null, 16 pixels of bottom padding is
/// added to separate the [icon] from the [title]. If the [title] is null and
/// [content] is _not_ null, then no bottom padding is provided (but see
/// [contentPadding]). In any other case 24 pixels of bottom padding is
/// added.
final EdgeInsetsGeometry? iconPadding;
/// The (optional) title of the dialog is displayed in a large font at the top /// The (optional) title of the dialog is displayed in a large font at the top
/// of the dialog. /// of the dialog, below the (optional) [icon].
/// ///
/// Typically a [Text] widget. /// Typically a [Text] widget.
final Widget? title; final Widget? title;
...@@ -321,11 +348,17 @@ class AlertDialog extends StatelessWidget { ...@@ -321,11 +348,17 @@ class AlertDialog extends StatelessWidget {
/// Padding around the content. /// Padding around the content.
/// ///
/// If there is no content, no padding will be provided. Otherwise, padding of /// If there is no [content], no padding will be provided. Otherwise, this
/// 20 pixels is provided above the content to separate the content from the /// padding is used.
/// title, and padding of 24 pixels is provided on the left, right, and bottom ///
/// to separate the content from the other edges of the dialog. /// This property defaults to providing a padding of 20 pixels above the
final EdgeInsetsGeometry contentPadding; /// [content] to separate the [content] from the [title], and 24 pixels on the
/// left, right, and bottom to separate the [content] from the other edges of
/// the dialog.
///
/// If [ThemeData.useMaterial3] is true, the top padding separating the
/// content from the title defaults to 16 pixels instead of 20 pixels.
final EdgeInsetsGeometry? contentPadding;
/// Style for the text in the [content] of this [AlertDialog]. /// Style for the text in the [content] of this [AlertDialog].
/// ///
...@@ -508,21 +541,55 @@ class AlertDialog extends StatelessWidget { ...@@ -508,21 +541,55 @@ class AlertDialog extends StatelessWidget {
final double paddingScaleFactor = _paddingScaleFactor(MediaQuery.of(context).textScaleFactor); final double paddingScaleFactor = _paddingScaleFactor(MediaQuery.of(context).textScaleFactor);
final TextDirection? textDirection = Directionality.maybeOf(context); final TextDirection? textDirection = Directionality.maybeOf(context);
Widget? iconWidget;
Widget? titleWidget; Widget? titleWidget;
Widget? contentWidget; Widget? contentWidget;
Widget? actionsWidget; Widget? actionsWidget;
if (icon != null) {
final bool belowIsTitle = title != null;
final bool belowIsContent = !belowIsTitle && content != null;
final EdgeInsets defaultIconPadding = EdgeInsets.only(
left: 24.0,
top: 24.0,
right: 24.0,
bottom: belowIsTitle ? 16.0 : belowIsContent ? 0.0 : 24.0,
);
final EdgeInsets effectiveIconPadding = iconPadding?.resolve(textDirection) ?? defaultIconPadding;
iconWidget = Padding(
padding: EdgeInsets.only(
left: effectiveIconPadding.left * paddingScaleFactor,
right: effectiveIconPadding.right * paddingScaleFactor,
top: effectiveIconPadding.top * paddingScaleFactor,
bottom: effectiveIconPadding.bottom,
),
child: IconTheme(
data: IconThemeData(
color: iconColor ?? dialogTheme.iconColor ?? defaults.iconColor,
),
child: icon!,
),
);
}
if (title != null) { if (title != null) {
final EdgeInsets defaultTitlePadding = EdgeInsets.fromLTRB(24.0, 24.0, 24.0, content == null ? 20.0 : 0.0); final EdgeInsets defaultTitlePadding = EdgeInsets.only(
left: 24.0,
top: icon == null ? 24.0 : 0.0,
right: 24.0,
bottom: content == null ? 20.0 : 0.0,
);
final EdgeInsets effectiveTitlePadding = titlePadding?.resolve(textDirection) ?? defaultTitlePadding; final EdgeInsets effectiveTitlePadding = titlePadding?.resolve(textDirection) ?? defaultTitlePadding;
titleWidget = Padding( titleWidget = Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: effectiveTitlePadding.left * paddingScaleFactor, left: effectiveTitlePadding.left * paddingScaleFactor,
right: effectiveTitlePadding.right * paddingScaleFactor, right: effectiveTitlePadding.right * paddingScaleFactor,
top: effectiveTitlePadding.top * paddingScaleFactor, top: icon == null ? effectiveTitlePadding.top * paddingScaleFactor : effectiveTitlePadding.top,
bottom: effectiveTitlePadding.bottom, bottom: effectiveTitlePadding.bottom,
), ),
child: DefaultTextStyle( child: DefaultTextStyle(
style: titleTextStyle ?? dialogTheme.titleTextStyle ?? defaults.titleTextStyle!, style: titleTextStyle ?? dialogTheme.titleTextStyle ?? defaults.titleTextStyle!,
textAlign: icon == null ? TextAlign.start : TextAlign.center,
child: Semantics( child: Semantics(
// For iOS platform, the focus always lands on the title. // For iOS platform, the focus always lands on the title.
// Set nameRoute to false to avoid title being announce twice. // Set nameRoute to false to avoid title being announce twice.
...@@ -535,12 +602,20 @@ class AlertDialog extends StatelessWidget { ...@@ -535,12 +602,20 @@ class AlertDialog extends StatelessWidget {
} }
if (content != null) { if (content != null) {
final EdgeInsets effectiveContentPadding = contentPadding.resolve(textDirection); final EdgeInsets defaultContentPadding = EdgeInsets.only(
left: 24.0,
top: theme.useMaterial3 ? 16.0 : 20.0,
right: 24.0,
bottom: 24.0,
);
final EdgeInsets effectiveContentPadding = contentPadding?.resolve(textDirection) ?? defaultContentPadding;
contentWidget = Padding( contentWidget = Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: effectiveContentPadding.left * paddingScaleFactor, left: effectiveContentPadding.left * paddingScaleFactor,
right: effectiveContentPadding.right * paddingScaleFactor, right: effectiveContentPadding.right * paddingScaleFactor,
top: title == null ? effectiveContentPadding.top * paddingScaleFactor : effectiveContentPadding.top, top: title == null && icon == null
? effectiveContentPadding.top * paddingScaleFactor
: effectiveContentPadding.top,
bottom: effectiveContentPadding.bottom, bottom: effectiveContentPadding.bottom,
), ),
child: DefaultTextStyle( child: DefaultTextStyle(
...@@ -580,6 +655,7 @@ class AlertDialog extends StatelessWidget { ...@@ -580,6 +655,7 @@ class AlertDialog extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
if (icon != null) iconWidget!,
if (title != null) titleWidget!, if (title != null) titleWidget!,
if (content != null) contentWidget!, if (content != null) contentWidget!,
], ],
...@@ -591,6 +667,7 @@ class AlertDialog extends StatelessWidget { ...@@ -591,6 +667,7 @@ class AlertDialog extends StatelessWidget {
]; ];
} else { } else {
columnChildren = <Widget>[ columnChildren = <Widget>[
if (icon != null) iconWidget!,
if (title != null) titleWidget!, if (title != null) titleWidget!,
if (content != null) Flexible(child: contentWidget!), if (content != null) Flexible(child: contentWidget!),
if (actions != null) actionsWidget!, if (actions != null) actionsWidget!,
...@@ -1187,6 +1264,7 @@ double _paddingScaleFactor(double textScaleFactor) { ...@@ -1187,6 +1264,7 @@ double _paddingScaleFactor(double textScaleFactor) {
class _DefaultsM2 extends DialogTheme { class _DefaultsM2 extends DialogTheme {
_DefaultsM2(this.context) _DefaultsM2(this.context)
: _textTheme = Theme.of(context).textTheme, : _textTheme = Theme.of(context).textTheme,
_iconTheme = Theme.of(context).iconTheme,
super( super(
alignment: Alignment.center, alignment: Alignment.center,
elevation: 24.0, elevation: 24.0,
...@@ -1195,6 +1273,10 @@ class _DefaultsM2 extends DialogTheme { ...@@ -1195,6 +1273,10 @@ class _DefaultsM2 extends DialogTheme {
final BuildContext context; final BuildContext context;
final TextTheme _textTheme; final TextTheme _textTheme;
final IconThemeData _iconTheme;
@override
Color? get iconColor => _iconTheme.color;
@override @override
Color? get backgroundColor => Theme.of(context).dialogBackgroundColor; Color? get backgroundColor => Theme.of(context).dialogBackgroundColor;
...@@ -1228,6 +1310,9 @@ class _TokenDefaultsM3 extends DialogTheme { ...@@ -1228,6 +1310,9 @@ class _TokenDefaultsM3 extends DialogTheme {
late final ColorScheme _colors = Theme.of(context).colorScheme; late final ColorScheme _colors = Theme.of(context).colorScheme;
late final TextTheme _textTheme = Theme.of(context).textTheme; late final TextTheme _textTheme = Theme.of(context).textTheme;
@override
Color? get iconColor => _colors.secondary;
// TODO(darrenaustin): overlay should be handled by Material widget: https://github.com/flutter/flutter/issues/9160 // TODO(darrenaustin): overlay should be handled by Material widget: https://github.com/flutter/flutter/issues/9160
@override @override
Color? get backgroundColor => ElevationOverlay.colorWithOverlay(_colors.surface, _colors.primary, 6.0); Color? get backgroundColor => ElevationOverlay.colorWithOverlay(_colors.surface, _colors.primary, 6.0);
......
...@@ -32,6 +32,7 @@ class DialogTheme with Diagnosticable { ...@@ -32,6 +32,7 @@ class DialogTheme with Diagnosticable {
this.elevation, this.elevation,
this.shape, this.shape,
this.alignment, this.alignment,
this.iconColor,
this.titleTextStyle, this.titleTextStyle,
this.contentTextStyle, this.contentTextStyle,
this.actionsPadding, this.actionsPadding,
...@@ -60,6 +61,9 @@ class DialogTheme with Diagnosticable { ...@@ -60,6 +61,9 @@ class DialogTheme with Diagnosticable {
/// Overrides the default value for [AlertDialog.actionsPadding]. /// Overrides the default value for [AlertDialog.actionsPadding].
final EdgeInsetsGeometry? actionsPadding; final EdgeInsetsGeometry? actionsPadding;
/// Used to configure the [IconTheme] for the [AlertDialog.icon] widget.
final Color? iconColor;
/// Creates a copy of this object but with the given fields replaced with the /// Creates a copy of this object but with the given fields replaced with the
/// new values. /// new values.
DialogTheme copyWith({ DialogTheme copyWith({
...@@ -67,6 +71,7 @@ class DialogTheme with Diagnosticable { ...@@ -67,6 +71,7 @@ class DialogTheme with Diagnosticable {
double? elevation, double? elevation,
ShapeBorder? shape, ShapeBorder? shape,
AlignmentGeometry? alignment, AlignmentGeometry? alignment,
Color? iconColor,
TextStyle? titleTextStyle, TextStyle? titleTextStyle,
TextStyle? contentTextStyle, TextStyle? contentTextStyle,
EdgeInsetsGeometry? actionsPadding, EdgeInsetsGeometry? actionsPadding,
...@@ -76,6 +81,7 @@ class DialogTheme with Diagnosticable { ...@@ -76,6 +81,7 @@ class DialogTheme with Diagnosticable {
elevation: elevation ?? this.elevation, elevation: elevation ?? this.elevation,
shape: shape ?? this.shape, shape: shape ?? this.shape,
alignment: alignment ?? this.alignment, alignment: alignment ?? this.alignment,
iconColor: iconColor ?? this.iconColor,
titleTextStyle: titleTextStyle ?? this.titleTextStyle, titleTextStyle: titleTextStyle ?? this.titleTextStyle,
contentTextStyle: contentTextStyle ?? this.contentTextStyle, contentTextStyle: contentTextStyle ?? this.contentTextStyle,
actionsPadding: actionsPadding ?? this.actionsPadding, actionsPadding: actionsPadding ?? this.actionsPadding,
...@@ -99,6 +105,7 @@ class DialogTheme with Diagnosticable { ...@@ -99,6 +105,7 @@ class DialogTheme with Diagnosticable {
elevation: lerpDouble(a?.elevation, b?.elevation, t), elevation: lerpDouble(a?.elevation, b?.elevation, t),
shape: ShapeBorder.lerp(a?.shape, b?.shape, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t), alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t),
iconColor: Color.lerp(a?.iconColor, b?.iconColor, t),
titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t), titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t),
contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t), contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
actionsPadding: EdgeInsetsGeometry.lerp(a?.actionsPadding, b?.actionsPadding, t), actionsPadding: EdgeInsetsGeometry.lerp(a?.actionsPadding, b?.actionsPadding, t),
...@@ -121,6 +128,7 @@ class DialogTheme with Diagnosticable { ...@@ -121,6 +128,7 @@ class DialogTheme with Diagnosticable {
&& other.elevation == elevation && other.elevation == elevation
&& other.shape == shape && other.shape == shape
&& other.alignment == alignment && other.alignment == alignment
&& other.iconColor == iconColor
&& other.titleTextStyle == titleTextStyle && other.titleTextStyle == titleTextStyle
&& other.contentTextStyle == contentTextStyle && other.contentTextStyle == contentTextStyle
&& other.actionsPadding == actionsPadding; && other.actionsPadding == actionsPadding;
...@@ -133,6 +141,7 @@ class DialogTheme with Diagnosticable { ...@@ -133,6 +141,7 @@ class DialogTheme with Diagnosticable {
properties.add(DoubleProperty('elevation', elevation)); properties.add(DoubleProperty('elevation', elevation));
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null)); properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null)); properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
properties.add(ColorProperty('iconColor', iconColor));
properties.add(DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('actionsPadding', actionsPadding, defaultValue: null)); properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('actionsPadding', actionsPadding, defaultValue: null));
......
...@@ -754,19 +754,21 @@ void main() { ...@@ -754,19 +754,21 @@ void main() {
3.0: 1.0 / 3.0, 3.0: 1.0 / 3.0,
}; };
final GlobalKey iconKey = GlobalKey();
final GlobalKey titleKey = GlobalKey(); final GlobalKey titleKey = GlobalKey();
final GlobalKey contentKey = GlobalKey(); final GlobalKey contentKey = GlobalKey();
final GlobalKey childrenKey = GlobalKey(); final GlobalKey childrenKey = GlobalKey();
final Finder dialogFinder = find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first; final Finder dialogFinder = find.descendant(of: find.byType(Dialog), matching: find.byType(Material)).first;
final Finder iconFinder = find.byKey(iconKey);
final Finder titleFinder = find.byKey(titleKey); final Finder titleFinder = find.byKey(titleKey);
final Finder contentFinder = find.byKey(contentKey); final Finder contentFinder = find.byKey(contentKey);
final Finder actionsFinder = _findButtonBar(); final Finder actionsFinder = _findButtonBar();
final Finder childrenFinder = find.byKey(childrenKey); final Finder childrenFinder = find.byKey(childrenKey);
Future<void> openDialog(WidgetTester tester, Widget dialog, double textScaleFactor) async { Future<void> openDialog(WidgetTester tester, Widget dialog, double textScaleFactor, {bool isM3 = false}) async {
await tester.pumpWidget( await tester.pumpWidget(
_buildAppWithDialog(dialog, textScaleFactor: textScaleFactor), _buildAppWithDialog(dialog, textScaleFactor: textScaleFactor, theme: ThemeData(useMaterial3: isM3)),
); );
await tester.tap(find.text('X')); await tester.tap(find.text('X'));
...@@ -853,6 +855,10 @@ void main() { ...@@ -853,6 +855,10 @@ void main() {
); );
} }
final Widget icon = Icon(
Icons.ac_unit,
key: iconKey,
);
final Widget title = Text( final Widget title = Text(
'title', 'title',
key: titleKey, key: titleKey,
...@@ -876,7 +882,203 @@ void main() { ...@@ -876,7 +882,203 @@ void main() {
]; ];
for (final double textScaleFactor in textScaleFactors) { for (final double textScaleFactor in textScaleFactors) {
testWidgets('AlertDialog padding is correct when only title and actions are specified [textScaleFactor]=$textScaleFactor}', (WidgetTester tester) async { testWidgets('AlertDialog padding is correct when only icon and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async {
final AlertDialog dialog = AlertDialog(
icon: icon,
actions: actions,
);
await openDialog(tester, dialog, textScaleFactor);
expectTopEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectLeftEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectRightEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectVerticalInnerPadding(
tester,
top: iconFinder,
bottom: actionsFinder,
value: 24.0,
);
expectLeftEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
expectRightEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
expectBottomEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
});
testWidgets('AlertDialog padding is correct when only icon, title and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async {
final AlertDialog dialog = AlertDialog(
icon: icon,
title: title,
actions: actions,
);
await openDialog(tester, dialog, textScaleFactor);
expectTopEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectLeftEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectRightEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectVerticalInnerPadding(
tester,
top: iconFinder,
bottom: titleFinder,
value: 16.0,
);
expectLeftEdgePadding(
tester,
finder: titleFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectRightEdgePadding(
tester,
finder: titleFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectVerticalInnerPadding(
tester,
top: titleFinder,
bottom: actionsFinder,
value: 20.0,
);
expectLeftEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
expectRightEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
expectBottomEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
});
for (final bool isM3 in <bool>[true, false]) {
testWidgets('AlertDialog padding is correct when only icon, content and actions are specified [textScaleFactor]=$textScaleFactor [isM3]=$isM3', (WidgetTester tester) async {
final AlertDialog dialog = AlertDialog(
icon: icon,
content: content,
actions: actions,
);
await openDialog(tester, dialog, textScaleFactor, isM3: isM3);
expectTopEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectLeftEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectRightEdgePadding(
tester,
finder: iconFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectVerticalInnerPadding(
tester,
top: iconFinder,
bottom: contentFinder,
value: isM3 ? 16.0 : 20.0,
);
expectLeftEdgePadding(
tester,
finder: contentFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectRightEdgePadding(
tester,
finder: contentFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 24.0,
);
expectVerticalInnerPadding(
tester,
top: contentFinder,
bottom: actionsFinder,
value: 24.0,
);
expectLeftEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
expectRightEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
expectBottomEdgePadding(
tester,
finder: actionsFinder,
textScaleFactor: textScaleFactor,
unscaledValue: 0.0,
);
});
}
testWidgets('AlertDialog padding is correct when only title and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async {
final AlertDialog dialog = AlertDialog( final AlertDialog dialog = AlertDialog(
title: title, title: title,
actions: actions, actions: actions,
...@@ -928,7 +1130,7 @@ void main() { ...@@ -928,7 +1130,7 @@ void main() {
); );
}); });
testWidgets('AlertDialog padding is correct when only content and actions are specified [textScaleFactor]=$textScaleFactor}', (WidgetTester tester) async { testWidgets('AlertDialog padding is correct when only content and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async {
final AlertDialog dialog = AlertDialog( final AlertDialog dialog = AlertDialog(
content: content, content: content,
actions: actions, actions: actions,
...@@ -980,7 +1182,7 @@ void main() { ...@@ -980,7 +1182,7 @@ void main() {
); );
}); });
testWidgets('AlertDialog padding is correct when title, content, and actions are specified [textScaleFactor]=$textScaleFactor}', (WidgetTester tester) async { testWidgets('AlertDialog padding is correct when title, content, and actions are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async {
final AlertDialog dialog = AlertDialog( final AlertDialog dialog = AlertDialog(
title: title, title: title,
content: content, content: content,
...@@ -1051,7 +1253,7 @@ void main() { ...@@ -1051,7 +1253,7 @@ void main() {
); );
}); });
testWidgets('SimpleDialog padding is correct when only children are specified [textScaleFactor]=$textScaleFactor}', (WidgetTester tester) async { testWidgets('SimpleDialog padding is correct when only children are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async {
final SimpleDialog dialog = SimpleDialog( final SimpleDialog dialog = SimpleDialog(
children: children, children: children,
); );
...@@ -1084,7 +1286,7 @@ void main() { ...@@ -1084,7 +1286,7 @@ void main() {
); );
}); });
testWidgets('SimpleDialog padding is correct when title and children are specified [textScaleFactor]=$textScaleFactor}', (WidgetTester tester) async { testWidgets('SimpleDialog padding is correct when title and children are specified [textScaleFactor]=$textScaleFactor', (WidgetTester tester) async {
final SimpleDialog dialog = SimpleDialog( final SimpleDialog dialog = SimpleDialog(
title: title, title: title,
children: children, children: children,
......
...@@ -52,6 +52,7 @@ void main() { ...@@ -52,6 +52,7 @@ void main() {
backgroundColor: Color(0xff123456), backgroundColor: Color(0xff123456),
elevation: 8.0, elevation: 8.0,
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,
iconColor: Color(0xff654321),
titleTextStyle: TextStyle(color: Color(0xffffffff)), titleTextStyle: TextStyle(color: Color(0xffffffff)),
contentTextStyle: TextStyle(color: Color(0xff000000)), contentTextStyle: TextStyle(color: Color(0xff000000)),
actionsPadding: EdgeInsets.all(8.0), actionsPadding: EdgeInsets.all(8.0),
...@@ -63,6 +64,7 @@ void main() { ...@@ -63,6 +64,7 @@ void main() {
'backgroundColor: Color(0xff123456)', 'backgroundColor: Color(0xff123456)',
'elevation: 8.0', 'elevation: 8.0',
'alignment: Alignment.bottomLeft', 'alignment: Alignment.bottomLeft',
'iconColor: Color(0xff654321)',
'titleTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))', 'titleTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))',
'contentTextStyle: TextStyle(inherit: true, color: Color(0xff000000))', 'contentTextStyle: TextStyle(inherit: true, color: Color(0xff000000))',
'actionsPadding: EdgeInsets.all(8.0)', 'actionsPadding: EdgeInsets.all(8.0)',
...@@ -182,6 +184,80 @@ void main() { ...@@ -182,6 +184,80 @@ void main() {
); );
}); });
testWidgets('Custom Icon Color - Constructor Param - highest preference', (WidgetTester tester) async {
const Color iconColor = Colors.pink, dialogThemeColor = Colors.green, iconThemeColor = Colors.yellow;
final ThemeData theme = ThemeData(
iconTheme: const IconThemeData(color: iconThemeColor),
dialogTheme: const DialogTheme(iconColor: dialogThemeColor),
);
const AlertDialog dialog = AlertDialog(
icon: Icon(Icons.ac_unit),
iconColor: iconColor,
actions: <Widget>[ ],
);
await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
// first is Text('X')
final RichText text = tester.widget(find.byType(RichText).last);
expect(text.text.style!.color, iconColor);
});
testWidgets('Custom Icon Color - Dialog Theme - preference over Theme', (WidgetTester tester) async {
const Color dialogThemeColor = Colors.green, iconThemeColor = Colors.yellow;
final ThemeData theme = ThemeData(
iconTheme: const IconThemeData(color: iconThemeColor),
dialogTheme: const DialogTheme(iconColor: dialogThemeColor),
);
const AlertDialog dialog = AlertDialog(
icon: Icon(Icons.ac_unit),
actions: <Widget>[ ],
);
await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
// first is Text('X')
final RichText text = tester.widget(find.byType(RichText).last);
expect(text.text.style!.color, dialogThemeColor);
});
testWidgets('Custom Icon Color - Theme - lowest preference', (WidgetTester tester) async {
const Color iconThemeColor = Colors.yellow;
final ThemeData theme = ThemeData(iconTheme: const IconThemeData(color: iconThemeColor));
const AlertDialog dialog = AlertDialog(
icon: Icon(Icons.ac_unit),
actions: <Widget>[ ],
);
await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
// first is Text('X')
final RichText text = tester.widget(find.byType(RichText).last);
expect(text.text.style!.color, iconThemeColor);
});
testWidgets('Custom Icon Color - Theme - lowest preference for M3', (WidgetTester tester) async {
final ThemeData theme = ThemeData(useMaterial3: true);
const AlertDialog dialog = AlertDialog(
icon: Icon(Icons.ac_unit),
actions: <Widget>[ ],
);
await tester.pumpWidget(_appWithDialog(tester, dialog, theme: theme));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
// first is Text('X')
final RichText text = tester.widget(find.byType(RichText).last);
expect(text.text.style!.color, ThemeData().colorScheme.secondary);
});
testWidgets('Custom Title Text Style - Constructor Param', (WidgetTester tester) async { testWidgets('Custom Title Text Style - Constructor Param', (WidgetTester tester) async {
const String titleText = 'Title'; const String titleText = 'Title';
const TextStyle titleTextStyle = TextStyle(color: Colors.pink); const TextStyle titleTextStyle = TextStyle(color: Colors.pink);
......
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