Made the snackbar fallback theme include a full inverse colorScheme. (#37038)
This commit is contained in:
parent
6ab2445ef5
commit
f0957abcd0
@ -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);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user