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
......@@ -34,6 +34,7 @@ class AppBarTheme extends Diagnosticable {
this.color,
this.elevation,
this.iconTheme,
this.actionsIconTheme,
this.textTheme,
});
......@@ -57,6 +58,11 @@ class AppBarTheme extends Diagnosticable {
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
final IconThemeData iconTheme;
/// Default value for [AppBar.actionsIconTheme].
///
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
final IconThemeData actionsIconTheme;
/// Default value for [AppBar.textTheme].
///
/// If null, [AppBar] uses [ThemeData.primaryTextTheme].
......@@ -65,6 +71,7 @@ class AppBarTheme extends Diagnosticable {
/// Creates a copy of this object with the given fields replaced with the
/// new values.
AppBarTheme copyWith({
IconThemeData actionsIconTheme,
Brightness brightness,
Color color,
double elevation,
......@@ -76,6 +83,7 @@ class AppBarTheme extends Diagnosticable {
color: color ?? this.color,
elevation: elevation ?? this.elevation,
iconTheme: iconTheme ?? this.iconTheme,
actionsIconTheme: actionsIconTheme ?? this.actionsIconTheme,
textTheme: textTheme ?? this.textTheme,
);
}
......@@ -97,6 +105,7 @@ class AppBarTheme extends Diagnosticable {
color: Color.lerp(a?.color, b?.color, t),
elevation: lerpDouble(a?.elevation, b?.elevation, 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),
);
}
......@@ -108,6 +117,7 @@ class AppBarTheme extends Diagnosticable {
color,
elevation,
iconTheme,
actionsIconTheme,
textTheme,
);
}
......@@ -123,6 +133,7 @@ class AppBarTheme extends Diagnosticable {
&& typedOther.color == color
&& typedOther.elevation == elevation
&& typedOther.iconTheme == iconTheme
&& typedOther.actionsIconTheme == actionsIconTheme
&& typedOther.textTheme == textTheme;
}
......@@ -133,6 +144,7 @@ class AppBarTheme extends Diagnosticable {
properties.add(DiagnosticsProperty<Color>('color', color, defaultValue: null));
properties.add(DiagnosticsProperty<double>('elevation', elevation, 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));
}
}
......@@ -15,17 +15,25 @@ void main() {
testWidgets('Passing no AppBarTheme returns defaults', (WidgetTester tester) async {
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 IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, Brightness.dark);
expect(widget.color, Colors.blue);
expect(widget.elevation, 4.0);
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));
});
......@@ -34,17 +42,26 @@ void main() {
await tester.pumpWidget(MaterialApp(
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 IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, appBarTheme.brightness);
expect(widget.color, appBarTheme.color);
expect(widget.elevation, appBarTheme.elevation);
expect(iconTheme.data, appBarTheme.iconTheme);
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
expect(actionIconText.text.style.color, appBarTheme.actionsIconTheme.color);
expect(text.style, appBarTheme.textTheme.body1);
});
......@@ -53,6 +70,7 @@ void main() {
const Color color = Colors.orange;
const double elevation = 3.0;
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));
final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme());
......@@ -64,38 +82,76 @@ void main() {
brightness: brightness,
elevation: elevation,
iconTheme: iconThemeData,
textTheme: textTheme,)
),
actionsIconTheme: actionsIconThemeData,
textTheme: textTheme,
actions: <Widget>[
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);
expect(SystemChrome.latestStyle.statusBarBrightness, brightness);
expect(widget.color, color);
expect(widget.elevation, elevation);
expect(iconTheme.data, iconThemeData);
expect(actionsIconTheme.data, actionsIconThemeData);
expect(actionIconText.text.style.color, actionsIconThemeData.color);
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 {
final AppBarTheme appBarTheme = _appBarTheme();
final ThemeData themeData = _themeData().copyWith(appBarTheme: _appBarTheme());
await tester.pumpWidget(MaterialApp(
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 IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, appBarTheme.brightness);
expect(widget.color, appBarTheme.color);
expect(widget.elevation, appBarTheme.elevation);
expect(iconTheme.data, appBarTheme.iconTheme);
expect(actionsIconTheme.data, appBarTheme.actionsIconTheme);
expect(actionIconText.text.style.color, appBarTheme.actionsIconTheme.color);
expect(text.style, appBarTheme.textTheme.body1);
});
......@@ -104,17 +160,25 @@ void main() {
await tester.pumpWidget(MaterialApp(
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 IconTheme iconTheme = _getAppBarIconTheme(tester);
final IconTheme actionsIconTheme = _getAppBarActionsIconTheme(tester);
final RichText actionIconText = _getAppBarIconRichText(tester);
final DefaultTextStyle text = _getAppBarText(tester);
expect(SystemChrome.latestStyle.statusBarBrightness, themeData.brightness);
expect(widget.color, themeData.primaryColor);
expect(widget.elevation, 4.0);
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));
});
}
......@@ -124,13 +188,15 @@ AppBarTheme _appBarTheme() {
const Color color = Colors.lightBlue;
const double elevation = 6.0;
const IconThemeData iconThemeData = IconThemeData(color: Colors.black);
const IconThemeData actionsIconThemeData = IconThemeData(color: Colors.pink);
const TextTheme textTheme = TextTheme(body1: TextStyle(color: Colors.yellow));
return const AppBarTheme(
actionsIconTheme: actionsIconThemeData,
brightness: brightness,
color: color,
elevation: elevation,
iconTheme: iconThemeData,
textTheme: textTheme
textTheme: textTheme,
);
}
......@@ -157,10 +223,27 @@ IconTheme _getAppBarIconTheme(WidgetTester tester) {
find.descendant(
of: find.byType(AppBar),
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) {
return tester.widget<DefaultTextStyle>(
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