mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
feat: add icon to AlertDialog (#104920)
This commit is contained in:
parent
e649210f39
commit
672859a0cb
@ -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 {
|
|||||||
///
|
///
|
||||||
/// 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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
/// 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 {
|
|||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
];
|
];
|
||||||
} 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) {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// 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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
&& 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 {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
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() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
'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() {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user