Commit 95e9e7e9 authored by xster's avatar xster Committed by GitHub

Theme inserts IconTheme into tree (#10179)

* Let Theme insert an IconTheme into the widget tree

* flip the order, no real reason

* Let icon theme use its own fallback

* review notes

* more review notes
parent 48237d54
...@@ -6,7 +6,6 @@ import 'package:flutter/foundation.dart'; ...@@ -6,7 +6,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'icon_theme_data.dart'; import 'icon_theme_data.dart';
import 'theme.dart';
/// Controls the default color, opacity, and size of icons in a widget subtree. /// Controls the default color, opacity, and size of icons in a widget subtree.
/// ///
...@@ -64,7 +63,7 @@ class IconTheme extends InheritedWidget { ...@@ -64,7 +63,7 @@ class IconTheme extends InheritedWidget {
static IconThemeData _getInheritedIconThemeData(BuildContext context) { static IconThemeData _getInheritedIconThemeData(BuildContext context) {
final IconTheme iconTheme = context.inheritFromWidgetOfExactType(IconTheme); final IconTheme iconTheme = context.inheritFromWidgetOfExactType(IconTheme);
return iconTheme?.data ?? Theme.of(context).iconTheme; return iconTheme?.data ?? const IconThemeData.fallback();
} }
@override @override
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'icon_theme.dart';
import 'theme_data.dart'; import 'theme_data.dart';
export 'theme_data.dart' show Brightness, ThemeData; export 'theme_data.dart' show Brightness, ThemeData;
...@@ -20,6 +21,9 @@ const Duration kThemeAnimationDuration = const Duration(milliseconds: 200); ...@@ -20,6 +21,9 @@ const Duration kThemeAnimationDuration = const Duration(milliseconds: 200);
/// [Theme.of]. When a widget uses [Theme.of], it is automatically rebuilt if /// [Theme.of]. When a widget uses [Theme.of], it is automatically rebuilt if
/// the theme later changes, so that the changes can be applied. /// the theme later changes, so that the changes can be applied.
/// ///
/// The [Theme] widget implies an [IconTheme] widget, set to the value of the
/// [ThemeData.iconTheme] of the [data] for the [Theme].
///
/// See also: /// See also:
/// ///
/// * [ThemeData], which describes the actual configuration of a theme. /// * [ThemeData], which describes the actual configuration of a theme.
...@@ -27,7 +31,7 @@ const Duration kThemeAnimationDuration = const Duration(milliseconds: 200); ...@@ -27,7 +31,7 @@ const Duration kThemeAnimationDuration = const Duration(milliseconds: 200);
/// than changing the theme all at once. /// than changing the theme all at once.
/// * [MaterialApp], which includes an [AnimatedTheme] widget configured via /// * [MaterialApp], which includes an [AnimatedTheme] widget configured via
/// the [MaterialApp.theme] argument. /// the [MaterialApp.theme] argument.
class Theme extends InheritedWidget { class Theme extends StatelessWidget {
/// Applies the given theme [data] to [child]. /// Applies the given theme [data] to [child].
/// ///
/// The [data] and [child] arguments must not be null. /// The [data] and [child] arguments must not be null.
...@@ -35,10 +39,10 @@ class Theme extends InheritedWidget { ...@@ -35,10 +39,10 @@ class Theme extends InheritedWidget {
Key key, Key key,
@required this.data, @required this.data,
this.isMaterialAppTheme: false, this.isMaterialAppTheme: false,
@required Widget child @required this.child,
}) : assert(child != null), }) : assert(child != null),
assert(data != null), assert(data != null),
super(key: key, child: child); super(key: key);
/// Specifies the color and typography values for descendant widgets. /// Specifies the color and typography values for descendant widgets.
final ThemeData data; final ThemeData data;
...@@ -54,6 +58,9 @@ class Theme extends InheritedWidget { ...@@ -54,6 +58,9 @@ class Theme extends InheritedWidget {
/// routes, like [PopupMenuButton] and [DropdownButton], do this. /// routes, like [PopupMenuButton] and [DropdownButton], do this.
final bool isMaterialAppTheme; final bool isMaterialAppTheme;
/// The widget below this widget in the tree.
final Widget child;
static final ThemeData _kFallbackTheme = new ThemeData.fallback(); static final ThemeData _kFallbackTheme = new ThemeData.fallback();
/// The data from the closest [Theme] instance that encloses the given /// The data from the closest [Theme] instance that encloses the given
...@@ -110,17 +117,26 @@ class Theme extends InheritedWidget { ...@@ -110,17 +117,26 @@ class Theme extends InheritedWidget {
/// } /// }
/// ``` /// ```
static ThemeData of(BuildContext context, { bool shadowThemeOnly: false }) { static ThemeData of(BuildContext context, { bool shadowThemeOnly: false }) {
final Theme theme = context.inheritFromWidgetOfExactType(Theme); final _InheritedTheme inheritedTheme =
context.inheritFromWidgetOfExactType(_InheritedTheme);
if (shadowThemeOnly) { if (shadowThemeOnly) {
if (theme == null || theme.isMaterialAppTheme) if (inheritedTheme == null || inheritedTheme.theme.isMaterialAppTheme)
return null; return null;
return theme.data; return inheritedTheme.theme.data;
} }
return (theme != null) ? theme.data : _kFallbackTheme; return (inheritedTheme != null) ? inheritedTheme.theme.data : _kFallbackTheme;
} }
@override @override
bool updateShouldNotify(Theme old) => data != old.data; Widget build(BuildContext context) {
return new _InheritedTheme(
theme: this,
child: new IconTheme(
data: data.iconTheme,
child: child,
),
);
}
@override @override
void debugFillDescription(List<String> description) { void debugFillDescription(List<String> description) {
...@@ -129,6 +145,20 @@ class Theme extends InheritedWidget { ...@@ -129,6 +145,20 @@ class Theme extends InheritedWidget {
} }
} }
class _InheritedTheme extends InheritedWidget {
const _InheritedTheme({
Key key,
@required this.theme,
@required Widget child
}) : assert(theme != null),
super(key: key, child: child);
final Theme theme;
@override
bool updateShouldNotify(_InheritedTheme old) => theme != old.theme;
}
/// An interpolation between two [ThemeData]s. /// An interpolation between two [ThemeData]s.
/// ///
/// This class specializes the interpolation of [Tween<ThemeData>] to call the /// This class specializes the interpolation of [Tween<ThemeData>] to call the
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
...@@ -231,4 +232,37 @@ void main() { ...@@ -231,4 +232,37 @@ void main() {
expect(materials[0].color, green); // app scaffold expect(materials[0].color, green); // app scaffold
expect(materials[1].color, green); // dialog scaffold expect(materials[1].color, green); // dialog scaffold
}); });
testWidgets('IconThemes are applied', (WidgetTester tester) async {
await tester.pumpWidget(
new MaterialApp(
theme: new ThemeData(iconTheme: const IconThemeData(color: Colors.green, size: 10.0)),
home: const Icon(Icons.computer),
)
);
RenderParagraph glyphText = tester.renderObject(find.byType(RichText));
expect(glyphText.text.style.color, Colors.green);
expect(glyphText.text.style.fontSize, 10.0);
await tester.pumpWidget(
new MaterialApp(
theme: new ThemeData(iconTheme: const IconThemeData(color: Colors.orange, size: 20.0)),
home: const Icon(Icons.computer),
),
);
await tester.pump(const Duration(milliseconds: 100)); // Halfway through the theme transition
glyphText = tester.renderObject(find.byType(RichText));
expect(glyphText.text.style.color, Color.lerp(Colors.green, Colors.orange, 0.5));
expect(glyphText.text.style.fontSize, 15.0);
await tester.pump(const Duration(milliseconds: 100)); // Finish the transition
glyphText = tester.renderObject(find.byType(RichText));
expect(glyphText.text.style.color, Colors.orange);
expect(glyphText.text.style.fontSize, 20.0);
});
} }
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