From 191d0aa4b6eb0b70181e554ccb1a225dcc146f63 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Tue, 10 Nov 2020 13:54:04 -0800 Subject: [PATCH] Revert "AppBar draws its defaults from theme.colorScheme (#69251)" (#70212) --- .../flutter/lib/src/material/app_bar.dart | 96 +++------- .../lib/src/material/app_bar_theme.dart | 65 +------ .../flutter/test/material/app_bar_test.dart | 14 +- .../test/material/app_bar_theme_test.dart | 168 +++++++----------- 4 files changed, 92 insertions(+), 251 deletions(-) diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index 46cb581f35..78ac1365b9 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -11,7 +11,6 @@ import 'package:flutter/widgets.dart'; import 'app_bar_theme.dart'; import 'back_button.dart'; -import 'color_scheme.dart'; import 'constants.dart'; import 'debug.dart'; import 'flexible_space_bar.dart'; @@ -197,7 +196,6 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { this.shadowColor, this.shape, this.backgroundColor, - this.foregroundColor, this.brightness, this.iconTheme, this.actionsIconTheme, @@ -359,68 +357,20 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { /// zero. final ShapeBorder? shape; - /// The fill color to use for the app bar's [Material]. + /// The color to use for the app bar's material. Typically this should be set + /// along with [brightness], [iconTheme], [textTheme]. /// - /// If null, then the [AppBarTheme.color] is used. If that value is also - /// null, then [AppBar] uses the overall theme's [ColorScheme.primary] if the - /// overall theme's brightness is [Brightness.light], and [ColorScheme.surface] - /// if the overall theme's [brightness] is [Brightness.dark]. - /// - /// See also: - /// - /// * [foregroundColor], which specifies the color for icons and text within - /// the app bar. - /// * [Theme.of], which returns the current overall Material theme as - /// a [ThemeData]. - /// * [ThemeData.colorScheme], the thirteen colors that most Material widget - /// default colors are based on. - /// * [ColorScheme.brightness], which indicates if the overall [Theme] - /// is light or dark. + /// If this property is null, then [AppBarTheme.color] of + /// [ThemeData.appBarTheme] is used. If that is also null, then + /// [ThemeData.primaryColor] is used. final Color? backgroundColor; - /// The default color for [Text] and [Icon]s within the app bar. + /// The brightness of the app bar's material. Typically this is set along + /// with [backgroundColor], [iconTheme], [textTheme]. /// - /// If null, then [AppBarTheme.foregroundColor] is used. If that - /// value is also null, then [AppBar] uses the overall theme's - /// [ColorScheme.onPrimary] if the overall theme's brightness is - /// [Brightness.light], and [ColorScheme.onSurface] if the overall - /// theme's [brightness] is [Brightness.dark]. - /// - /// This color is used to configure [DefaultTextStyle] that contains - /// the app bar's children, and the default [IconTheme] widgets that - /// are created if [iconTheme] and [actionsIconTheme] are null. - /// - /// See also: - /// - /// * [backgroundColor], which specifies the app bar's background color. - /// * [Theme.of], which returns the current overall Material theme as - /// a [ThemeData]. - /// * [ThemeData.colorScheme], the thirteen colors that most Material widget - /// default colors are based on. - /// * [ColorScheme.brightness], which indicates if the overall [Theme] - /// is light or dark. - final Color? foregroundColor; - - /// Determines the brightness of the [SystemUiOverlayStyle]: for - /// [Brightness.dark], [SystemUiOverlayStyle.light] is used and fo - /// [Brightness.light], [SystemUiOverlayStyle.dark] is used. - /// - /// If this value is null then [AppBarTheme.brightness] is used - /// and if that's null then overall theme's brightness is used. - /// - /// The AppBar is built within a `AnnotatedRegion` - /// which causes [SystemChrome.setSystemUIOverlayStyle] to be called - /// automatically. Apps should not enclose the AppBar with - /// their own [AnnotatedRegion]. - /// - /// See also: - /// - /// * [Theme.of], which returns the current overall Material theme as - /// a [ThemeData]. - /// * [ThemeData.colorScheme], the thirteen colors that most Material widget - /// default colors are based on. - /// * [ColorScheme.brightness], which indicates if the overall [Theme] - /// is light or dark. + /// If this property is null, then [AppBarTheme.brightness] of + /// [ThemeData.appBarTheme] is used. If that is also null, then + /// [ThemeData.primaryColorBrightness] is used. final Brightness? brightness; /// The color, opacity, and size to use for app bar icons. Typically this @@ -549,7 +499,6 @@ class _AppBarState extends State { assert(!widget.primary || debugCheckHasMediaQuery(context)); assert(debugCheckHasMaterialLocalizations(context)); final ThemeData theme = Theme.of(context); - final ColorScheme colorScheme = theme.colorScheme; final AppBarTheme appBarTheme = AppBarTheme.of(context); final ScaffoldState? scaffold = Scaffold.maybeOf(context); final ModalRoute? parentRoute = ModalRoute.of(context); @@ -561,25 +510,18 @@ class _AppBarState extends State { final double toolbarHeight = widget.toolbarHeight ?? kToolbarHeight; - final Color backgroundColor = widget.backgroundColor - ?? appBarTheme.color - ?? (colorScheme.brightness == Brightness.dark ? colorScheme.surface : colorScheme.primary); - final Color foregroundColor = widget.foregroundColor - ?? appBarTheme.foregroundColor - ?? (colorScheme.brightness == Brightness.dark ? colorScheme.onSurface : colorScheme.onPrimary); - IconThemeData overallIconTheme = widget.iconTheme ?? appBarTheme.iconTheme - ?? theme.iconTheme.copyWith(color: foregroundColor); + ?? theme.primaryIconTheme; IconThemeData actionsIconTheme = widget.actionsIconTheme ?? appBarTheme.actionsIconTheme ?? overallIconTheme; TextStyle? centerStyle = widget.textTheme?.headline6 ?? appBarTheme.textTheme?.headline6 - ?? theme.primaryTextTheme.headline6?.copyWith(color: foregroundColor); + ?? theme.primaryTextTheme.headline6; TextStyle? sideStyle = widget.textTheme?.bodyText2 ?? appBarTheme.textTheme?.bodyText2 - ?? theme.primaryTextTheme.bodyText2?.copyWith(color: foregroundColor); + ?? theme.primaryTextTheme.bodyText2; if (widget.toolbarOpacity != 1.0) { final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity); @@ -588,10 +530,10 @@ class _AppBarState extends State { if (sideStyle?.color != null) sideStyle = sideStyle!.copyWith(color: sideStyle.color!.withOpacity(opacity)); overallIconTheme = overallIconTheme.copyWith( - opacity: opacity * (overallIconTheme.opacity ?? 1.0), + opacity: opacity * (overallIconTheme.opacity ?? 1.0) ); actionsIconTheme = actionsIconTheme.copyWith( - opacity: opacity * (actionsIconTheme.opacity ?? 1.0), + opacity: opacity * (actionsIconTheme.opacity ?? 1.0) ); } @@ -765,19 +707,21 @@ class _AppBarState extends State { ], ); } - final Brightness brightness = widget.brightness ?? appBarTheme.brightness - ?? colorScheme.brightness; + ?? theme.primaryColorBrightness; final SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark; + return Semantics( container: true, child: AnnotatedRegion( value: overlayStyle, child: Material( - color: backgroundColor, + color: widget.backgroundColor + ?? appBarTheme.color + ?? theme.primaryColor, elevation: widget.elevation ?? appBarTheme.elevation ?? _defaultElevation, diff --git a/packages/flutter/lib/src/material/app_bar_theme.dart b/packages/flutter/lib/src/material/app_bar_theme.dart index 3ce1708fa5..c6d0a5c697 100644 --- a/packages/flutter/lib/src/material/app_bar_theme.dart +++ b/packages/flutter/lib/src/material/app_bar_theme.dart @@ -33,7 +33,6 @@ class AppBarTheme with Diagnosticable { const AppBarTheme({ this.brightness, this.color, - this.foregroundColor, this.elevation, this.shadowColor, this.iconTheme, @@ -43,66 +42,16 @@ class AppBarTheme with Diagnosticable { this.titleSpacing, }); - /// AppBar uses this value to determine the default (background) [color] and - /// [foregroundColor] as well as the app bar's [SystemUiOverlayStyle]. + /// Default value for [AppBar.brightness]. /// - /// For [Brightness.dark], [SystemUiOverlayStyle.light] is used and for - /// [Brightness.light], [SystemUiOverlayStyle.dark] is used. - /// - /// See also: - /// - /// * [AppBar.brightness], which overrides the this value and the overall - /// theme's [ColorScheme.brightness]. - /// * [Theme.of], which returns the current overall Material theme as - /// a [ThemeData]. - /// * [ThemeData.colorScheme], the thirteen colors that most Material widget - /// default colors are based on. - /// * [ColorScheme.brightness], which indicates if the overall [Theme] - /// is light or dark. + /// If null, [AppBar] uses [ThemeData.primaryColorBrightness]. final Brightness? brightness; - /// The app bar's background color. + /// Default value for [AppBar.backgroundColor]. /// - /// If null, [AppBar] uses the overall theme's [ColorScheme.primary] if the - /// overall theme's brightness is [Brightness.light], and [ColorScheme.surface] - /// if the overall theme's [brightness] is [Brightness.dark]. - /// - /// See also: - /// - /// * [AppBar.backgroundColor], which specifies the AppBar's background color - /// and overrides the background color defined by this theme. - /// * [foregroundColor], which specifies the color for icons and text within - /// the app bar. - /// * [Theme.of], which returns the current overall Material theme as - /// a [ThemeData]. - /// * [ThemeData.colorScheme], the thirteen colors that most Material widget - /// default colors are based on. - /// * [ColorScheme.brightness], which indicates if the overall [Theme] - /// is light or dark. + /// If null, [AppBar] uses [ThemeData.primaryColor]. final Color? color; - /// The default color for [Text] and [Icon]s within the app bar. - /// - /// If null, [AppBar] uses the overall theme's [ColorScheme.onPrimary] if the - /// overall theme's brightness is [Brightness.light], and [ColorScheme.onSurface] - /// if the overall theme's [brightness] is [Brightness.dark]. - /// - /// This color is used to configure [DefaultTextStyle] and [IconTheme] - /// widgets. - /// - /// See also: - /// - /// * [AppBar.foregroundColor], which specifies the app bar's text and icon - /// colors and overrides the foreground color defined by this theme. - /// * [color], which specifies the app bar's background color. - /// * [Theme.of], which returns the current overall Material theme as - /// a [ThemeData]. - /// * [ThemeData.colorScheme], the thirteen colors that most Material widget - /// default colors are based on. - /// * [ColorScheme.brightness], which indicates if the overall [Theme] - /// is light or dark. - final Color? foregroundColor; - /// Default value for [AppBar.elevation]. /// /// If null, [AppBar] uses a default value of 4.0. @@ -144,7 +93,6 @@ class AppBarTheme with Diagnosticable { IconThemeData? actionsIconTheme, Brightness? brightness, Color? color, - Color? foregroundColor, double? elevation, Color? shadowColor, IconThemeData? iconTheme, @@ -155,7 +103,6 @@ class AppBarTheme with Diagnosticable { return AppBarTheme( brightness: brightness ?? this.brightness, color: color ?? this.color, - foregroundColor: foregroundColor ?? this.foregroundColor, elevation: elevation ?? this.elevation, shadowColor: shadowColor ?? this.shadowColor, iconTheme: iconTheme ?? this.iconTheme, @@ -181,7 +128,6 @@ class AppBarTheme with Diagnosticable { return AppBarTheme( brightness: t < 0.5 ? a?.brightness : b?.brightness, color: Color.lerp(a?.color, b?.color, t), - foregroundColor: Color.lerp(a?.foregroundColor, b?.foregroundColor, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), iconTheme: IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t), @@ -197,7 +143,6 @@ class AppBarTheme with Diagnosticable { return hashValues( brightness, color, - foregroundColor, elevation, shadowColor, iconTheme, @@ -217,7 +162,6 @@ class AppBarTheme with Diagnosticable { return other is AppBarTheme && other.brightness == brightness && other.color == color - && other.foregroundColor == foregroundColor && other.elevation == elevation && other.shadowColor == shadowColor && other.iconTheme == iconTheme @@ -232,7 +176,6 @@ class AppBarTheme with Diagnosticable { super.debugFillProperties(properties); properties.add(DiagnosticsProperty('brightness', brightness, defaultValue: null)); properties.add(ColorProperty('color', color, defaultValue: null)); - properties.add(ColorProperty('foregroundColor', foregroundColor, defaultValue: null)); properties.add(DiagnosticsProperty('elevation', elevation, defaultValue: null)); properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); properties.add(DiagnosticsProperty('iconTheme', iconTheme, defaultValue: null)); diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 49a0d4cacc..5af0cf6ce1 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -1769,7 +1769,6 @@ void main() { )); expect(darkTheme.primaryColorBrightness, Brightness.dark); - expect(darkTheme.colorScheme.brightness, Brightness.dark); expect(SystemChrome.latestStyle, const SystemUiOverlayStyle( statusBarBrightness: Brightness.dark, statusBarIconBrightness: Brightness.light, @@ -1778,17 +1777,14 @@ void main() { testWidgets('AppBar draws a dark system bar for a light background', (WidgetTester tester) async { final ThemeData lightTheme = ThemeData(primaryColor: Colors.white); - await tester.pumpWidget( - MaterialApp( - theme: lightTheme, - home: Scaffold( - appBar: AppBar(title: const Text('test')), - ), + await tester.pumpWidget(MaterialApp( + theme: lightTheme, + home: Scaffold( + appBar: AppBar(title: const Text('test')), ), - ); + )); expect(lightTheme.primaryColorBrightness, Brightness.light); - expect(lightTheme.colorScheme.brightness, Brightness.light); expect(SystemChrome.latestStyle, const SystemUiOverlayStyle( statusBarBrightness: Brightness.light, statusBarIconBrightness: Brightness.dark, diff --git a/packages/flutter/test/material/app_bar_theme_test.dart b/packages/flutter/test/material/app_bar_theme_test.dart index e37ea3c483..3a83eba8b2 100644 --- a/packages/flutter/test/material/app_bar_theme_test.dart +++ b/packages/flutter/test/material/app_bar_theme_test.dart @@ -29,7 +29,7 @@ void main() { final RichText actionIconText = _getAppBarIconRichText(tester); final DefaultTextStyle text = _getAppBarText(tester); - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.dark.statusBarBrightness); + expect(SystemChrome.latestStyle!.statusBarBrightness, Brightness.dark); expect(widget.color, Colors.blue); expect(widget.elevation, 4.0); expect(widget.shadowColor, Colors.black); @@ -77,25 +77,23 @@ void main() { const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue); const TextTheme textTheme = TextTheme(headline6: TextStyle(color: Colors.orange), bodyText2: TextStyle(color: Colors.pink)); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()), - home: Scaffold( - appBar: AppBar( - backgroundColor: color, - brightness: brightness, - elevation: elevation, - shadowColor: shadowColor, - iconTheme: iconThemeData, - actionsIconTheme: actionsIconThemeData, - textTheme: textTheme, - actions: [ - IconButton(icon: const Icon(Icons.share), onPressed: () { }), - ], - ), - ), - ), - ); + final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme()); + + await tester.pumpWidget(MaterialApp( + theme: themeData, + home: Scaffold(appBar: AppBar( + backgroundColor: color, + brightness: brightness, + elevation: elevation, + shadowColor: shadowColor, + iconTheme: iconThemeData, + actionsIconTheme: actionsIconThemeData, + textTheme: textTheme, + actions: [ + IconButton(icon: const Icon(Icons.share), onPressed: () { }), + ], + )), + )); final Material widget = _getAppBarMaterial(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester); @@ -118,8 +116,10 @@ void main() { const IconThemeData iconThemeData = IconThemeData(color: Colors.green); const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue); + final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme()); + await tester.pumpWidget(MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()), + theme: themeData, home: Scaffold(appBar: AppBar( iconTheme: iconThemeData, actionsIconTheme: actionsIconThemeData, @@ -135,20 +135,16 @@ void main() { testWidgets('AppBarTheme properties take priority over ThemeData properties', (WidgetTester tester) async { final AppBarTheme appBarTheme = _appBarTheme(); + final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme()); - await tester.pumpWidget( - MaterialApp( - theme: ThemeData.from(colorScheme: const ColorScheme.light()) - .copyWith(appBarTheme: _appBarTheme()), - home: Scaffold( - appBar: AppBar( - actions: [ - IconButton(icon: const Icon(Icons.share), onPressed: () { }), - ], - ), - ), - ), - ); + await tester.pumpWidget(MaterialApp( + theme: themeData, + home: Scaffold(appBar: AppBar( + actions: [ + IconButton(icon: const Icon(Icons.share), onPressed: () { }), + ], + )), + )); final Material widget = _getAppBarMaterial(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester); @@ -166,80 +162,33 @@ void main() { expect(text.style, appBarTheme.textTheme!.bodyText2); }); - testWidgets('ThemeData colorScheme is used when no AppBarTheme is set', (WidgetTester tester) async { - late ThemeData theme; - Widget buildFrame(ThemeData appTheme) { - return MaterialApp( - theme: appTheme, - home: Builder( - builder: (BuildContext context) { - // This ThemeData has been localized with ThemeData.localize. The - // appTheme parameter has not, so its textTheme is incomplete. - theme = Theme.of(context); - return Scaffold( - appBar: AppBar( - actions: [ - IconButton(icon: const Icon(Icons.share), onPressed: () { }), - ], - ), - ); - }, - ), - ); - } + testWidgets('ThemeData properties are used when no AppBarTheme is set', (WidgetTester tester) async { + final ThemeData themeData = _themeData(); - // AppBar defaults for light themes: - // - elevation: 4 - // - shadow color: black - // - background color: ColorScheme.primary - // - foreground color: ColorScheme.onPrimary - // - actions text: style bodyText2, foreground color - // - status bar brightness: dark (based on color scheme brightness) - { - await tester.pumpWidget(buildFrame(ThemeData.from(colorScheme: const ColorScheme.light()))); + await tester.pumpWidget(MaterialApp( + theme: themeData, + home: Scaffold(appBar: AppBar( + actions: [ + IconButton(icon: const Icon(Icons.share), onPressed: () { }), + ], + )), + )); - final Material widget = _getAppBarMaterial(tester); - final IconTheme iconTheme = _getAppBarIconTheme(tester); - final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); - final RichText actionIconText = _getAppBarIconRichText(tester); - final DefaultTextStyle text = _getAppBarText(tester); + final Material widget = _getAppBarMaterial(tester); + final IconTheme iconTheme = _getAppBarIconTheme(tester); + final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); + final RichText actionIconText = _getAppBarIconRichText(tester); + final DefaultTextStyle text = _getAppBarText(tester); - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.dark.statusBarBrightness); - expect(widget.color, theme.colorScheme.primary); - expect(widget.elevation, 4.0); - expect(widget.shadowColor, Colors.black); - expect(iconTheme.data.color, theme.colorScheme.onPrimary); - expect(actionsIconTheme.data.color, theme.colorScheme.onPrimary); - expect(actionIconText.text.style!.color, theme.colorScheme.onPrimary); - expect(text.style.compareTo(theme.textTheme.bodyText2!.copyWith(color: theme.colorScheme.onPrimary)), RenderComparison.identical); - } - - // AppBar defaults for dark themes: - // - elevation: 4 - // - shadow color: black - // - background color: ColorScheme.surface - // - foreground color: ColorScheme.onSurface - // - actions text: style bodyText2, foreground color - // - status bar brightness: dark (based on background color) - { - await tester.pumpWidget(buildFrame(ThemeData.from(colorScheme: const ColorScheme.dark()))); - await tester.pumpAndSettle(); // Theme change animation - - final Material widget = _getAppBarMaterial(tester); - final IconTheme iconTheme = _getAppBarIconTheme(tester); - final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester); - final RichText actionIconText = _getAppBarIconRichText(tester); - final DefaultTextStyle text = _getAppBarText(tester); - - expect(SystemChrome.latestStyle!.statusBarBrightness, SystemUiOverlayStyle.light.statusBarBrightness); - expect(widget.color, theme.colorScheme.surface); - expect(widget.elevation, 4.0); - expect(widget.shadowColor, Colors.black); - expect(iconTheme.data.color, theme.colorScheme.onSurface); - expect(actionsIconTheme.data.color, theme.colorScheme.onSurface); - expect(actionIconText.text.style!.color, theme.colorScheme.onSurface); - expect(text.style.compareTo(theme.textTheme.bodyText2!.copyWith(color: theme.colorScheme.onSurface)), RenderComparison.identical); - } + expect(SystemChrome.latestStyle!.statusBarBrightness, themeData.brightness); + expect(widget.color, themeData.primaryColor); + expect(widget.elevation, 4.0); + expect(widget.shadowColor, Colors.black); + expect(iconTheme.data, themeData.primaryIconTheme); + expect(actionsIconTheme.data, themeData.primaryIconTheme); + expect(actionIconText.text.style!.color, themeData.primaryIconTheme.color); + // Default value for ThemeData.typography is Typography.material2014() + expect(text.style, Typography.material2014().englishLike.bodyText2!.merge(Typography.material2014().white.bodyText2).merge(themeData.primaryTextTheme.bodyText2)); }); testWidgets('AppBar uses AppBarTheme.centerTitle when centerTitle is null', (WidgetTester tester) async { @@ -426,6 +375,15 @@ AppBarTheme _appBarTheme() { ); } +ThemeData _themeData() { + return ThemeData( + primaryColor: Colors.purple, + brightness: Brightness.dark, + primaryIconTheme: const IconThemeData(color: Colors.green), + primaryTextTheme: const TextTheme(headline6: TextStyle(color: Colors.orange), bodyText2: TextStyle(color: Colors.pink)), + ); +} + Material _getAppBarMaterial(WidgetTester tester) { return tester.widget( find.descendant(