Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reland "Add shadowColor and surfaceTintColor to Dialog and DialogTheme." #108718

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions dev/tools/gen_defaults/lib/dialog_template.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ class _${blockName}DefaultsM3 extends DialogTheme {
@override
Color? get iconColor => _colors.secondary;

// TODO(darrenaustin): overlay should be handled by Material widget: https://github.com/flutter/flutter/issues/9160
@override
Color? get backgroundColor => ElevationOverlay.colorWithOverlay(${componentColor("md.comp.dialog.container")}, _colors.primary, ${elevation("md.comp.dialog.container")});
Color? get backgroundColor => ${componentColor("md.comp.dialog.container")};

@override
Color? get surfaceTintColor => ${componentColor("md.comp.dialog.container.surface-tint-layer")};

@override
TextStyle? get titleTextStyle => ${textStyle("md.comp.dialog.headline")};
Expand Down
86 changes: 77 additions & 9 deletions packages/flutter/lib/src/material/dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import 'color_scheme.dart';
import 'colors.dart';
import 'debug.dart';
import 'dialog_theme.dart';
import 'elevation_overlay.dart';
import 'ink_well.dart';
import 'material.dart';
import 'material_localizations.dart';
Expand Down Expand Up @@ -46,14 +45,17 @@ class Dialog extends StatelessWidget {
super.key,
this.backgroundColor,
this.elevation,
this.shadowColor,
this.surfaceTintColor,
this.insetAnimationDuration = const Duration(milliseconds: 100),
this.insetAnimationCurve = Curves.decelerate,
this.insetPadding = _defaultInsetPadding,
this.clipBehavior = Clip.none,
this.shape,
this.alignment,
this.child,
}) : assert(clipBehavior != null);
}) : assert(clipBehavior != null),
assert(elevation == null || elevation >= 0.0);

/// {@template flutter.material.dialog.backgroundColor}
/// The background color of the surface of this [Dialog].
Expand All @@ -67,12 +69,53 @@ class Dialog extends StatelessWidget {
/// {@template flutter.material.dialog.elevation}
/// The z-coordinate of this [Dialog].
///
/// If null then [DialogTheme.elevation] is used, and if that's null then the
/// dialog's elevation is 24.0.
/// Controls how far above the parent the dialog will appear. Elevation is
/// represented by a drop shadow if [shadowColor] is non null,
/// and a surface tint overlay on the background color if [surfaceTintColor] is
/// non null.
///
/// If null then [DialogTheme.elevation] is used, and if that is null then
/// the elevation will match the Material Design specification for Dialogs.
///
/// See also:
/// * [Material.elevation], which describes how [elevation] effects the
/// drop shadow or surface tint overlay.
/// * [shadowColor], color of the drop shadow used to indicate the elevation.
/// * [surfaceTintColor], color of an overlay on top of the background
/// color used to indicate the elevation.
/// * <https://m3.material.io/components/dialogs/overview>, the Material
/// Design specification for dialogs.
/// {@endtemplate}
/// {@macro flutter.material.material.elevation}
final double? elevation;

/// {@template flutter.material.dialog.shadowColor}
/// The color to paint the [elevation] shadow under the dialog's [Material].
///
/// If null then no drop shadow will be painted.
///
/// See also:
/// * [Material.shadowColor], which describes how the drop shadow is painted.
/// * [elevation], effects how the drop shadow is painted.
/// * [surfaceTintColor], if non-null will also provide a surface tint
/// overlay on the background color to indicate elevation.
/// {@endtemplate}
final Color? shadowColor;

/// {@template flutter.material.dialog.surfaceTintColor}
/// The color used as a surface tint overlay on the dialog's background color,
/// which reflects the dialog's [elevation].
///
/// If null then no surface tint will be applied.
///
/// See also:
/// * [Material.surfaceTintColor], which describes how the surface tint will
/// be applied to the background color of the dialog.
/// * [elevation], effects the opacity of the surface tint.
/// * [shadowColor], if non-null will also provide a drop shadow to
/// indicate elevation.
/// {@endtemplate}
final Color? surfaceTintColor;

/// {@template flutter.material.dialog.insetAnimationDuration}
/// The duration of the animation to show when the system keyboard intrudes
/// into the space that the dialog is placed in.
Expand Down Expand Up @@ -155,6 +198,8 @@ class Dialog extends StatelessWidget {
child: Material(
color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor,
elevation: elevation ?? dialogTheme.elevation ?? defaults.elevation!,
shadowColor: shadowColor ?? dialogTheme.shadowColor ?? defaults.shadowColor,
surfaceTintColor: surfaceTintColor ?? dialogTheme.surfaceTintColor ?? defaults.surfaceTintColor,
shape: shape ?? dialogTheme.shape ?? defaults.shape!,
type: MaterialType.card,
clipBehavior: clipBehavior,
Expand Down Expand Up @@ -280,6 +325,8 @@ class AlertDialog extends StatelessWidget {
this.buttonPadding,
this.backgroundColor,
this.elevation,
this.shadowColor,
this.surfaceTintColor,
this.semanticLabel,
this.insetPadding = _defaultInsetPadding,
this.clipBehavior = Clip.none,
Expand Down Expand Up @@ -478,9 +525,14 @@ class AlertDialog extends StatelessWidget {
final Color? backgroundColor;

/// {@macro flutter.material.dialog.elevation}
/// {@macro flutter.material.material.elevation}
final double? elevation;

/// {@macro flutter.material.dialog.shadowColor}
final Color? shadowColor;

/// {@macro flutter.material.dialog.surfaceTintColor}
final Color? surfaceTintColor;

/// The semantic label of the dialog used by accessibility frameworks to
/// announce screen transitions when the dialog is opened and closed.
///
Expand Down Expand Up @@ -695,6 +747,8 @@ class AlertDialog extends StatelessWidget {
return Dialog(
backgroundColor: backgroundColor,
elevation: elevation,
shadowColor: shadowColor,
surfaceTintColor: surfaceTintColor,
insetPadding: insetPadding,
clipBehavior: clipBehavior,
shape: shape,
Expand Down Expand Up @@ -860,6 +914,8 @@ class SimpleDialog extends StatelessWidget {
this.contentPadding = const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0),
this.backgroundColor,
this.elevation,
this.shadowColor,
this.surfaceTintColor,
this.semanticLabel,
this.insetPadding = _defaultInsetPadding,
this.clipBehavior = Clip.none,
Expand Down Expand Up @@ -915,9 +971,14 @@ class SimpleDialog extends StatelessWidget {
final Color? backgroundColor;

/// {@macro flutter.material.dialog.elevation}
/// {@macro flutter.material.material.elevation}
final double? elevation;

/// {@macro flutter.material.dialog.shadowColor}
final Color? shadowColor;

/// {@macro flutter.material.dialog.surfaceTintColor}
final Color? surfaceTintColor;

/// The semantic label of the dialog used by accessibility frameworks to
/// announce screen transitions when the dialog is opened and closed.
///
Expand Down Expand Up @@ -1031,6 +1092,8 @@ class SimpleDialog extends StatelessWidget {
return Dialog(
backgroundColor: backgroundColor,
elevation: elevation,
shadowColor: shadowColor,
surfaceTintColor: surfaceTintColor,
insetPadding: insetPadding,
clipBehavior: clipBehavior,
shape: shape,
Expand Down Expand Up @@ -1296,6 +1359,9 @@ class _DialogDefaultsM2 extends DialogTheme {
@override
Color? get backgroundColor => Theme.of(context).dialogBackgroundColor;

@override
Color? get shadowColor => Theme.of(context).shadowColor;

@override
TextStyle? get titleTextStyle => _textTheme.headline6;

Expand Down Expand Up @@ -1330,9 +1396,11 @@ class _DialogDefaultsM3 extends DialogTheme {
@override
Color? get iconColor => _colors.secondary;

// TODO(darrenaustin): overlay should be handled by Material widget: https://github.com/flutter/flutter/issues/9160
@override
Color? get backgroundColor => ElevationOverlay.colorWithOverlay(_colors.surface, _colors.primary, 6.0);
Color? get backgroundColor => _colors.surface;

@override
Color? get surfaceTintColor => _colors.surfaceTint;

@override
TextStyle? get titleTextStyle => _textTheme.headlineSmall;
Expand Down
18 changes: 18 additions & 0 deletions packages/flutter/lib/src/material/dialog_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ class DialogTheme with Diagnosticable {
const DialogTheme({
this.backgroundColor,
this.elevation,
this.shadowColor,
this.surfaceTintColor,
this.shape,
this.alignment,
this.iconColor,
Expand All @@ -44,6 +46,12 @@ class DialogTheme with Diagnosticable {
/// Overrides the default value for [Dialog.elevation].
final double? elevation;

/// Overrides the default value for [Dialog.shadowColor].
final Color? shadowColor;

/// Overrides the default value for [Dialog.surfaceTintColor].
final Color? surfaceTintColor;

/// Overrides the default value for [Dialog.shape].
final ShapeBorder? shape;

Expand All @@ -69,6 +77,8 @@ class DialogTheme with Diagnosticable {
DialogTheme copyWith({
Color? backgroundColor,
double? elevation,
Color? shadowColor,
Color? surfaceTintColor,
ShapeBorder? shape,
AlignmentGeometry? alignment,
Color? iconColor,
Expand All @@ -79,6 +89,8 @@ class DialogTheme with Diagnosticable {
return DialogTheme(
backgroundColor: backgroundColor ?? this.backgroundColor,
elevation: elevation ?? this.elevation,
shadowColor: shadowColor ?? this.shadowColor,
surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor,
shape: shape ?? this.shape,
alignment: alignment ?? this.alignment,
iconColor: iconColor ?? this.iconColor,
Expand All @@ -103,6 +115,8 @@ class DialogTheme with Diagnosticable {
return DialogTheme(
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t),
shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t),
shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t),
iconColor: Color.lerp(a?.iconColor, b?.iconColor, t),
Expand All @@ -126,6 +140,8 @@ class DialogTheme with Diagnosticable {
return other is DialogTheme
&& other.backgroundColor == backgroundColor
&& other.elevation == elevation
&& other.shadowColor == shadowColor
&& other.surfaceTintColor == surfaceTintColor
&& other.shape == shape
&& other.alignment == alignment
&& other.iconColor == iconColor
Expand All @@ -139,6 +155,8 @@ class DialogTheme with Diagnosticable {
super.debugFillProperties(properties);
properties.add(ColorProperty('backgroundColor', backgroundColor));
properties.add(DoubleProperty('elevation', elevation));
properties.add(ColorProperty('shadowColor', shadowColor));
properties.add(ColorProperty('surfaceTintColor', surfaceTintColor));
properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
properties.add(ColorProperty('iconColor', iconColor));
Expand Down
6 changes: 6 additions & 0 deletions packages/flutter/test/material/dialog_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,13 @@ void main() {

testWidgets('Custom dialog elevation', (WidgetTester tester) async {
const double customElevation = 12.0;
const Color shadowColor = Color(0xFF000001);
const Color surfaceTintColor = Color(0xFF000002);
const AlertDialog dialog = AlertDialog(
actions: <Widget>[ ],
elevation: customElevation,
shadowColor: shadowColor,
surfaceTintColor: surfaceTintColor,
);
await tester.pumpWidget(_buildAppWithDialog(dialog));

Expand All @@ -151,6 +155,8 @@ void main() {

final Material materialWidget = _getMaterialFromDialog(tester);
expect(materialWidget.elevation, customElevation);
expect(materialWidget.shadowColor, shadowColor);
expect(materialWidget.surfaceTintColor, surfaceTintColor);
});

testWidgets('Custom Title Text Style', (WidgetTester tester) async {
Expand Down
16 changes: 15 additions & 1 deletion packages/flutter/test/material/dialog_theme_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ void main() {
const DialogTheme(
backgroundColor: Color(0xff123456),
elevation: 8.0,
shadowColor: Color(0xff000001),
surfaceTintColor: Color(0xff000002),
alignment: Alignment.bottomLeft,
iconColor: Color(0xff654321),
titleTextStyle: TextStyle(color: Color(0xffffffff)),
Expand All @@ -63,6 +65,8 @@ void main() {
expect(description, <String>[
'backgroundColor: Color(0xff123456)',
'elevation: 8.0',
'shadowColor: Color(0xff000001)',
'surfaceTintColor: Color(0xff000002)',
'alignment: Alignment.bottomLeft',
'iconColor: Color(0xff654321)',
'titleTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))',
Expand All @@ -89,11 +93,19 @@ void main() {

testWidgets('Custom dialog elevation', (WidgetTester tester) async {
const double customElevation = 12.0;
const Color shadowColor = Color(0xFF000001);
const Color surfaceTintColor = Color(0xFF000002);
const AlertDialog dialog = AlertDialog(
title: Text('Title'),
actions: <Widget>[ ],
);
final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(elevation: customElevation));
final ThemeData theme = ThemeData(
dialogTheme: const DialogTheme(
elevation: customElevation,
shadowColor: shadowColor,
surfaceTintColor: surfaceTintColor,
),
);

await tester.pumpWidget(
_appWithDialog(tester, dialog, theme: theme),
Expand All @@ -103,6 +115,8 @@ void main() {

final Material materialWidget = _getMaterialFromDialog(tester);
expect(materialWidget.elevation, customElevation);
expect(materialWidget.shadowColor, shadowColor);
expect(materialWidget.surfaceTintColor, surfaceTintColor);
});

testWidgets('Custom dialog shape', (WidgetTester tester) async {
Expand Down