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';
import 'package:flutter/widgets.dart';
import 'icon_theme_data.dart';
import 'theme.dart';
/// Controls the default color, opacity, and size of icons in a widget subtree.
///
......@@ -64,7 +63,7 @@ class IconTheme extends InheritedWidget {
static IconThemeData _getInheritedIconThemeData(BuildContext context) {
final IconTheme iconTheme = context.inheritFromWidgetOfExactType(IconTheme);
return iconTheme?.data ?? Theme.of(context).iconTheme;
return iconTheme?.data ?? const IconThemeData.fallback();
}
@override
......
......@@ -5,6 +5,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'icon_theme.dart';
import 'theme_data.dart';
export 'theme_data.dart' show Brightness, ThemeData;
......@@ -20,6 +21,9 @@ const Duration kThemeAnimationDuration = const Duration(milliseconds: 200);
/// [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] widget implies an [IconTheme] widget, set to the value of the
/// [ThemeData.iconTheme] of the [data] for the [Theme].
///
/// See also:
///
/// * [ThemeData], which describes the actual configuration of a theme.
......@@ -27,7 +31,7 @@ const Duration kThemeAnimationDuration = const Duration(milliseconds: 200);
/// than changing the theme all at once.
/// * [MaterialApp], which includes an [AnimatedTheme] widget configured via
/// the [MaterialApp.theme] argument.
class Theme extends InheritedWidget {
class Theme extends StatelessWidget {
/// Applies the given theme [data] to [child].
///
/// The [data] and [child] arguments must not be null.
......@@ -35,10 +39,10 @@ class Theme extends InheritedWidget {
Key key,
@required this.data,
this.isMaterialAppTheme: false,
@required Widget child
@required this.child,
}) : assert(child != null),
assert(data != null),
super(key: key, child: child);
super(key: key);
/// Specifies the color and typography values for descendant widgets.
final ThemeData data;
......@@ -54,6 +58,9 @@ class Theme extends InheritedWidget {
/// routes, like [PopupMenuButton] and [DropdownButton], do this.
final bool isMaterialAppTheme;
/// The widget below this widget in the tree.
final Widget child;
static final ThemeData _kFallbackTheme = new ThemeData.fallback();
/// The data from the closest [Theme] instance that encloses the given
......@@ -110,17 +117,26 @@ class Theme extends InheritedWidget {
/// }
/// ```
static ThemeData of(BuildContext context, { bool shadowThemeOnly: false }) {
final Theme theme = context.inheritFromWidgetOfExactType(Theme);
final _InheritedTheme inheritedTheme =
context.inheritFromWidgetOfExactType(_InheritedTheme);
if (shadowThemeOnly) {
if (theme == null || theme.isMaterialAppTheme)
if (inheritedTheme == null || inheritedTheme.theme.isMaterialAppTheme)
return null;
return theme.data;
return inheritedTheme.theme.data;
}
return (theme != null) ? theme.data : _kFallbackTheme;
return (inheritedTheme != null) ? inheritedTheme.theme.data : _kFallbackTheme;
}
@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
void debugFillDescription(List<String> description) {
......@@ -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.
///
/// This class specializes the interpolation of [Tween<ThemeData>] to call the
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
......@@ -231,4 +232,37 @@ void main() {
expect(materials[0].color, green); // app 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