Unverified Commit fc6079a2 authored by rami-a's avatar rami-a Committed by GitHub

[Material] Add the ability to theme trailing app bar actions independently from leading (#28214)

* Allow app bar actions to be themed independently if needed

* Update SliverAppBar docs that were out of date

* Clarify fallback behavior in a comment

* Analyzer

* Address PR feedback

* Address PR feedback

* Put back checks on actions icon theme

* Address PR feedback

* Retrigger CI
parent c26a69e9
...@@ -135,10 +135,10 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -135,10 +135,10 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// and [automaticallyImplyLeading] must not be null. Additionally, if /// and [automaticallyImplyLeading] must not be null. Additionally, if
/// [elevation] is specified, it must be non-negative. /// [elevation] is specified, it must be non-negative.
/// ///
/// If [backgroundColor], [elevation], [brightness], [iconTheme], or /// If [backgroundColor], [elevation], [brightness], [iconTheme],
/// [textTheme] are null, their [AppBarTheme] values will be used. If the /// [actionsIconTheme], or [textTheme] are null, then their [AppBarTheme]
/// corresponding [AppBarTheme] property is null, then the default specified /// values will be used. If the corresponding [AppBarTheme] property is null,
/// in the property's documentation will be used. /// then the default specified in the property's documentation will be used.
/// ///
/// Typically used in the [Scaffold.appBar] property. /// Typically used in the [Scaffold.appBar] property.
AppBar({ AppBar({
...@@ -153,6 +153,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -153,6 +153,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
this.backgroundColor, this.backgroundColor,
this.brightness, this.brightness,
this.iconTheme, this.iconTheme,
this.actionsIconTheme,
this.textTheme, this.textTheme,
this.primary = true, this.primary = true,
this.centerTitle, this.centerTitle,
...@@ -280,7 +281,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -280,7 +281,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// ///
/// The value is non-negative. /// The value is non-negative.
/// ///
/// If this property is null then [ThemeData.appBarTheme.elevation] is used, /// If this property is null, then [ThemeData.appBarTheme.elevation] is used,
/// if that is also null, the default value is 4, the appropriate elevation /// if that is also null, the default value is 4, the appropriate elevation
/// for app bars. /// for app bars.
final double elevation; final double elevation;
...@@ -288,29 +289,38 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -288,29 +289,38 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// The color to use for the app bar's material. Typically this should be set /// The color to use for the app bar's material. Typically this should be set
/// along with [brightness], [iconTheme], [textTheme]. /// along with [brightness], [iconTheme], [textTheme].
/// ///
/// If this property is null then [ThemeData.appBarTheme.color] is used, /// If this property is null, then [ThemeData.appBarTheme.color] is used,
/// if that is also null then [ThemeData.primaryColor] is used. /// if that is also null, then [ThemeData.primaryColor] is used.
final Color backgroundColor; final Color backgroundColor;
/// The brightness of the app bar's material. Typically this is set along /// The brightness of the app bar's material. Typically this is set along
/// with [backgroundColor], [iconTheme], [textTheme]. /// with [backgroundColor], [iconTheme], [textTheme].
/// ///
/// If this property is null then [ThemeData.appBarTheme.brightness] is used, /// If this property is null, then [ThemeData.appBarTheme.brightness] is used,
/// if that is also null then [ThemeData.primaryColorBrightness] is used. /// if that is also null, then [ThemeData.primaryColorBrightness] is used.
final Brightness brightness; final Brightness brightness;
/// The color, opacity, and size to use for app bar icons. Typically this /// The color, opacity, and size to use for app bar icons. Typically this
/// is set along with [backgroundColor], [brightness], [textTheme]. /// is set along with [backgroundColor], [brightness], [textTheme].
/// ///
/// If this property is null then [ThemeData.appBarTheme.iconTheme] is used, /// If this property is null, then [ThemeData.appBarTheme.iconTheme] is used,
/// if that is also null then [ThemeData.primaryIconTheme] is used. /// if that is also null, then [ThemeData.primaryIconTheme] is used.
final IconThemeData iconTheme; final IconThemeData iconTheme;
/// The color, opacity, and size to use for the icons that appear in the app
/// bar's [actions]. This should only be used when the [actions] should be
/// themed differently than the icon that appears in the app bar's [leading]
/// widget.
///
/// If this property is null, then [ThemeData.appBarTheme.actionsIconTheme] is
/// used, if that is also null, then this falls back to [iconTheme].
final IconThemeData actionsIconTheme;
/// The typographic styles to use for text in the app bar. Typically this is /// The typographic styles to use for text in the app bar. Typically this is
/// set along with [brightness] [backgroundColor], [iconTheme]. /// set along with [brightness] [backgroundColor], [iconTheme].
/// ///
/// If this property is null then [ThemeData.appBarTheme.textTheme] is used, /// If this property is null, then [ThemeData.appBarTheme.textTheme] is used,
/// if that is also null then [ThemeData.primaryTextTheme] is used. /// if that is also null, then [ThemeData.primaryTextTheme] is used.
final TextTheme textTheme; final TextTheme textTheme;
/// Whether this app bar is being displayed at the top of the screen. /// Whether this app bar is being displayed at the top of the screen.
...@@ -400,9 +410,12 @@ class _AppBarState extends State<AppBar> { ...@@ -400,9 +410,12 @@ class _AppBarState extends State<AppBar> {
final bool canPop = parentRoute?.canPop ?? false; final bool canPop = parentRoute?.canPop ?? false;
final bool useCloseButton = parentRoute is PageRoute<dynamic> && parentRoute.fullscreenDialog; final bool useCloseButton = parentRoute is PageRoute<dynamic> && parentRoute.fullscreenDialog;
IconThemeData appBarIconTheme = widget.iconTheme IconThemeData overallIconTheme = widget.iconTheme
?? appBarTheme.iconTheme ?? appBarTheme.iconTheme
?? themeData.primaryIconTheme; ?? themeData.primaryIconTheme;
IconThemeData actionsIconTheme = widget.actionsIconTheme
?? appBarTheme.actionsIconTheme
?? overallIconTheme;
TextStyle centerStyle = widget.textTheme?.title TextStyle centerStyle = widget.textTheme?.title
?? appBarTheme.textTheme?.title ?? appBarTheme.textTheme?.title
?? themeData.primaryTextTheme.title; ?? themeData.primaryTextTheme.title;
...@@ -416,8 +429,11 @@ class _AppBarState extends State<AppBar> { ...@@ -416,8 +429,11 @@ class _AppBarState extends State<AppBar> {
centerStyle = centerStyle.copyWith(color: centerStyle.color.withOpacity(opacity)); centerStyle = centerStyle.copyWith(color: centerStyle.color.withOpacity(opacity));
if (sideStyle?.color != null) if (sideStyle?.color != null)
sideStyle = sideStyle.copyWith(color: sideStyle.color.withOpacity(opacity)); sideStyle = sideStyle.copyWith(color: sideStyle.color.withOpacity(opacity));
appBarIconTheme = appBarIconTheme.copyWith( overallIconTheme = overallIconTheme.copyWith(
opacity: opacity * (appBarIconTheme.opacity ?? 1.0) opacity: opacity * (overallIconTheme.opacity ?? 1.0)
);
actionsIconTheme = actionsIconTheme.copyWith(
opacity: opacity * (actionsIconTheme.opacity ?? 1.0)
); );
} }
...@@ -479,6 +495,14 @@ class _AppBarState extends State<AppBar> { ...@@ -479,6 +495,14 @@ class _AppBarState extends State<AppBar> {
); );
} }
// Allow the trailing actions to have their own theme if necessary.
if (actions != null) {
actions = IconTheme.merge(
data: actionsIconTheme,
child: actions,
);
}
final Widget toolbar = NavigationToolbar( final Widget toolbar = NavigationToolbar(
leading: leading, leading: leading,
middle: title, middle: title,
...@@ -493,7 +517,7 @@ class _AppBarState extends State<AppBar> { ...@@ -493,7 +517,7 @@ class _AppBarState extends State<AppBar> {
child: CustomSingleChildLayout( child: CustomSingleChildLayout(
delegate: const _ToolbarContainerLayout(), delegate: const _ToolbarContainerLayout(),
child: IconTheme.merge( child: IconTheme.merge(
data: appBarIconTheme, data: overallIconTheme,
child: DefaultTextStyle( child: DefaultTextStyle(
style: sideStyle, style: sideStyle,
child: toolbar, child: toolbar,
...@@ -634,6 +658,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -634,6 +658,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
@required this.backgroundColor, @required this.backgroundColor,
@required this.brightness, @required this.brightness,
@required this.iconTheme, @required this.iconTheme,
@required this.actionsIconTheme,
@required this.textTheme, @required this.textTheme,
@required this.primary, @required this.primary,
@required this.centerTitle, @required this.centerTitle,
...@@ -658,6 +683,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -658,6 +683,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
final Color backgroundColor; final Color backgroundColor;
final Brightness brightness; final Brightness brightness;
final IconThemeData iconTheme; final IconThemeData iconTheme;
final IconThemeData actionsIconTheme;
final TextTheme textTheme; final TextTheme textTheme;
final bool primary; final bool primary;
final bool centerTitle; final bool centerTitle;
...@@ -716,6 +742,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -716,6 +742,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
brightness: brightness, brightness: brightness,
iconTheme: iconTheme, iconTheme: iconTheme,
actionsIconTheme: actionsIconTheme,
textTheme: textTheme, textTheme: textTheme,
primary: primary, primary: primary,
centerTitle: centerTitle, centerTitle: centerTitle,
...@@ -740,6 +767,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate { ...@@ -740,6 +767,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|| backgroundColor != oldDelegate.backgroundColor || backgroundColor != oldDelegate.backgroundColor
|| brightness != oldDelegate.brightness || brightness != oldDelegate.brightness
|| iconTheme != oldDelegate.iconTheme || iconTheme != oldDelegate.iconTheme
|| actionsIconTheme != oldDelegate.actionsIconTheme
|| textTheme != oldDelegate.textTheme || textTheme != oldDelegate.textTheme
|| primary != oldDelegate.primary || primary != oldDelegate.primary
|| centerTitle != oldDelegate.centerTitle || centerTitle != oldDelegate.centerTitle
...@@ -851,6 +879,7 @@ class SliverAppBar extends StatefulWidget { ...@@ -851,6 +879,7 @@ class SliverAppBar extends StatefulWidget {
this.backgroundColor, this.backgroundColor,
this.brightness, this.brightness,
this.iconTheme, this.iconTheme,
this.actionsIconTheme,
this.textTheme, this.textTheme,
this.primary = true, this.primary = true,
this.centerTitle, this.centerTitle,
...@@ -944,7 +973,9 @@ class SliverAppBar extends StatefulWidget { ...@@ -944,7 +973,9 @@ class SliverAppBar extends StatefulWidget {
/// The z-coordinate at which to place this app bar when it is above other /// The z-coordinate at which to place this app bar when it is above other
/// content. This controls the size of the shadow below the app bar. /// content. This controls the size of the shadow below the app bar.
/// ///
/// Defaults to 4, the appropriate elevation for app bars. /// If this property is null, then [ThemeData.appBarTheme.elevation] is used,
/// if that is also null, the default value is 4, the appropriate elevation
/// for app bars.
/// ///
/// If [forceElevated] is false, the elevation is ignored when the app bar has /// If [forceElevated] is false, the elevation is ignored when the app bar has
/// no content underneath it. For example, if the app bar is [pinned] but no /// no content underneath it. For example, if the app bar is [pinned] but no
...@@ -966,25 +997,37 @@ class SliverAppBar extends StatefulWidget { ...@@ -966,25 +997,37 @@ class SliverAppBar extends StatefulWidget {
/// The color to use for the app bar's material. Typically this should be set /// The color to use for the app bar's material. Typically this should be set
/// along with [brightness], [iconTheme], [textTheme]. /// along with [brightness], [iconTheme], [textTheme].
/// ///
/// Defaults to [ThemeData.primaryColor]. /// If this property is null, then [ThemeData.appBarTheme.color] is used,
/// if that is also null, then [ThemeData.primaryColor] is used.
final Color backgroundColor; final Color backgroundColor;
/// The brightness of the app bar's material. Typically this is set along /// The brightness of the app bar's material. Typically this is set along
/// with [backgroundColor], [iconTheme], [textTheme]. /// with [backgroundColor], [iconTheme], [textTheme].
/// ///
/// Defaults to [ThemeData.primaryColorBrightness]. /// If this property is null, then [ThemeData.appBarTheme.brightness] is used,
/// if that is also null, then [ThemeData.primaryColorBrightness] is used.
final Brightness brightness; final Brightness brightness;
/// The color, opacity, and size to use for app bar icons. Typically this /// The color, opacity, and size to use for app bar icons. Typically this
/// is set along with [backgroundColor], [brightness], [textTheme]. /// is set along with [backgroundColor], [brightness], [textTheme].
/// ///
/// Defaults to [ThemeData.primaryIconTheme]. /// If this property is null, then [ThemeData.appBarTheme.iconTheme] is used,
/// if that is also null, then [ThemeData.primaryIconTheme] is used.
final IconThemeData iconTheme; final IconThemeData iconTheme;
/// The color, opacity, and size to use for trailing app bar icons. This
/// should only be used when the trailing icons should be themed differently
/// than the leading icons.
///
/// If this property is null, then [ThemeData.appBarTheme.actionsIconTheme] is
/// used, if that is also null, then this falls back to [iconTheme].
final IconThemeData actionsIconTheme;
/// The typographic styles to use for text in the app bar. Typically this is /// The typographic styles to use for text in the app bar. Typically this is
/// set along with [brightness] [backgroundColor], [iconTheme]. /// set along with [brightness] [backgroundColor], [iconTheme].
/// ///
/// Defaults to [ThemeData.primaryTextTheme]. /// If this property is null, then [ThemeData.appBarTheme.textTheme] is used,
/// if that is also null, then [ThemeData.primaryTextTheme] is used.
final TextTheme textTheme; final TextTheme textTheme;
/// Whether this app bar is being displayed at the top of the screen. /// Whether this app bar is being displayed at the top of the screen.
...@@ -1148,6 +1191,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix ...@@ -1148,6 +1191,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
backgroundColor: widget.backgroundColor, backgroundColor: widget.backgroundColor,
brightness: widget.brightness, brightness: widget.brightness,
iconTheme: widget.iconTheme, iconTheme: widget.iconTheme,
actionsIconTheme: widget.actionsIconTheme,
textTheme: widget.textTheme, textTheme: widget.textTheme,
primary: widget.primary, primary: widget.primary,
centerTitle: widget.centerTitle, centerTitle: widget.centerTitle,
......
...@@ -34,6 +34,7 @@ class AppBarTheme extends Diagnosticable { ...@@ -34,6 +34,7 @@ class AppBarTheme extends Diagnosticable {
this.color, this.color,
this.elevation, this.elevation,
this.iconTheme, this.iconTheme,
this.actionsIconTheme,
this.textTheme, this.textTheme,
}); });
...@@ -57,6 +58,11 @@ class AppBarTheme extends Diagnosticable { ...@@ -57,6 +58,11 @@ class AppBarTheme extends Diagnosticable {
/// If null, [AppBar] uses [ThemeData.primaryIconTheme]. /// If null, [AppBar] uses [ThemeData.primaryIconTheme].
final IconThemeData iconTheme; final IconThemeData iconTheme;
/// Default value for [AppBar.actionsIconTheme].
///
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
final IconThemeData actionsIconTheme;
/// Default value for [AppBar.textTheme]. /// Default value for [AppBar.textTheme].
/// ///
/// If null, [AppBar] uses [ThemeData.primaryTextTheme]. /// If null, [AppBar] uses [ThemeData.primaryTextTheme].
...@@ -65,6 +71,7 @@ class AppBarTheme extends Diagnosticable { ...@@ -65,6 +71,7 @@ class AppBarTheme extends Diagnosticable {
/// Creates a copy of this object with the given fields replaced with the /// Creates a copy of this object with the given fields replaced with the
/// new values. /// new values.
AppBarTheme copyWith({ AppBarTheme copyWith({
IconThemeData actionsIconTheme,
Brightness brightness, Brightness brightness,
Color color, Color color,
double elevation, double elevation,
...@@ -76,6 +83,7 @@ class AppBarTheme extends Diagnosticable { ...@@ -76,6 +83,7 @@ class AppBarTheme extends Diagnosticable {
color: color ?? this.color, color: color ?? this.color,
elevation: elevation ?? this.elevation, elevation: elevation ?? this.elevation,
iconTheme: iconTheme ?? this.iconTheme, iconTheme: iconTheme ?? this.iconTheme,
actionsIconTheme: actionsIconTheme ?? this.actionsIconTheme,
textTheme: textTheme ?? this.textTheme, textTheme: textTheme ?? this.textTheme,
); );
} }
...@@ -97,6 +105,7 @@ class AppBarTheme extends Diagnosticable { ...@@ -97,6 +105,7 @@ class AppBarTheme extends Diagnosticable {
color: Color.lerp(a?.color, b?.color, t), color: Color.lerp(a?.color, b?.color, t),
elevation: lerpDouble(a?.elevation, b?.elevation, t), elevation: lerpDouble(a?.elevation, b?.elevation, t),
iconTheme: IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t), iconTheme: IconThemeData.lerp(a?.iconTheme, b?.iconTheme, t),
actionsIconTheme: IconThemeData.lerp(a?.actionsIconTheme, b?.actionsIconTheme, t),
textTheme: TextTheme.lerp(a?.textTheme, b?.textTheme, t), textTheme: TextTheme.lerp(a?.textTheme, b?.textTheme, t),
); );
} }
...@@ -108,6 +117,7 @@ class AppBarTheme extends Diagnosticable { ...@@ -108,6 +117,7 @@ class AppBarTheme extends Diagnosticable {
color, color,
elevation, elevation,
iconTheme, iconTheme,
actionsIconTheme,
textTheme, textTheme,
); );
} }
...@@ -123,6 +133,7 @@ class AppBarTheme extends Diagnosticable { ...@@ -123,6 +133,7 @@ class AppBarTheme extends Diagnosticable {
&& typedOther.color == color && typedOther.color == color
&& typedOther.elevation == elevation && typedOther.elevation == elevation
&& typedOther.iconTheme == iconTheme && typedOther.iconTheme == iconTheme
&& typedOther.actionsIconTheme == actionsIconTheme
&& typedOther.textTheme == textTheme; && typedOther.textTheme == textTheme;
} }
...@@ -133,6 +144,7 @@ class AppBarTheme extends Diagnosticable { ...@@ -133,6 +144,7 @@ class AppBarTheme extends Diagnosticable {
properties.add(DiagnosticsProperty<Color>('color', color, defaultValue: null)); properties.add(DiagnosticsProperty<Color>('color', color, defaultValue: null));
properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null)); properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null));
properties.add(DiagnosticsProperty<IconThemeData>('iconTheme', iconTheme, defaultValue: null)); properties.add(DiagnosticsProperty<IconThemeData>('iconTheme', iconTheme, defaultValue: null));
properties.add(DiagnosticsProperty<IconThemeData>('actionsIconTheme', actionsIconTheme, defaultValue: null));
properties.add(DiagnosticsProperty<TextTheme>('textTheme', textTheme, defaultValue: null)); properties.add(DiagnosticsProperty<TextTheme>('textTheme', textTheme, defaultValue: null));
} }
} }
...@@ -15,17 +15,25 @@ void main() { ...@@ -15,17 +15,25 @@ void main() {
testWidgets('Passing no AppBarTheme returns defaults', (WidgetTester tester) async { testWidgets('Passing no AppBarTheme returns defaults', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: Scaffold(appBar: AppBar()), home: Scaffold(appBar: AppBar(
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () {})
],
)),
)); ));
final Material widget = _getAppBarMaterial(tester); final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, Brightness.dark); expect(SystemChrome.latestStyle.statusBarBrightness, Brightness.dark);
expect(widget.color, Colors.blue); expect(widget.color, Colors.blue);
expect(widget.elevation, 4.0); expect(widget.elevation, 4.0);
expect(iconTheme.data, const IconThemeData(color: Colors.white)); expect(iconTheme.data, const IconThemeData(color: Colors.white));
expect(actionsIconTheme.data, const IconThemeData(color: Colors.white));
expect(actionIconText.text.style.color, Colors.white);
expect(text.style, Typography().englishLike.body1.merge(Typography().white.body1)); expect(text.style, Typography().englishLike.body1.merge(Typography().white.body1));
}); });
...@@ -34,17 +42,26 @@ void main() { ...@@ -34,17 +42,26 @@ void main() {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: ThemeData(appBarTheme: appBarTheme), theme: ThemeData(appBarTheme: appBarTheme),
home: Scaffold(appBar: AppBar(title: const Text('App Bar Title'),)), home: Scaffold(appBar: AppBar(
title: const Text('App Bar Title'),
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () {})
],
)),
)); ));
final Material widget = _getAppBarMaterial(tester); final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, appBarTheme.brightness); expect(SystemChrome.latestStyle.statusBarBrightness, appBarTheme.brightness);
expect(widget.color, appBarTheme.color); expect(widget.color, appBarTheme.color);
expect(widget.elevation, appBarTheme.elevation); expect(widget.elevation, appBarTheme.elevation);
expect(iconTheme.data, appBarTheme.iconTheme); expect(iconTheme.data, appBarTheme.iconTheme);
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
expect(actionIconText.text.style.color, appBarTheme.actionsIconTheme.color);
expect(text.style, appBarTheme.textTheme.body1); expect(text.style, appBarTheme.textTheme.body1);
}); });
...@@ -53,6 +70,7 @@ void main() { ...@@ -53,6 +70,7 @@ void main() {
const Color color = Colors.orange; const Color color = Colors.orange;
const double elevation = 3.0; const double elevation = 3.0;
const IconThemeData iconThemeData = IconThemeData(color: Colors.green); const IconThemeData iconThemeData = IconThemeData(color: Colors.green);
const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.lightBlue);
const TextTheme textTheme = TextTheme(title: TextStyle(color: Colors.orange), body1: TextStyle(color: Colors.pink)); const TextTheme textTheme = TextTheme(title: TextStyle(color: Colors.orange), body1: TextStyle(color: Colors.pink));
final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme()); final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme());
...@@ -64,38 +82,76 @@ void main() { ...@@ -64,38 +82,76 @@ void main() {
brightness: brightness, brightness: brightness,
elevation: elevation, elevation: elevation,
iconTheme: iconThemeData, iconTheme: iconThemeData,
textTheme: textTheme,) actionsIconTheme: actionsIconThemeData,
), textTheme: textTheme,
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () {})
],
)),
)); ));
final Material widget = _getAppBarMaterial(tester); final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, brightness); expect(SystemChrome.latestStyle.statusBarBrightness, brightness);
expect(widget.color, color); expect(widget.color, color);
expect(widget.elevation, elevation); expect(widget.elevation, elevation);
expect(iconTheme.data, iconThemeData); expect(iconTheme.data, iconThemeData);
expect(actionsIconTheme.data, actionsIconThemeData);
expect(actionIconText.text.style.color, actionsIconThemeData.color);
expect(text.style, textTheme.body1); expect(text.style, textTheme.body1);
}); });
testWidgets('AppBar icon color takes priority over everything', (WidgetTester tester) async {
const Color color = Colors.lime;
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,
home: Scaffold(appBar: AppBar(
iconTheme: iconThemeData,
actionsIconTheme: actionsIconThemeData,
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), color: color, onPressed: () {})
],
)),
));
final RichText actionIconText = _getAppBarIconRichText(tester);
expect(actionIconText.text.style.color, color);
});
testWidgets('AppBarTheme properties take priority over ThemeData properties', (WidgetTester tester) async { testWidgets('AppBarTheme properties take priority over ThemeData properties', (WidgetTester tester) async {
final AppBarTheme appBarTheme = _appBarTheme(); final AppBarTheme appBarTheme = _appBarTheme();
final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme()); final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme());
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: themeData, theme: themeData,
home: Scaffold(appBar: AppBar()), home: Scaffold(appBar: AppBar(
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () {})
],
)),
)); ));
final Material widget = _getAppBarMaterial(tester); final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, appBarTheme.brightness); expect(SystemChrome.latestStyle.statusBarBrightness, appBarTheme.brightness);
expect(widget.color, appBarTheme.color); expect(widget.color, appBarTheme.color);
expect(widget.elevation, appBarTheme.elevation); expect(widget.elevation, appBarTheme.elevation);
expect(iconTheme.data, appBarTheme.iconTheme); expect(iconTheme.data, appBarTheme.iconTheme);
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
expect(actionIconText.text.style.color, appBarTheme.actionsIconTheme.color);
expect(text.style, appBarTheme.textTheme.body1); expect(text.style, appBarTheme.textTheme.body1);
}); });
...@@ -104,17 +160,25 @@ void main() { ...@@ -104,17 +160,25 @@ void main() {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
theme: themeData, theme: themeData,
home: Scaffold(appBar: AppBar()), home: Scaffold(appBar: AppBar(
actions: <Widget>[
IconButton(icon: const Icon(Icons.share), onPressed: () {})
],
)),
)); ));
final Material widget = _getAppBarMaterial(tester); final Material widget = _getAppBarMaterial(tester);
final IconTheme iconTheme = _getAppBarIconTheme(tester); final IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester); final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, themeData.brightness); expect(SystemChrome.latestStyle.statusBarBrightness, themeData.brightness);
expect(widget.color, themeData.primaryColor); expect(widget.color, themeData.primaryColor);
expect(widget.elevation, 4.0); expect(widget.elevation, 4.0);
expect(iconTheme.data, themeData.primaryIconTheme); expect(iconTheme.data, themeData.primaryIconTheme);
expect(actionsIconTheme.data, themeData.primaryIconTheme);
expect(actionIconText.text.style.color, themeData.primaryIconTheme.color);
expect(text.style, Typography().englishLike.body1.merge(Typography().white.body1).merge(themeData.primaryTextTheme.body1)); expect(text.style, Typography().englishLike.body1.merge(Typography().white.body1).merge(themeData.primaryTextTheme.body1));
}); });
} }
...@@ -124,13 +188,15 @@ AppBarTheme _appBarTheme() { ...@@ -124,13 +188,15 @@ AppBarTheme _appBarTheme() {
const Color color = Colors.lightBlue; const Color color = Colors.lightBlue;
const double elevation = 6.0; const double elevation = 6.0;
const IconThemeData iconThemeData = IconThemeData(color: Colors.black); const IconThemeData iconThemeData = IconThemeData(color: Colors.black);
const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.pink);
const TextTheme textTheme = TextTheme(body1: TextStyle(color: Colors.yellow)); const TextTheme textTheme = TextTheme(body1: TextStyle(color: Colors.yellow));
return const AppBarTheme( return const AppBarTheme(
actionsIconTheme: actionsIconThemeData,
brightness: brightness, brightness: brightness,
color: color, color: color,
elevation: elevation, elevation: elevation,
iconTheme: iconThemeData, iconTheme: iconThemeData,
textTheme: textTheme textTheme: textTheme,
); );
} }
...@@ -157,10 +223,27 @@ IconTheme _getAppBarIconTheme(WidgetTester tester) { ...@@ -157,10 +223,27 @@ IconTheme _getAppBarIconTheme(WidgetTester tester) {
find.descendant( find.descendant(
of: find.byType(AppBar), of: find.byType(AppBar),
matching: find.byType(IconTheme), matching: find.byType(IconTheme),
), ).first,
);
}
IconTheme _getAppBarActionsIconTheme(WidgetTester tester) {
return tester.widget<IconTheme>(
find.descendant(
of: find.byType(NavigationToolbar),
matching: find.byType(IconTheme),
).first,
); );
} }
RichText _getAppBarIconRichText(WidgetTester tester) {
return tester.widget<RichText>(
find.descendant(
of: find.byType(Icon),
matching: find.byType(RichText),
).first,
);
}
DefaultTextStyle _getAppBarText(WidgetTester tester) { DefaultTextStyle _getAppBarText(WidgetTester tester) {
return tester.widget<DefaultTextStyle>( return tester.widget<DefaultTextStyle>(
find.descendant( find.descendant(
......
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