1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import 'package:flutter/foundation.dart';
6
7import 'basic.dart';
8import 'framework.dart';
9import 'icon_theme_data.dart';
10import 'inherited_theme.dart';
11
12// Examples can assume:
13// late BuildContext context;
14
15/// Controls the default properties of icons in a widget subtree.
16///
17/// The icon theme is honored by [Icon] and [ImageIcon] widgets.
18class IconTheme extends InheritedTheme {
19 /// Creates an icon theme that controls properties of descendant widgets.
20 const IconTheme({
21 super.key,
22 required this.data,
23 required super.child,
24 });
25
26 /// Creates an icon theme that controls the properties of
27 /// descendant widgets, and merges in the current icon theme, if any.
28 static Widget merge({
29 Key? key,
30 required IconThemeData data,
31 required Widget child,
32 }) {
33 return Builder(
34 builder: (BuildContext context) {
35 return IconTheme(
36 key: key,
37 data: _getInheritedIconThemeData(context).merge(data),
38 child: child,
39 );
40 },
41 );
42 }
43
44 /// The set of properties to use for icons in this subtree.
45 final IconThemeData data;
46
47 /// The data from the closest instance of this class that encloses the given
48 /// context, if any.
49 ///
50 /// If there is no ambient icon theme, defaults to [IconThemeData.fallback].
51 /// The returned [IconThemeData] is concrete (all values are non-null; see
52 /// [IconThemeData.isConcrete]). Any properties on the ambient icon theme that
53 /// are null get defaulted to the values specified on
54 /// [IconThemeData.fallback].
55 ///
56 /// The [Theme] widget from the `material` library introduces an [IconTheme]
57 /// widget set to the [ThemeData.iconTheme], so in a Material Design
58 /// application, this will typically default to the icon theme from the
59 /// ambient [Theme].
60 ///
61 /// Typical usage is as follows:
62 ///
63 /// ```dart
64 /// IconThemeData theme = IconTheme.of(context);
65 /// ```
66 static IconThemeData of(BuildContext context) {
67 final IconThemeData iconThemeData = _getInheritedIconThemeData(context).resolve(context);
68 return iconThemeData.isConcrete
69 ? iconThemeData
70 : iconThemeData.copyWith(
71 size: iconThemeData.size ?? const IconThemeData.fallback().size,
72 fill: iconThemeData.fill ?? const IconThemeData.fallback().fill,
73 weight: iconThemeData.weight ?? const IconThemeData.fallback().weight,
74 grade: iconThemeData.grade ?? const IconThemeData.fallback().grade,
75 opticalSize: iconThemeData.opticalSize ?? const IconThemeData.fallback().opticalSize,
76 color: iconThemeData.color ?? const IconThemeData.fallback().color,
77 opacity: iconThemeData.opacity ?? const IconThemeData.fallback().opacity,
78 shadows: iconThemeData.shadows ?? const IconThemeData.fallback().shadows,
79 applyTextScaling: iconThemeData.applyTextScaling ?? const IconThemeData.fallback().applyTextScaling,
80 );
81 }
82
83 static IconThemeData _getInheritedIconThemeData(BuildContext context) {
84 final IconTheme? iconTheme = context.dependOnInheritedWidgetOfExactType<IconTheme>();
85 return iconTheme?.data ?? const IconThemeData.fallback();
86 }
87
88 @override
89 bool updateShouldNotify(IconTheme oldWidget) => data != oldWidget.data;
90
91 @override
92 Widget wrap(BuildContext context, Widget child) {
93 return IconTheme(data: data, child: child);
94 }
95
96 @override
97 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
98 super.debugFillProperties(properties);
99 data.debugFillProperties(properties);
100 }
101}
102