mirror of
https://github.com/flutter/flutter
synced 2024-09-13 21:32:11 +00:00
Reland "Update MaterialBanner
to support Material 3" (#111299)
This commit is contained in:
parent
0ad0a56e86
commit
e8e979772a
|
@ -18,6 +18,7 @@ import 'dart:convert';
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:gen_defaults/app_bar_template.dart';
|
||||
import 'package:gen_defaults/banner_template.dart';
|
||||
import 'package:gen_defaults/button_template.dart';
|
||||
import 'package:gen_defaults/card_template.dart';
|
||||
import 'package:gen_defaults/checkbox_template.dart';
|
||||
|
@ -104,6 +105,7 @@ Future<void> main(List<String> args) async {
|
|||
tokens['colorsDark'] = _readTokenFile('color_dark.json');
|
||||
|
||||
AppBarTemplate('AppBar', '$materialLib/app_bar.dart', tokens).updateFile();
|
||||
BannerTemplate('Banner', '$materialLib/banner.dart', tokens).updateFile();
|
||||
ButtonTemplate('md.comp.elevated-button', 'ElevatedButton', '$materialLib/elevated_button.dart', tokens).updateFile();
|
||||
ButtonTemplate('md.comp.filled-button', 'FilledButton', '$materialLib/filled_button.dart', tokens).updateFile();
|
||||
ButtonTemplate('md.comp.filled-tonal-button', 'FilledTonalButton', '$materialLib/filled_button.dart', tokens).updateFile();
|
||||
|
|
31
dev/tools/gen_defaults/lib/banner_template.dart
Normal file
31
dev/tools/gen_defaults/lib/banner_template.dart
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'template.dart';
|
||||
|
||||
class BannerTemplate extends TokenTemplate {
|
||||
const BannerTemplate(super.blockName, super.fileName, super.tokens);
|
||||
|
||||
@override
|
||||
String generate() => '''
|
||||
class _${blockName}DefaultsM3 extends MaterialBannerThemeData {
|
||||
const _${blockName}DefaultsM3(this.context)
|
||||
: super(elevation: ${elevation("md.comp.banner.container")});
|
||||
|
||||
final BuildContext context;
|
||||
|
||||
@override
|
||||
Color? get backgroundColor => ${componentColor("md.comp.banner.container")};
|
||||
|
||||
@override
|
||||
Color? get surfaceTintColor => ${color("md.comp.banner.container.surface-tint-layer.color")};
|
||||
|
||||
@override
|
||||
Color? get dividerColor => ${color("md.comp.banner.divider.color")};
|
||||
|
||||
@override
|
||||
TextStyle? get contentTextStyle => ${textStyle("md.comp.banner.supporting-text")};
|
||||
}
|
||||
''';
|
||||
}
|
|
@ -102,12 +102,15 @@ class MaterialBanner extends StatefulWidget {
|
|||
this.elevation,
|
||||
this.leading,
|
||||
this.backgroundColor,
|
||||
this.surfaceTintColor,
|
||||
this.shadowColor,
|
||||
this.dividerColor,
|
||||
this.padding,
|
||||
this.leadingPadding,
|
||||
this.forceActionsBelow = false,
|
||||
this.overflowAlignment = OverflowBarAlignment.end,
|
||||
this.animation,
|
||||
this.onVisible
|
||||
this.onVisible,
|
||||
}) : assert(elevation == null || elevation >= 0.0),
|
||||
assert(content != null),
|
||||
assert(actions != null),
|
||||
|
@ -153,6 +156,29 @@ class MaterialBanner extends StatefulWidget {
|
|||
/// also `null`, [ColorScheme.surface] of [ThemeData.colorScheme] is used.
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// The color used as an overlay on [backgroundColor] to indicate elevation.
|
||||
///
|
||||
/// If null, [MaterialBannerThemeData.surfaceTintColor] is used. If that
|
||||
/// is also null, the default value is [ColorScheme.surfaceTint].
|
||||
///
|
||||
/// See [Material.surfaceTintColor] for more details on how this
|
||||
/// overlay is applied.
|
||||
final Color? surfaceTintColor;
|
||||
|
||||
/// The color of the shadow below the [MaterialBanner].
|
||||
///
|
||||
/// If this property is null, then [MaterialBannerThemeData.shadowColor] of
|
||||
/// [ThemeData.bannerTheme] is used. If that is also null, the default value
|
||||
/// is null.
|
||||
final Color? shadowColor;
|
||||
|
||||
/// The color of the divider.
|
||||
///
|
||||
/// If this property is null, then [MaterialBannerThemeData.dividerColor] of
|
||||
/// [ThemeData.bannerTheme] is used. If that is also null, the default value
|
||||
/// is [ColorScheme.surfaceVariant].
|
||||
final Color? dividerColor;
|
||||
|
||||
/// The amount of space by which to inset the [content].
|
||||
///
|
||||
/// If the [actions] are below the [content], this defaults to
|
||||
|
@ -273,6 +299,7 @@ class _MaterialBannerState extends State<MaterialBanner> {
|
|||
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final MaterialBannerThemeData bannerTheme = MaterialBannerTheme.of(context);
|
||||
final MaterialBannerThemeData defaults = theme.useMaterial3 ? _BannerDefaultsM3(context) : _BannerDefaultsM2(context);
|
||||
|
||||
final bool isSingleRow = widget.actions.length == 1 && !widget.forceActionsBelow;
|
||||
final EdgeInsetsGeometry padding = widget.padding ?? bannerTheme.padding ?? (isSingleRow
|
||||
|
@ -296,16 +323,26 @@ class _MaterialBannerState extends State<MaterialBanner> {
|
|||
final double elevation = widget.elevation ?? bannerTheme.elevation ?? 0.0;
|
||||
final Color backgroundColor = widget.backgroundColor
|
||||
?? bannerTheme.backgroundColor
|
||||
?? theme.colorScheme.surface;
|
||||
?? defaults.backgroundColor!;
|
||||
final Color? surfaceTintColor = widget.surfaceTintColor
|
||||
?? bannerTheme.surfaceTintColor
|
||||
?? defaults.surfaceTintColor;
|
||||
final Color? shadowColor = widget.shadowColor
|
||||
?? bannerTheme.shadowColor;
|
||||
final Color? dividerColor = widget.dividerColor
|
||||
?? bannerTheme.dividerColor
|
||||
?? defaults.dividerColor;
|
||||
final TextStyle? textStyle = widget.contentTextStyle
|
||||
?? bannerTheme.contentTextStyle
|
||||
?? theme.textTheme.bodyMedium;
|
||||
?? defaults.contentTextStyle;
|
||||
|
||||
Widget materialBanner = Container(
|
||||
margin: EdgeInsets.only(bottom: elevation > 0 ? 10.0 : 0.0),
|
||||
child: Material(
|
||||
elevation: elevation,
|
||||
color: backgroundColor,
|
||||
surfaceTintColor: surfaceTintColor,
|
||||
shadowColor: shadowColor,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
|
@ -331,9 +368,8 @@ class _MaterialBannerState extends State<MaterialBanner> {
|
|||
),
|
||||
if (!isSingleRow)
|
||||
buttonBar,
|
||||
|
||||
if (elevation == 0)
|
||||
const Divider(height: 0),
|
||||
Divider(height: 0, color: dividerColor),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -394,3 +430,48 @@ class _MaterialBannerState extends State<MaterialBanner> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _BannerDefaultsM2 extends MaterialBannerThemeData {
|
||||
_BannerDefaultsM2(this.context)
|
||||
: _theme = Theme.of(context),
|
||||
super(elevation: 0.0);
|
||||
|
||||
final BuildContext context;
|
||||
final ThemeData _theme;
|
||||
|
||||
@override
|
||||
Color? get backgroundColor => _theme.colorScheme.surface;
|
||||
|
||||
@override
|
||||
TextStyle? get contentTextStyle => _theme.textTheme.bodyMedium;
|
||||
}
|
||||
|
||||
// BEGIN GENERATED TOKEN PROPERTIES - Banner
|
||||
|
||||
// Do not edit by hand. The code between the "BEGIN GENERATED" and
|
||||
// "END GENERATED" comments are generated from data in the Material
|
||||
// Design token database by the script:
|
||||
// dev/tools/gen_defaults/bin/gen_defaults.dart.
|
||||
|
||||
// Token database version: v0_101
|
||||
|
||||
class _BannerDefaultsM3 extends MaterialBannerThemeData {
|
||||
const _BannerDefaultsM3(this.context)
|
||||
: super(elevation: 1.0);
|
||||
|
||||
final BuildContext context;
|
||||
|
||||
@override
|
||||
Color? get backgroundColor => Theme.of(context).colorScheme.surface;
|
||||
|
||||
@override
|
||||
Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint;
|
||||
|
||||
@override
|
||||
Color? get dividerColor => Theme.of(context).colorScheme.surfaceVariant;
|
||||
|
||||
@override
|
||||
TextStyle? get contentTextStyle => Theme.of(context).textTheme.bodyMedium;
|
||||
}
|
||||
|
||||
// END GENERATED TOKEN PROPERTIES - Banner
|
||||
|
|
|
@ -35,6 +35,9 @@ class MaterialBannerThemeData with Diagnosticable {
|
|||
/// [ThemeData.bannerTheme].
|
||||
const MaterialBannerThemeData({
|
||||
this.backgroundColor,
|
||||
this.surfaceTintColor,
|
||||
this.shadowColor,
|
||||
this.dividerColor,
|
||||
this.contentTextStyle,
|
||||
this.elevation,
|
||||
this.padding,
|
||||
|
@ -44,6 +47,15 @@ class MaterialBannerThemeData with Diagnosticable {
|
|||
/// The background color of a [MaterialBanner].
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// Overrides the default value of [MaterialBanner.surfaceTintColor].
|
||||
final Color? surfaceTintColor;
|
||||
|
||||
/// Overrides the default value of [MaterialBanner.shadowColor].
|
||||
final Color? shadowColor;
|
||||
|
||||
/// Overrides the default value of [MaterialBanner.dividerColor].
|
||||
final Color? dividerColor;
|
||||
|
||||
/// Used to configure the [DefaultTextStyle] for the [MaterialBanner.content]
|
||||
/// widget.
|
||||
final TextStyle? contentTextStyle;
|
||||
|
@ -63,6 +75,9 @@ class MaterialBannerThemeData with Diagnosticable {
|
|||
/// new values.
|
||||
MaterialBannerThemeData copyWith({
|
||||
Color? backgroundColor,
|
||||
Color? surfaceTintColor,
|
||||
Color? shadowColor,
|
||||
Color? dividerColor,
|
||||
TextStyle? contentTextStyle,
|
||||
double? elevation,
|
||||
EdgeInsetsGeometry? padding,
|
||||
|
@ -70,6 +85,9 @@ class MaterialBannerThemeData with Diagnosticable {
|
|||
}) {
|
||||
return MaterialBannerThemeData(
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor,
|
||||
shadowColor: shadowColor ?? this.shadowColor,
|
||||
dividerColor: dividerColor ?? this.dividerColor,
|
||||
contentTextStyle: contentTextStyle ?? this.contentTextStyle,
|
||||
elevation: elevation ?? this.elevation,
|
||||
padding: padding ?? this.padding,
|
||||
|
@ -86,6 +104,9 @@ class MaterialBannerThemeData with Diagnosticable {
|
|||
assert(t != null);
|
||||
return MaterialBannerThemeData(
|
||||
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
|
||||
surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t),
|
||||
shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t),
|
||||
dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t),
|
||||
contentTextStyle: TextStyle.lerp(a?.contentTextStyle, b?.contentTextStyle, t),
|
||||
elevation: lerpDouble(a?.elevation, b?.elevation, t),
|
||||
padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t),
|
||||
|
@ -96,6 +117,9 @@ class MaterialBannerThemeData with Diagnosticable {
|
|||
@override
|
||||
int get hashCode => Object.hash(
|
||||
backgroundColor,
|
||||
surfaceTintColor,
|
||||
shadowColor,
|
||||
dividerColor,
|
||||
contentTextStyle,
|
||||
elevation,
|
||||
padding,
|
||||
|
@ -111,19 +135,25 @@ class MaterialBannerThemeData with Diagnosticable {
|
|||
return false;
|
||||
}
|
||||
return other is MaterialBannerThemeData
|
||||
&& other.backgroundColor == backgroundColor
|
||||
&& other.contentTextStyle == contentTextStyle
|
||||
&& other.elevation == elevation
|
||||
&& other.padding == padding
|
||||
&& other.leadingPadding == leadingPadding;
|
||||
&& other.backgroundColor == backgroundColor
|
||||
&& other.surfaceTintColor == surfaceTintColor
|
||||
&& other.shadowColor == shadowColor
|
||||
&& other.dividerColor == dividerColor
|
||||
&& other.contentTextStyle == contentTextStyle
|
||||
&& other.elevation == elevation
|
||||
&& other.padding == padding
|
||||
&& other.leadingPadding == leadingPadding;
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
|
||||
properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null));
|
||||
properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null));
|
||||
properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<TextStyle>('contentTextStyle', contentTextStyle, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null));
|
||||
properties.add(DoubleProperty('elevation', elevation, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
|
||||
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('leadingPadding', leadingPadding, defaultValue: null));
|
||||
}
|
||||
|
|
|
@ -15,7 +15,13 @@ void main() {
|
|||
test('MaterialBannerThemeData null fields by default', () {
|
||||
const MaterialBannerThemeData bannerTheme = MaterialBannerThemeData();
|
||||
expect(bannerTheme.backgroundColor, null);
|
||||
expect(bannerTheme.surfaceTintColor, null);
|
||||
expect(bannerTheme.shadowColor, null);
|
||||
expect(bannerTheme.dividerColor, null);
|
||||
expect(bannerTheme.contentTextStyle, null);
|
||||
expect(bannerTheme.elevation, null);
|
||||
expect(bannerTheme.padding, null);
|
||||
expect(bannerTheme.leadingPadding, null);
|
||||
});
|
||||
|
||||
testWidgets('Default MaterialBannerThemeData debugFillProperties', (WidgetTester tester) async {
|
||||
|
@ -23,9 +29,9 @@ void main() {
|
|||
const MaterialBannerThemeData().debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description, <String>[]);
|
||||
});
|
||||
|
@ -33,27 +39,43 @@ void main() {
|
|||
testWidgets('MaterialBannerThemeData implements debugFillProperties', (WidgetTester tester) async {
|
||||
final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder();
|
||||
const MaterialBannerThemeData(
|
||||
backgroundColor: Color(0xFFFFFFFF),
|
||||
contentTextStyle: TextStyle(color: Color(0xFFFFFFFF)),
|
||||
backgroundColor: Color(0xfffffff0),
|
||||
surfaceTintColor: Color(0xfffffff1),
|
||||
shadowColor: Color(0xfffffff2),
|
||||
dividerColor: Color(0xfffffff3),
|
||||
contentTextStyle: TextStyle(color: Color(0xfffffff4)),
|
||||
elevation: 4.0,
|
||||
padding: EdgeInsets.all(20.0),
|
||||
leadingPadding: EdgeInsets.only(left: 8.0),
|
||||
).debugFillProperties(builder);
|
||||
|
||||
final List<String> description = builder.properties
|
||||
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
|
||||
.map((DiagnosticsNode node) => node.toString())
|
||||
.toList();
|
||||
|
||||
expect(description, <String>[
|
||||
'backgroundColor: Color(0xffffffff)',
|
||||
'contentTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))',
|
||||
'backgroundColor: Color(0xfffffff0)',
|
||||
'surfaceTintColor: Color(0xfffffff1)',
|
||||
'shadowColor: Color(0xfffffff2)',
|
||||
'dividerColor: Color(0xfffffff3)',
|
||||
'contentTextStyle: TextStyle(inherit: true, color: Color(0xfffffff4))',
|
||||
'elevation: 4.0',
|
||||
'padding: EdgeInsets.all(20.0)',
|
||||
'leadingPadding: EdgeInsets(8.0, 0.0, 0.0, 0.0)',
|
||||
]);
|
||||
});
|
||||
|
||||
testWidgets('Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async {
|
||||
final ThemeData theme = ThemeData();
|
||||
const String contentText = 'Content';
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(useMaterial3: true),
|
||||
home: Scaffold(
|
||||
body: MaterialBanner(
|
||||
content: const Text(contentText),
|
||||
leading: const Icon(Icons.umbrella),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('Action'),
|
||||
|
@ -65,16 +87,39 @@ void main() {
|
|||
));
|
||||
|
||||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(material.color, const Color(0xffffffff));
|
||||
// Default value for ThemeData.typography is Typography.material2014()
|
||||
expect(content.text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium));
|
||||
expect(material.surfaceTintColor, theme.colorScheme.surfaceTint);
|
||||
expect(material.shadowColor, null);
|
||||
expect(material.elevation, 0.0);
|
||||
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
// Default value for ThemeData.typography is Typography.material2021()
|
||||
expect(
|
||||
content.text.style,
|
||||
Typography.material2021().englishLike.bodyMedium!.merge(
|
||||
Typography.material2021().black.bodyMedium,
|
||||
),
|
||||
);
|
||||
|
||||
final Offset rowTopLeft = tester.getTopLeft(find.byType(Row));
|
||||
final Offset materialTopLeft = tester.getTopLeft(_materialFinder());
|
||||
final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella));
|
||||
expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding.
|
||||
expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding.
|
||||
expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding.
|
||||
expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding.
|
||||
|
||||
final Divider divider = tester.widget<Divider>(find.byType(Divider));
|
||||
expect(divider.color, theme.colorScheme.surfaceVariant);
|
||||
});
|
||||
|
||||
testWidgets('Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async {
|
||||
final ThemeData theme = ThemeData();
|
||||
const String contentText = 'Content';
|
||||
const Key tapTarget = Key('tap-target');
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(useMaterial3: true),
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (BuildContext context) {
|
||||
|
@ -83,6 +128,7 @@ void main() {
|
|||
onTap: () {
|
||||
ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner(
|
||||
content: const Text(contentText),
|
||||
leading: const Icon(Icons.umbrella),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('Action'),
|
||||
|
@ -105,10 +151,30 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
|
||||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(material.color, const Color(0xffffffff));
|
||||
// Default value for ThemeData.typography is Typography.material2014()
|
||||
expect(content.text.style, Typography.material2014().englishLike.bodyMedium!.merge(Typography.material2014().black.bodyMedium));
|
||||
expect(material.surfaceTintColor, theme.colorScheme.surfaceTint);
|
||||
expect(material.shadowColor, null);
|
||||
expect(material.elevation, 0.0);
|
||||
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
// Default value for ThemeData.typography is Typography.material2021()
|
||||
expect(
|
||||
content.text.style,
|
||||
Typography.material2021().englishLike.bodyMedium!.merge(
|
||||
Typography.material2021().black.bodyMedium,
|
||||
),
|
||||
);
|
||||
|
||||
final Offset rowTopLeft = tester.getTopLeft(find.byType(Row));
|
||||
final Offset materialTopLeft = tester.getTopLeft(_materialFinder());
|
||||
final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella));
|
||||
expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding.
|
||||
expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding.
|
||||
expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding.
|
||||
expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding.
|
||||
|
||||
final Divider divider = tester.widget<Divider>(find.byType(Divider));
|
||||
expect(divider.color, theme.colorScheme.surfaceVariant);
|
||||
});
|
||||
|
||||
testWidgets('MaterialBanner uses values from MaterialBannerThemeData', (WidgetTester tester) async {
|
||||
|
@ -131,8 +197,12 @@ void main() {
|
|||
));
|
||||
|
||||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(material.color, bannerTheme.backgroundColor);
|
||||
expect(material.surfaceTintColor, bannerTheme.surfaceTintColor);
|
||||
expect(material.shadowColor, bannerTheme.shadowColor);
|
||||
expect(material.elevation, bannerTheme.elevation);
|
||||
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(content.text.style, bannerTheme.contentTextStyle);
|
||||
|
||||
final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText));
|
||||
|
@ -142,6 +212,8 @@ void main() {
|
|||
expect(contentTopLeft.dx - materialTopLeft.dx, 41);
|
||||
expect(leadingTopLeft.dy - materialTopLeft.dy, 19);
|
||||
expect(leadingTopLeft.dx - materialTopLeft.dx, 11);
|
||||
|
||||
expect(find.byType(Divider), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('MaterialBanner uses values from MaterialBannerThemeData when presented by ScaffoldMessenger', (WidgetTester tester) async {
|
||||
|
@ -181,8 +253,12 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
|
||||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(material.color, bannerTheme.backgroundColor);
|
||||
expect(material.surfaceTintColor, bannerTheme.surfaceTintColor);
|
||||
expect(material.shadowColor, bannerTheme.shadowColor);
|
||||
expect(material.elevation, bannerTheme.elevation);
|
||||
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(content.text.style, bannerTheme.contentTextStyle);
|
||||
|
||||
final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText));
|
||||
|
@ -192,18 +268,26 @@ void main() {
|
|||
expect(contentTopLeft.dx - materialTopLeft.dx, 41);
|
||||
expect(leadingTopLeft.dy - materialTopLeft.dy, 19);
|
||||
expect(leadingTopLeft.dx - materialTopLeft.dx, 11);
|
||||
|
||||
expect(find.byType(Divider), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('MaterialBanner widget properties take priority over theme', (WidgetTester tester) async {
|
||||
const Color backgroundColor = Colors.purple;
|
||||
const Color surfaceTintColor = Colors.red;
|
||||
const Color shadowColor = Colors.orange;
|
||||
const TextStyle textStyle = TextStyle(color: Colors.green);
|
||||
final MaterialBannerThemeData bannerTheme = _bannerTheme();
|
||||
const String contentText = 'Content';
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(bannerTheme: bannerTheme),
|
||||
home: Scaffold(
|
||||
body: MaterialBanner(
|
||||
backgroundColor: backgroundColor,
|
||||
surfaceTintColor: surfaceTintColor,
|
||||
shadowColor: shadowColor,
|
||||
elevation: 6.0,
|
||||
leading: const Icon(Icons.ac_unit),
|
||||
contentTextStyle: textStyle,
|
||||
content: const Text(contentText),
|
||||
|
@ -220,8 +304,12 @@ void main() {
|
|||
));
|
||||
|
||||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(material.color, backgroundColor);
|
||||
expect(material.surfaceTintColor, surfaceTintColor);
|
||||
expect(material.shadowColor, shadowColor);
|
||||
expect(material.elevation, 6.0);
|
||||
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(content.text.style, textStyle);
|
||||
|
||||
final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText));
|
||||
|
@ -231,14 +319,18 @@ void main() {
|
|||
expect(contentTopLeft.dx - materialTopLeft.dx, 58);
|
||||
expect(leadingTopLeft.dy - materialTopLeft.dy, 24);
|
||||
expect(leadingTopLeft.dx - materialTopLeft.dx, 22);
|
||||
|
||||
expect(find.byType(Divider), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('MaterialBanner widget properties take priority over theme when presented by ScaffoldMessenger', (WidgetTester tester) async {
|
||||
const Color backgroundColor = Colors.purple;
|
||||
const double elevation = 6.0;
|
||||
const TextStyle textStyle = TextStyle(color: Colors.green);
|
||||
final MaterialBannerThemeData bannerTheme = _bannerTheme();
|
||||
const String contentText = 'Content';
|
||||
const Key tapTarget = Key('tap-target');
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
theme: ThemeData(bannerTheme: bannerTheme),
|
||||
home: Scaffold(
|
||||
|
@ -249,6 +341,7 @@ void main() {
|
|||
onTap: () {
|
||||
ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner(
|
||||
backgroundColor: backgroundColor,
|
||||
elevation: elevation,
|
||||
leading: const Icon(Icons.ac_unit),
|
||||
contentTextStyle: textStyle,
|
||||
content: const Text(contentText),
|
||||
|
@ -276,8 +369,10 @@ void main() {
|
|||
await tester.pumpAndSettle();
|
||||
|
||||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(material.color, backgroundColor);
|
||||
expect(material.elevation, elevation);
|
||||
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
expect(content.text.style, textStyle);
|
||||
|
||||
final Offset contentTopLeft = tester.getTopLeft(_textFinder(contentText));
|
||||
|
@ -287,6 +382,8 @@ void main() {
|
|||
expect(contentTopLeft.dx - materialTopLeft.dx, 58);
|
||||
expect(leadingTopLeft.dy - materialTopLeft.dy, 24);
|
||||
expect(leadingTopLeft.dx - materialTopLeft.dx, 22);
|
||||
|
||||
expect(find.byType(Divider), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('MaterialBanner uses color scheme when necessary', (WidgetTester tester) async {
|
||||
|
@ -349,12 +446,128 @@ void main() {
|
|||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
expect(material.color, colorScheme.surface);
|
||||
});
|
||||
|
||||
group('Material 2', () {
|
||||
// Tests that are only relevant for Material 2. Once ThemeData.useMaterial3
|
||||
// is turned on by default, these tests can be removed.
|
||||
|
||||
testWidgets('Passing no MaterialBannerThemeData returns defaults', (WidgetTester tester) async {
|
||||
const String contentText = 'Content';
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MaterialBanner(
|
||||
content: const Text(contentText),
|
||||
leading: const Icon(Icons.umbrella),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('Action'),
|
||||
onPressed: () { },
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
|
||||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
expect(material.color, const Color(0xffffffff));
|
||||
expect(material.surfaceTintColor, null);
|
||||
expect(material.shadowColor, null);
|
||||
expect(material.elevation, 0.0);
|
||||
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
// Default value for ThemeData.typography is Typography.material2014()
|
||||
expect(
|
||||
content.text.style,
|
||||
Typography.material2014().englishLike.bodyText2!.merge(
|
||||
Typography.material2014().black.bodyText2,
|
||||
),
|
||||
);
|
||||
|
||||
final Offset rowTopLeft = tester.getTopLeft(find.byType(Row));
|
||||
final Offset materialTopLeft = tester.getTopLeft(_materialFinder());
|
||||
final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella));
|
||||
expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding.
|
||||
expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding.
|
||||
expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding.
|
||||
expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding.
|
||||
|
||||
final Divider divider = tester.widget<Divider>(find.byType(Divider));
|
||||
expect(divider.color, null);
|
||||
});
|
||||
|
||||
testWidgets('Passing no MaterialBannerThemeData returns defaults when presented by ScaffoldMessenger', (WidgetTester tester) async {
|
||||
const String contentText = 'Content';
|
||||
const Key tapTarget = Key('tap-target');
|
||||
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(
|
||||
body: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return GestureDetector(
|
||||
key: tapTarget,
|
||||
onTap: () {
|
||||
ScaffoldMessenger.of(context).showMaterialBanner(MaterialBanner(
|
||||
content: const Text(contentText),
|
||||
leading: const Icon(Icons.umbrella),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('Action'),
|
||||
onPressed: () { },
|
||||
),
|
||||
],
|
||||
));
|
||||
},
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: const SizedBox(
|
||||
height: 100.0,
|
||||
width: 100.0,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
));
|
||||
await tester.tap(find.byKey(tapTarget));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final Material material = _getMaterialFromText(tester, contentText);
|
||||
expect(material.color, const Color(0xffffffff));
|
||||
expect(material.surfaceTintColor, null);
|
||||
expect(material.shadowColor, null);
|
||||
expect(material.elevation, 0.0);
|
||||
|
||||
final RenderParagraph content = _getTextRenderObjectFromDialog(tester, contentText);
|
||||
// Default value for ThemeData.typography is Typography.material2014()
|
||||
expect(
|
||||
content.text.style,
|
||||
Typography.material2014().englishLike.bodyText2!.merge(
|
||||
Typography.material2014().black.bodyText2,
|
||||
),
|
||||
);
|
||||
|
||||
final Offset rowTopLeft = tester.getTopLeft(find.byType(Row));
|
||||
final Offset materialTopLeft = tester.getTopLeft(_materialFinder());
|
||||
final Offset leadingTopLeft = tester.getTopLeft(find.byIcon(Icons.umbrella));
|
||||
expect(rowTopLeft.dy - materialTopLeft.dy, 2.0); // Default single line top padding.
|
||||
expect(rowTopLeft.dx - materialTopLeft.dx, 16.0); // Default single line start padding.
|
||||
expect(leadingTopLeft.dy - materialTopLeft.dy, 16); // Default leading padding.
|
||||
expect(leadingTopLeft.dx - materialTopLeft.dx, 16); // Default leading padding.
|
||||
|
||||
final Divider divider = tester.widget<Divider>(find.byType(Divider));
|
||||
expect(divider.color, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
MaterialBannerThemeData _bannerTheme() {
|
||||
return const MaterialBannerThemeData(
|
||||
backgroundColor: Colors.orange,
|
||||
surfaceTintColor: Colors.yellow,
|
||||
shadowColor: Colors.red,
|
||||
dividerColor: Colors.green,
|
||||
contentTextStyle: TextStyle(color: Colors.pink),
|
||||
elevation: 4.0,
|
||||
padding: EdgeInsets.all(5),
|
||||
leadingPadding: EdgeInsets.all(6),
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue