Unverified Commit f0957abc authored by Darren Austin's avatar Darren Austin Committed by GitHub

Made the snackbar fallback theme include a full inverse colorScheme. (#37038)

parent 6ab2445e
......@@ -6,6 +6,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'button_theme.dart';
import 'color_scheme.dart';
import 'flat_button.dart';
import 'material.dart';
import 'scaffold.dart';
......@@ -14,7 +15,6 @@ import 'theme.dart';
import 'theme_data.dart';
const double _singleLineVerticalPadding = 14.0;
const Color _snackBarBackgroundColor = Color(0xFF323232);
// TODO(ianh): We should check if the given text and actions are going to fit on
// one line or not, and if they are, use the single-line layout, and if not, use
......@@ -158,6 +158,8 @@ class _SnackBarActionState extends State<SnackBarAction> {
/// displayed snack bar, if any, and allows the next to be displayed.
/// * [SnackBarAction], which is used to specify an [action] button to show
/// on the snack bar.
/// * [SnackBarThemeData], to configure the default property values for
/// [SnackBar] widgets.
/// * <https://material.io/design/components/snackbars.html>
class SnackBar extends StatelessWidget {
/// Creates a snack bar.
......@@ -184,7 +186,10 @@ class SnackBar extends StatelessWidget {
/// Typically a [Text] widget.
final Widget content;
/// The Snackbar's background color. By default the color is dark grey.
/// The Snackbar's background color. If not specified it will use
/// [ThemeData.snackBarTheme.backgroundColor]. If that is not specified
/// it will default to a dark variation of [ColorScheme.surface] for light
/// themes, or [ColorScheme.onSurface] for dark themes.
final Color backgroundColor;
/// The z-coordinate at which to place the snack bar. This controls the size
......@@ -245,15 +250,40 @@ class SnackBar extends StatelessWidget {
final MediaQueryData mediaQueryData = MediaQuery.of(context);
assert(animation != null);
final ThemeData theme = Theme.of(context);
final ColorScheme colorScheme = theme.colorScheme;
final SnackBarThemeData snackBarTheme = theme.snackBarTheme;
// TODO(rami-a): Use a light theme if the app has a dark theme, https://github.com/flutter/flutter/issues/31418
final ThemeData darkTheme = ThemeData(
brightness: Brightness.dark,
accentColor: theme.accentColor,
accentColorBrightness: theme.accentColorBrightness,
final bool isThemeDark = theme.brightness == Brightness.dark;
// SnackBar uses a theme that is the opposite brightness from
// the surrounding theme.
final Brightness brightness = isThemeDark ? Brightness.light : Brightness.dark;
final Color themeBackgroundColor = isThemeDark
? colorScheme.onSurface
: Color.alphaBlend(colorScheme.onSurface.withOpacity(0.80), colorScheme.surface);
final ThemeData inverseTheme = ThemeData(
brightness: brightness,
backgroundColor: themeBackgroundColor,
colorScheme: ColorScheme(
primary: colorScheme.onPrimary,
primaryVariant: colorScheme.onPrimary,
// For the button color, the spec says it should be primaryVariant, but for
// backward compatibility on light themes we are leaving it as secondary.
secondary: isThemeDark ? colorScheme.primaryVariant : colorScheme.secondary,
secondaryVariant: colorScheme.onSecondary,
surface: colorScheme.onSurface,
background: themeBackgroundColor,
error: colorScheme.onError,
onPrimary: colorScheme.primary,
onSecondary: colorScheme.secondary,
onSurface: colorScheme.surface,
onBackground: colorScheme.background,
onError: colorScheme.error,
brightness: brightness,
),
snackBarTheme: snackBarTheme,
);
final TextStyle contentTextStyle = snackBarTheme.contentTextStyle ?? darkTheme.textTheme.subhead;
final TextStyle contentTextStyle = snackBarTheme.contentTextStyle ?? inverseTheme.textTheme.subhead;
final SnackBarBehavior snackBarBehavior = behavior ?? snackBarTheme.behavior ?? SnackBarBehavior.fixed;
final bool isFloatingSnackBar = snackBarBehavior == SnackBarBehavior.floating;
final double snackBarPadding = isFloatingSnackBar ? 16.0 : 24.0;
......@@ -297,7 +327,7 @@ class SnackBar extends StatelessWidget {
);
final double elevation = this.elevation ?? snackBarTheme.elevation ?? 6.0;
final Color backgroundColor = this.backgroundColor ?? snackBarTheme.backgroundColor ?? _snackBarBackgroundColor;
final Color backgroundColor = this.backgroundColor ?? snackBarTheme.backgroundColor ?? inverseTheme.backgroundColor;
final ShapeBorder shape = this.shape
?? snackBarTheme.shape
?? (isFloatingSnackBar ? RoundedRectangleBorder(borderRadius: BorderRadius.circular(4.0)) : null);
......@@ -307,7 +337,7 @@ class SnackBar extends StatelessWidget {
elevation: elevation,
color: backgroundColor,
child: Theme(
data: darkTheme,
data: inverseTheme,
child: mediaQueryData.accessibleNavigation
? snackBar
: FadeTransition(
......
......@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('SnackBar control test', (WidgetTester tester) async {
......@@ -296,6 +297,87 @@ void main() {
expect(tapCount, equals(1));
});
testWidgets('Light theme SnackBar has dark background', (WidgetTester tester) async {
final ThemeData lightTheme = ThemeData.light();
await tester.pumpWidget(
MaterialApp(
theme: lightTheme,
home: Scaffold(
body: Builder(
builder: (BuildContext context) {
return GestureDetector(
onTap: () {
Scaffold.of(context).showSnackBar(
SnackBar(
content: const Text('I am a snack bar.'),
duration: const Duration(seconds: 2),
action: SnackBarAction(
label: 'ACTION',
onPressed: () { },
),
),
);
},
child: const Text('X'),
);
}
),
),
),
);
await tester.tap(find.text('X'));
await tester.pump(); // start animation
await tester.pump(const Duration(milliseconds: 750));
final RenderPhysicalModel renderModel = tester.renderObject(
find.widgetWithText(Material, 'I am a snack bar.').first
);
// There is a somewhat complicated background color calculation based
// off of the surface color. For the default light theme it
// should be this value.
expect(renderModel.color, equals(const Color(0xFF333333)));
});
testWidgets('Dark theme SnackBar has light background', (WidgetTester tester) async {
final ThemeData darkTheme = ThemeData.dark();
await tester.pumpWidget(
MaterialApp(
theme: darkTheme,
home: Scaffold(
body: Builder(
builder: (BuildContext context) {
return GestureDetector(
onTap: () {
Scaffold.of(context).showSnackBar(
SnackBar(
content: const Text('I am a snack bar.'),
duration: const Duration(seconds: 2),
action: SnackBarAction(
label: 'ACTION',
onPressed: () { },
),
),
);
},
child: const Text('X'),
);
}
),
),
),
);
await tester.tap(find.text('X'));
await tester.pump(); // start animation
await tester.pump(const Duration(milliseconds: 750));
final RenderPhysicalModel renderModel = tester.renderObject(
find.widgetWithText(Material, 'I am a snack bar.').first
);
expect(renderModel.color, equals(darkTheme.colorScheme.onSurface));
});
testWidgets('Snackbar labels can be colored', (WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
......
......@@ -92,7 +92,7 @@ void main() {
final RenderParagraph content = _getSnackBarTextRenderObject(tester, text);
expect(content.text.style, Typography().white.subhead);
expect(material.color, const Color(0xFF323232));
expect(material.color, const Color(0xFF333333));
expect(material.elevation, 6.0);
expect(material.shape, null);
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment