1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'dialog.dart';
6library;
7
8import 'dart:ui' show lerpDouble;
9
10import 'package:flutter/foundation.dart';
11import 'package:flutter/widgets.dart';
12
13import 'theme.dart';
14
15/// Defines a theme for [Dialog] widgets.
16///
17/// Descendant widgets obtain the current [DialogThemeData] object using
18/// [DialogTheme.of]. Instances of [DialogTheme] can be customized with
19/// [DialogTheme.copyWith].
20///
21/// [titleTextStyle] and [contentTextStyle] are used in [AlertDialog]s and [SimpleDialog]s.
22///
23/// See also:
24///
25/// * [Dialog], a dialog that can be customized using this [DialogTheme].
26/// * [AlertDialog], a dialog that can be customized using this [DialogTheme].
27/// * [SimpleDialog], a dialog that can be customized using this [DialogTheme].
28/// * [ThemeData], which describes the overall theme information for the
29/// application.
30@immutable
31class DialogTheme extends InheritedTheme with Diagnosticable {
32 /// Creates a dialog theme that can be used for [ThemeData.dialogTheme].
33 const DialogTheme({
34 super.key,
35 Color? backgroundColor,
36 double? elevation,
37 Color? shadowColor,
38 Color? surfaceTintColor,
39 ShapeBorder? shape,
40 AlignmentGeometry? alignment,
41 Color? iconColor,
42 TextStyle? titleTextStyle,
43 TextStyle? contentTextStyle,
44 EdgeInsetsGeometry? actionsPadding,
45 Color? barrierColor,
46 EdgeInsets? insetPadding,
47 Clip? clipBehavior,
48 DialogThemeData? data,
49 Widget? child,
50 }) : assert(
51 data == null ||
52 (backgroundColor ??
53 elevation ??
54 shadowColor ??
55 surfaceTintColor ??
56 shape ??
57 alignment ??
58 iconColor ??
59 titleTextStyle ??
60 contentTextStyle ??
61 actionsPadding ??
62 barrierColor ??
63 insetPadding ??
64 clipBehavior) ==
65 null,
66 ),
67 _data = data,
68 _backgroundColor = backgroundColor,
69 _elevation = elevation,
70 _shadowColor = shadowColor,
71 _surfaceTintColor = surfaceTintColor,
72 _shape = shape,
73 _alignment = alignment,
74 _iconColor = iconColor,
75 _titleTextStyle = titleTextStyle,
76 _contentTextStyle = contentTextStyle,
77 _actionsPadding = actionsPadding,
78 _barrierColor = barrierColor,
79 _insetPadding = insetPadding,
80 _clipBehavior = clipBehavior,
81 super(child: child ?? const SizedBox());
82
83 final DialogThemeData? _data;
84 final Color? _backgroundColor;
85 final double? _elevation;
86 final Color? _shadowColor;
87 final Color? _surfaceTintColor;
88 final ShapeBorder? _shape;
89 final AlignmentGeometry? _alignment;
90 final TextStyle? _titleTextStyle;
91 final TextStyle? _contentTextStyle;
92 final EdgeInsetsGeometry? _actionsPadding;
93 final Color? _iconColor;
94 final Color? _barrierColor;
95 final EdgeInsets? _insetPadding;
96 final Clip? _clipBehavior;
97
98 /// Overrides the default value for [Dialog.backgroundColor].
99 ///
100 /// This property is obsolete and will be deprecated in a future release:
101 /// please use the [DialogThemeData.backgroundColor] property in [data] instead.
102 Color? get backgroundColor => _data != null ? _data.backgroundColor : _backgroundColor;
103
104 /// Overrides the default value for [Dialog.elevation].
105 ///
106 /// This property is obsolete and will be deprecated in a future release:
107 /// please use the [DialogThemeData.elevation] property in [data] instead.
108 double? get elevation => _data != null ? _data.elevation : _elevation;
109
110 /// Overrides the default value for [Dialog.shadowColor].
111 ///
112 /// This property is obsolete and will be deprecated in a future release:
113 /// please use the [DialogThemeData.shadowColor] property in [data] instead.
114 Color? get shadowColor => _data != null ? _data.shadowColor : _shadowColor;
115
116 /// Overrides the default value for [Dialog.surfaceTintColor].
117 ///
118 /// This property is obsolete and will be deprecated in a future release:
119 /// please use the [DialogThemeData.surfaceTintColor] property in [data] instead.
120 Color? get surfaceTintColor => _data != null ? _data.surfaceTintColor : _surfaceTintColor;
121
122 /// Overrides the default value for [Dialog.shape].
123 ///
124 /// This property is obsolete and will be deprecated in a future release:
125 /// please use the [DialogThemeData.shape] property in [data] instead.
126 ShapeBorder? get shape => _data != null ? _data.shape : _shape;
127
128 /// Overrides the default value for [Dialog.alignment].
129 ///
130 /// This property is obsolete and will be deprecated in a future release:
131 /// please use the [DialogThemeData.alignment] property in [data] instead.
132 AlignmentGeometry? get alignment => _data != null ? _data.alignment : _alignment;
133
134 /// Overrides the default value for [DefaultTextStyle] for [SimpleDialog.title] and
135 /// [AlertDialog.title].
136 ///
137 /// This property is obsolete and will be deprecated in a future release:
138 /// please use the [DialogThemeData.titleTextStyle] property in [data] instead.
139 TextStyle? get titleTextStyle => _data != null ? _data.titleTextStyle : _titleTextStyle;
140
141 /// Overrides the default value for [DefaultTextStyle] for [SimpleDialog.children] and
142 /// [AlertDialog.content].
143 ///
144 /// This property is obsolete and will be deprecated in a future release:
145 /// please use the [DialogThemeData.contentTextStyle] property in [data] instead.
146 TextStyle? get contentTextStyle => _data != null ? _data.contentTextStyle : _contentTextStyle;
147
148 /// Overrides the default value for [AlertDialog.actionsPadding].
149 ///
150 /// This property is obsolete and will be deprecated in a future release:
151 /// please use the [DialogThemeData.actionsPadding] property in [data] instead.
152 EdgeInsetsGeometry? get actionsPadding => _data != null ? _data.actionsPadding : _actionsPadding;
153
154 /// Used to configure the [IconTheme] for the [AlertDialog.icon] widget.
155 ///
156 /// This property is obsolete and will be deprecated in a future release:
157 /// please use the [DialogThemeData.iconColor] property in [data] instead.
158 Color? get iconColor => _data != null ? _data.iconColor : _iconColor;
159
160 /// Overrides the default value for [barrierColor] in [showDialog].
161 ///
162 /// This property is obsolete and will be deprecated in a future release:
163 /// please use the [DialogThemeData.barrierColor] property in [data] instead.
164 Color? get barrierColor => _data != null ? _data.barrierColor : _barrierColor;
165
166 /// Overrides the default value for [Dialog.insetPadding].
167 EdgeInsets? get insetPadding => _data != null ? _data.insetPadding : _insetPadding;
168
169 /// Overrides the default value of [Dialog.clipBehavior].
170 ///
171 /// This property is obsolete and will be deprecated in a future release:
172 /// please use the [DialogThemeData.clipBehavior] property in [data] instead.
173 Clip? get clipBehavior => _data != null ? _data.clipBehavior : _clipBehavior;
174
175 /// The properties used for all descendant [Dialog] widgets.
176 DialogThemeData get data {
177 return _data ??
178 DialogThemeData(
179 backgroundColor: _backgroundColor,
180 elevation: _elevation,
181 shadowColor: _shadowColor,
182 surfaceTintColor: _surfaceTintColor,
183 shape: _shape,
184 alignment: _alignment,
185 iconColor: _iconColor,
186 titleTextStyle: _titleTextStyle,
187 contentTextStyle: _contentTextStyle,
188 actionsPadding: _actionsPadding,
189 barrierColor: _barrierColor,
190 insetPadding: _insetPadding,
191 clipBehavior: _clipBehavior,
192 );
193 }
194
195 /// The [ThemeData.dialogTheme] property of the ambient [Theme].
196 static DialogThemeData of(BuildContext context) {
197 final DialogTheme? dialogTheme = context.dependOnInheritedWidgetOfExactType<DialogTheme>();
198 return dialogTheme?.data ?? Theme.of(context).dialogTheme;
199 }
200
201 @override
202 Widget wrap(BuildContext context, Widget child) {
203 return DialogTheme(data: data, child: child);
204 }
205
206 @override
207 bool updateShouldNotify(DialogTheme oldWidget) => data != oldWidget.data;
208
209 /// Creates a copy of this object but with the given fields replaced with the
210 /// new values.
211 ///
212 /// This method is obsolete and will be deprecated in a future release:
213 /// please use the [DialogThemeData.copyWith] instead.
214 DialogTheme copyWith({
215 Color? backgroundColor,
216 double? elevation,
217 Color? shadowColor,
218 Color? surfaceTintColor,
219 ShapeBorder? shape,
220 AlignmentGeometry? alignment,
221 Color? iconColor,
222 TextStyle? titleTextStyle,
223 TextStyle? contentTextStyle,
224 EdgeInsetsGeometry? actionsPadding,
225 Color? barrierColor,
226 EdgeInsets? insetPadding,
227 Clip? clipBehavior,
228 }) {
229 return DialogTheme(
230 backgroundColor: backgroundColor ?? this.backgroundColor,
231 elevation: elevation ?? this.elevation,
232 shadowColor: shadowColor ?? this.shadowColor,
233 surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor,
234 shape: shape ?? this.shape,
235 alignment: alignment ?? this.alignment,
236 iconColor: iconColor ?? this.iconColor,
237 titleTextStyle: titleTextStyle ?? this.titleTextStyle,
238 contentTextStyle: contentTextStyle ?? this.contentTextStyle,
239 actionsPadding: actionsPadding ?? this.actionsPadding,
240 barrierColor: barrierColor ?? this.barrierColor,
241 insetPadding: insetPadding ?? this.insetPadding,
242 clipBehavior: clipBehavior ?? this.clipBehavior,
243 );
244 }
245
246 /// Linearly interpolate between two dialog themes.
247 ///
248 /// {@macro dart.ui.shadow.lerp}
249 ///
250 /// This method is obsolete and will be deprecated in a future release:
251 /// please use the [DialogThemeData.lerp] instead.
252 static DialogTheme lerp(DialogTheme? a, DialogTheme? b, double t) {
253 if (identical(a, b) && a != null) {
254 return a;
255 }
256 return DialogTheme(
257 backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
258 elevation: lerpDouble(a?.elevation, b?.elevation, t),
259 shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
260 surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t),
261 shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
262 alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t),
263 iconColor: Color.lerp(a?.iconColor, b?.iconColor, t),
264 titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t),
265 contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
266 actionsPadding: EdgeInsetsGeometry.lerp(a?.actionsPadding, b?.actionsPadding, t),
267 barrierColor: Color.lerp(a?.barrierColor, b?.barrierColor, t),
268 insetPadding: EdgeInsets.lerp(a?.insetPadding, b?.insetPadding, t),
269 clipBehavior: t < 0.5 ? a?.clipBehavior : b?.clipBehavior,
270 );
271 }
272
273 @override
274 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
275 super.debugFillProperties(properties);
276 properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
277 properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
278 properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null));
279 properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null));
280 properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
281 properties.add(
282 DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null),
283 );
284 properties.add(ColorProperty('iconColor', iconColor, defaultValue: null));
285 properties.add(
286 DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null),
287 );
288 properties.add(
289 DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null),
290 );
291 properties.add(
292 DiagnosticsProperty<EdgeInsetsGeometry>('actionsPadding', actionsPadding, defaultValue: null),
293 );
294 properties.add(ColorProperty('barrierColor', barrierColor, defaultValue: null));
295 properties.add(
296 DiagnosticsProperty<EdgeInsets>('insetPadding', insetPadding, defaultValue: null),
297 );
298 properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior, defaultValue: null));
299 }
300}
301
302/// Defines default property values for descendant [Dialog] widgets.
303///
304/// Descendant widgets obtain the current [DialogThemeData] object using
305/// [DialogTheme.of]. Instances of [DialogThemeData] can be
306/// customized with [DialogThemeData.copyWith].
307///
308/// Typically a [DialogThemeData] is specified as part of the overall [Theme]
309/// with [ThemeData.dialogTheme].
310///
311/// All [DialogThemeData] properties are `null` by default. When null, the [Dialog]
312/// will use the values from [ThemeData] if they exist, otherwise it will
313/// provide its own defaults. See the individual [Dialog] properties for details.
314///
315/// See also:
316///
317/// * [Dialog], a dialog that can be customized using this [DialogTheme].
318/// * [AlertDialog], a dialog that can be customized using this [DialogTheme].
319/// * [SimpleDialog], a dialog that can be customized using this [DialogTheme].
320/// * [ThemeData], which describes the overall theme information for the
321/// application.
322@immutable
323class DialogThemeData with Diagnosticable {
324 /// Creates a dialog theme that can be used for [ThemeData.dialogTheme].
325 const DialogThemeData({
326 this.backgroundColor,
327 this.elevation,
328 this.shadowColor,
329 this.surfaceTintColor,
330 this.shape,
331 this.alignment,
332 this.iconColor,
333 this.titleTextStyle,
334 this.contentTextStyle,
335 this.actionsPadding,
336 this.barrierColor,
337 this.insetPadding,
338 this.clipBehavior,
339 this.constraints,
340 });
341
342 /// Overrides the default value for [Dialog.backgroundColor].
343 final Color? backgroundColor;
344
345 /// Overrides the default value for [Dialog.elevation].
346 final double? elevation;
347
348 /// Overrides the default value for [Dialog.shadowColor].
349 final Color? shadowColor;
350
351 /// Overrides the default value for [Dialog.surfaceTintColor].
352 final Color? surfaceTintColor;
353
354 /// Overrides the default value for [Dialog.shape].
355 final ShapeBorder? shape;
356
357 /// Overrides the default value for [Dialog.alignment].
358 final AlignmentGeometry? alignment;
359
360 /// Overrides the default value for [DefaultTextStyle] for [SimpleDialog.title] and
361 /// [AlertDialog.title].
362 final TextStyle? titleTextStyle;
363
364 /// Overrides the default value for [DefaultTextStyle] for [SimpleDialog.children] and
365 /// [AlertDialog.content].
366 final TextStyle? contentTextStyle;
367
368 /// Overrides the default value for [AlertDialog.actionsPadding].
369 final EdgeInsetsGeometry? actionsPadding;
370
371 /// Used to configure the [IconTheme] for the [AlertDialog.icon] widget.
372 final Color? iconColor;
373
374 /// Overrides the default value for [barrierColor] in [showDialog].
375 final Color? barrierColor;
376
377 /// Overrides the default value for [Dialog.insetPadding].
378 final EdgeInsets? insetPadding;
379
380 /// Overrides the default value of [Dialog.clipBehavior].
381 final Clip? clipBehavior;
382
383 /// Constrains the size of the [Dialog].
384 ///
385 /// If null, the bottom sheet's size will be unconstrained.
386 final BoxConstraints? constraints;
387
388 /// Creates a copy of this object but with the given fields replaced with the
389 /// new values.
390 DialogThemeData copyWith({
391 Color? backgroundColor,
392 double? elevation,
393 Color? shadowColor,
394 Color? surfaceTintColor,
395 ShapeBorder? shape,
396 AlignmentGeometry? alignment,
397 Color? iconColor,
398 TextStyle? titleTextStyle,
399 TextStyle? contentTextStyle,
400 EdgeInsetsGeometry? actionsPadding,
401 Color? barrierColor,
402 EdgeInsets? insetPadding,
403 Clip? clipBehavior,
404 BoxConstraints? constraints,
405 }) {
406 return DialogThemeData(
407 backgroundColor: backgroundColor ?? this.backgroundColor,
408 elevation: elevation ?? this.elevation,
409 shadowColor: shadowColor ?? this.shadowColor,
410 surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor,
411 shape: shape ?? this.shape,
412 alignment: alignment ?? this.alignment,
413 iconColor: iconColor ?? this.iconColor,
414 titleTextStyle: titleTextStyle ?? this.titleTextStyle,
415 contentTextStyle: contentTextStyle ?? this.contentTextStyle,
416 actionsPadding: actionsPadding ?? this.actionsPadding,
417 barrierColor: barrierColor ?? this.barrierColor,
418 insetPadding: insetPadding ?? this.insetPadding,
419 clipBehavior: clipBehavior ?? this.clipBehavior,
420 constraints: constraints ?? this.constraints,
421 );
422 }
423
424 /// Linearly interpolate between two [DialogThemeData].
425 ///
426 /// {@macro dart.ui.shadow.lerp}
427 static DialogThemeData lerp(DialogThemeData? a, DialogThemeData? b, double t) {
428 if (identical(a, b) && a != null) {
429 return a;
430 }
431 return DialogThemeData(
432 backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
433 elevation: lerpDouble(a?.elevation, b?.elevation, t),
434 shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
435 surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t),
436 shape: ShapeBorder.lerp(a?.shape, b?.shape, t),
437 alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t),
438 iconColor: Color.lerp(a?.iconColor, b?.iconColor, t),
439 titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t),
440 contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
441 actionsPadding: EdgeInsetsGeometry.lerp(a?.actionsPadding, b?.actionsPadding, t),
442 barrierColor: Color.lerp(a?.barrierColor, b?.barrierColor, t),
443 insetPadding: EdgeInsets.lerp(a?.insetPadding, b?.insetPadding, t),
444 clipBehavior: t < 0.5 ? a?.clipBehavior : b?.clipBehavior,
445 constraints: BoxConstraints.lerp(a?.constraints, b?.constraints, t),
446 );
447 }
448
449 @override
450 int get hashCode => Object.hashAll(<Object?>[
451 backgroundColor,
452 elevation,
453 shadowColor,
454 surfaceTintColor,
455 shape,
456 alignment,
457 iconColor,
458 titleTextStyle,
459 contentTextStyle,
460 actionsPadding,
461 barrierColor,
462 insetPadding,
463 clipBehavior,
464 constraints,
465 ]);
466
467 @override
468 bool operator ==(Object other) {
469 if (identical(this, other)) {
470 return true;
471 }
472 if (other.runtimeType != runtimeType) {
473 return false;
474 }
475 return other is DialogThemeData &&
476 other.backgroundColor == backgroundColor &&
477 other.elevation == elevation &&
478 other.shadowColor == shadowColor &&
479 other.surfaceTintColor == surfaceTintColor &&
480 other.shape == shape &&
481 other.alignment == alignment &&
482 other.iconColor == iconColor &&
483 other.titleTextStyle == titleTextStyle &&
484 other.contentTextStyle == contentTextStyle &&
485 other.actionsPadding == actionsPadding &&
486 other.barrierColor == barrierColor &&
487 other.insetPadding == insetPadding &&
488 other.clipBehavior == clipBehavior &&
489 other.constraints == constraints;
490 }
491
492 @override
493 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
494 super.debugFillProperties(properties);
495 properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
496 properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
497 properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null));
498 properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null));
499 properties.add(DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: null));
500 properties.add(
501 DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null),
502 );
503 properties.add(ColorProperty('iconColor', iconColor, defaultValue: null));
504 properties.add(
505 DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null),
506 );
507 properties.add(
508 DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null),
509 );
510 properties.add(
511 DiagnosticsProperty<EdgeInsetsGeometry>('actionsPadding', actionsPadding, defaultValue: null),
512 );
513 properties.add(ColorProperty('barrierColor', barrierColor, defaultValue: null));
514 properties.add(
515 DiagnosticsProperty<EdgeInsets>('insetPadding', insetPadding, defaultValue: null),
516 );
517 properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior, defaultValue: null));
518 properties.add(
519 DiagnosticsProperty<BoxConstraints>('constraints', constraints, defaultValue: null),
520 );
521 }
522}
523