Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Feat: Migrate Theme to InheritedModel #165289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
20 changes: 18 additions & 2 deletions packages/flutter/lib/src/cupertino/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class CupertinoTheme extends StatelessWidget {
///
/// Resolves all the colors defined in that [CupertinoThemeData] against the
/// given [BuildContext] on a best-effort basis.
///
/// For specific theme properties, consider using [selectOf],
/// which will only rebuild widget when the selected property changes.
static CupertinoThemeData of(BuildContext context) {
final InheritedCupertinoTheme? inheritedTheme =
context.dependOnInheritedWidgetOfExactType<InheritedCupertinoTheme>();
Expand Down Expand Up @@ -114,6 +117,19 @@ class CupertinoTheme extends StatelessWidget {
return inheritedTheme?.theme.data.brightness ?? MediaQuery.maybePlatformBrightnessOf(context);
}

/// Evaluates [ThemeSelector.selectFrom] using [data] provided by the
/// nearest ancestor [CupertinoTheme] widget, and returns the result.
///
/// When this value changes, a notification is sent to the [context]
/// to trigger an update.
static T selectOf<T>(BuildContext context, T Function(CupertinoThemeData) selector) {
final ThemeSelector<CupertinoThemeData, T> themeSelector =
ThemeSelector<CupertinoThemeData, T>.from(selector);
final InheritedCupertinoTheme? inheritedTheme =
InheritedModel.inheritFrom<InheritedCupertinoTheme>(context, aspect: themeSelector);
return themeSelector.selectFrom(inheritedTheme?.theme.data ?? const CupertinoThemeData());
}

/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.ProxyWidget.child}
Expand All @@ -135,7 +151,7 @@ class CupertinoTheme extends StatelessWidget {
}

/// Provides a [CupertinoTheme] to all descendents.
class InheritedCupertinoTheme extends InheritedTheme {
class InheritedCupertinoTheme extends InheritedTheme<CupertinoThemeData> {
/// Creates an [InheritedTheme] that provides a [CupertinoTheme] to all
/// descendents.
const InheritedCupertinoTheme({super.key, required this.theme, required super.child});
Expand All @@ -149,7 +165,7 @@ class InheritedCupertinoTheme extends InheritedTheme {
}

@override
bool updateShouldNotify(InheritedCupertinoTheme oldWidget) => theme.data != oldWidget.theme.data;
CupertinoThemeData get themeData => theme.data;
}

/// Styling specifications for a [CupertinoTheme].
Expand Down
26 changes: 24 additions & 2 deletions packages/flutter/lib/src/material/action_icons_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class ActionIconThemeData with Diagnosticable {
///
/// ** See code in examples/api/lib/material/action_buttons/action_icon_theme.0.dart **
/// {@end-tool}
class ActionIconTheme extends InheritedTheme {
class ActionIconTheme extends InheritedTheme<ActionIconThemeData> {
/// Creates a theme that overrides the default icon of [BackButtonIcon],
/// [CloseButtonIcon], [DrawerButtonIcon], and [EndDrawerButtonIcon] in this
/// widget's subtree.
Expand All @@ -166,6 +166,15 @@ class ActionIconTheme extends InheritedTheme {
/// If there is no enclosing [ActionIconTheme] widget, then
/// [ThemeData.actionIconTheme] is used.
///
/// For specific theme properties, consider using [selectOf],
/// which will only rebuild widget when the selected property changes:
/// ```dart
/// final Widget Function(BuildContext)? closeButtonIconBuilder = ActionIconTheme.selectOf(
/// context,
/// (ActionIconThemeData data) => data.closeButtonIconBuilder
/// );
/// ```
///
/// Typical usage is as follows:
///
/// ```dart
Expand All @@ -177,11 +186,24 @@ class ActionIconTheme extends InheritedTheme {
return actionIconTheme?.data ?? Theme.of(context).actionIconTheme;
}

/// Evaluates [ThemeSelector.selectFrom] using [data] provided by the
/// nearest ancestor [ActionIconTheme] widget, and returns the result.
///
/// When this value changes, a notification is sent to the [context]
/// to trigger an update.
static T selectOf<T>(BuildContext context, T Function(ActionIconThemeData) selector) {
final ThemeSelector<ActionIconThemeData, T> themeSelector =
ThemeSelector<ActionIconThemeData, T>.from(selector);
final ActionIconThemeData theme =
InheritedModel.inheritFrom<ActionIconTheme>(context, aspect: themeSelector)!.data;
return themeSelector.selectFrom(theme);
}

@override
Widget wrap(BuildContext context, Widget child) {
return ActionIconTheme(data: data, child: child);
}

@override
bool updateShouldNotify(ActionIconTheme oldWidget) => data != oldWidget.data;
ActionIconThemeData get themeData => data;
}
27 changes: 25 additions & 2 deletions packages/flutter/lib/src/material/badge_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ class BadgeThemeData with Diagnosticable {
///
/// Values specified here override the defaults for [Badge] properties which
/// are not given an explicit non-null value.
class BadgeTheme extends InheritedTheme {
class BadgeTheme extends InheritedTheme<BadgeThemeData> {
/// Creates a theme that overrides the default color parameters for [Badge]s
/// in this widget's subtree.
const BadgeTheme({super.key, required this.data, required super.child});
Expand All @@ -176,6 +176,15 @@ class BadgeTheme extends InheritedTheme {
/// If there is no enclosing [BadgeTheme] widget, then
/// [ThemeData.badgeTheme] is used.
///
/// For specific theme properties, consider using [selectOf],
/// which will only rebuild widget when the selected property changes:
/// ```dart
/// final Color? backgroundColor = BadgeTheme.selectOf(
/// context,
/// (BadgeThemeData data) => data.backgroundColor,
/// );
/// ```
///
/// Typical usage is as follows:
///
/// ```dart
Expand All @@ -186,11 +195,25 @@ class BadgeTheme extends InheritedTheme {
return badgeTheme?.data ?? Theme.of(context).badgeTheme;
}

/// Evaluates [ThemeSelector.selectFrom] using [data] provided by the
/// nearest ancestor [BadgeTheme] widget, and returns the result.
///
/// When this value changes, a notification is sent to the [context]
/// to trigger an update.
static T selectOf<T>(BuildContext context, T Function(BadgeThemeData) selector) {
final ThemeSelector<BadgeThemeData, T> themeSelector = ThemeSelector<BadgeThemeData, T>.from(
selector,
);
final BadgeThemeData theme =
InheritedModel.inheritFrom<BadgeTheme>(context, aspect: themeSelector)!.data;
return themeSelector.selectFrom(theme);
}

@override
Widget wrap(BuildContext context, Widget child) {
return BadgeTheme(data: data, child: child);
}

@override
bool updateShouldNotify(BadgeTheme oldWidget) => data != oldWidget.data;
BadgeThemeData get themeData => data;
}
42 changes: 41 additions & 1 deletion packages/flutter/lib/src/material/banner_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class MaterialBannerThemeData with Diagnosticable {
///
/// Values specified here are used for [MaterialBanner] properties that are not
/// given an explicit non-null value.
class MaterialBannerTheme extends InheritedTheme {
class MaterialBannerTheme extends InheritedTheme<MaterialBannerThemeData> {
/// Creates a banner theme that controls the configurations for
/// [MaterialBanner]s in its widget subtree.
const MaterialBannerTheme({super.key, this.data, required super.child});
Expand All @@ -185,6 +185,15 @@ class MaterialBannerTheme extends InheritedTheme {
/// If there is no ancestor, it returns [ThemeData.bannerTheme]. Applications
/// can assume that the returned value will not be null.
///
/// For specific theme properties, consider using [selectOf],
/// which will only rebuild widget when the selected property changes:
/// ```dart
/// final Color? backgroundColor = MaterialBannerTheme.selectOf(
/// context,
/// (MaterialBannerThemeData data) => data.backgroundColor!,
/// );
/// ```
///
/// Typical usage is as follows:
///
/// ```dart
Expand All @@ -196,11 +205,42 @@ class MaterialBannerTheme extends InheritedTheme {
return bannerTheme?.data ?? Theme.of(context).bannerTheme;
}

/// Evaluates [ThemeSelector.selectFrom] using [data] provided by the
/// nearest ancestor [MaterialBannerTheme] widget, and returns the result.
///
/// When this value changes, a notification is sent to the [context]
/// to trigger an update.
static T? selectOf<T>(BuildContext context, T Function(MaterialBannerThemeData) selector) {
final ThemeSelector<MaterialBannerThemeData, T> themeSelector =
ThemeSelector<MaterialBannerThemeData, T>.from(selector);
final MaterialBannerThemeData? theme =
InheritedModel.inheritFrom<MaterialBannerTheme>(context, aspect: themeSelector)?.data;
return theme == null ? null : themeSelector.selectFrom(theme);
}

@override
Widget wrap(BuildContext context, Widget child) {
return MaterialBannerTheme(data: data, child: child);
}

@override
bool updateShouldNotify(MaterialBannerTheme oldWidget) => data != oldWidget.data;

@override
bool updateShouldNotifyDependent(
MaterialBannerTheme oldWidget,
Set<ThemeSelector<MaterialBannerThemeData, Object?>> dependencies,
) {
for (final ThemeSelector<MaterialBannerThemeData, Object?> selector in dependencies) {
final Object? oldValue = oldWidget.data == null ? null : selector.selectFrom(oldWidget.data!);
final Object? newValue = data == null ? null : selector.selectFrom(data!);
if (oldValue != newValue) {
return true;
}
}
return false;
}

@override
MaterialBannerThemeData get themeData => data!;
}
26 changes: 24 additions & 2 deletions packages/flutter/lib/src/material/button_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ enum ButtonBarLayoutBehavior {
///
/// * [RawMaterialButton], which can be used to configure a button that doesn't
/// depend on any inherited themes.
class ButtonTheme extends InheritedTheme {
class ButtonTheme extends InheritedTheme<ButtonThemeData> {
/// Creates a button theme.
ButtonTheme({
super.key,
Expand Down Expand Up @@ -126,6 +126,14 @@ class ButtonTheme extends InheritedTheme {

/// The closest instance of this class that encloses the given context.
///
/// For specific theme properties, consider using [selectOf],
/// which will only rebuild widget when the selected property changes:
/// ```dart
/// final double height = ButtonTheme.selectOf(
/// context, (ButtonThemeData data) => data.height,
/// );
/// ```
///
/// Typical usage is as follows:
///
/// ```dart
Expand All @@ -149,13 +157,27 @@ class ButtonTheme extends InheritedTheme {
return buttonTheme!;
}

/// Evaluates [ThemeSelector.selectFrom] using [data] provided by the
/// nearest ancestor [ButtonTheme] widget, and returns the result.
///
/// When this value changes, a notification is sent to the [context]
/// to trigger an update.
static T selectOf<T>(BuildContext context, T Function(ButtonThemeData) selector) {
final ThemeSelector<ButtonThemeData, T> themeSelector = ThemeSelector<ButtonThemeData, T>.from(
selector,
);
final ButtonThemeData theme =
InheritedModel.inheritFrom<ButtonTheme>(context, aspect: themeSelector)!.data;
return themeSelector.selectFrom(theme);
}

@override
Widget wrap(BuildContext context, Widget child) {
return ButtonTheme.fromButtonThemeData(data: data, child: child);
}

@override
bool updateShouldNotify(ButtonTheme oldWidget) => data != oldWidget.data;
ButtonThemeData get themeData => data;
}

/// Used with [ButtonTheme] to configure the color and geometry of buttons.
Expand Down
18 changes: 15 additions & 3 deletions packages/flutter/lib/src/material/carousel_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class CarouselViewThemeData with Diagnosticable {
/// * [CarouselViewThemeData], which describes the actual configuration of a carousel
/// theme.
/// * [Theme], which controls the overall theme inheritance.
class CarouselViewTheme extends InheritedTheme {
class CarouselViewTheme extends InheritedTheme<CarouselViewThemeData> {
/// Creates a carousel theme that configures all descendant [CarouselView] widgets.
const CarouselViewTheme({super.key, required this.data, required super.child});

Expand All @@ -171,13 +171,25 @@ class CarouselViewTheme extends InheritedTheme {
return inheritedTheme?.data ?? Theme.of(context).carouselViewTheme;
}

/// Evaluates [ThemeSelector.selectFrom] using [data] provided by the
/// nearest ancestor [CarouselViewTheme] widget, and returns the result.
///
/// When this value changes, a notification is sent to the [context]
/// to trigger an update.
static T selectOf<T>(BuildContext context, T Function(CarouselViewThemeData) selector) {
final ThemeSelector<CarouselViewThemeData, T> themeSelector =
ThemeSelector<CarouselViewThemeData, T>.from(selector);
final CarouselViewThemeData theme =
InheritedModel.inheritFrom<CarouselViewTheme>(context, aspect: themeSelector)!.data;
return themeSelector.selectFrom(theme);
}

/// Wraps the given [child] with a [CarouselViewTheme] containing the [data].
@override
Widget wrap(BuildContext context, Widget child) {
return CarouselViewTheme(data: data, child: child);
}

/// Returns true if the [data] fields of the two themes are different.
@override
bool updateShouldNotify(CarouselViewTheme oldWidget) => data != oldWidget.data;
CarouselViewThemeData get themeData => data;
}
21 changes: 19 additions & 2 deletions packages/flutter/lib/src/material/chip_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import 'theme.dart';
/// theme.
/// * [ThemeData], which describes the overall theme information for the
/// application.
class ChipTheme extends InheritedTheme {
class ChipTheme extends InheritedTheme<ChipThemeData> {
/// Applies the given theme [data] to [child].
const ChipTheme({super.key, required this.data, required super.child});

Expand All @@ -63,6 +63,9 @@ class ChipTheme extends InheritedTheme {
/// Defaults to the ambient [ThemeData.chipTheme] if there is no
/// [ChipTheme] in the given build context.
///
/// For specific theme properties, consider using [selectOf],
/// which will only rebuild widget when the selected property changes.
///
/// {@tool snippet}
///
/// ```dart
Expand Down Expand Up @@ -92,13 +95,27 @@ class ChipTheme extends InheritedTheme {
return inheritedTheme?.data ?? Theme.of(context).chipTheme;
}

/// Evaluates [ThemeSelector.selectFrom] using [data] provided by the
/// nearest ancestor [ChipTheme] widget, and returns the result.
///
/// When this value changes, a notification is sent to the [context]
/// to trigger an update.
static T selectOf<T>(BuildContext context, T Function(ChipThemeData) selector) {
final ThemeSelector<ChipThemeData, T> themeSelector = ThemeSelector<ChipThemeData, T>.from(
selector,
);
final ChipThemeData theme =
InheritedModel.inheritFrom<ChipTheme>(context, aspect: themeSelector)!.data;
return themeSelector.selectFrom(theme);
}

@override
Widget wrap(BuildContext context, Widget child) {
return ChipTheme(data: data, child: child);
}

@override
bool updateShouldNotify(ChipTheme oldWidget) => data != oldWidget.data;
ChipThemeData get themeData => data;
}

/// Holds the color, shape, and text styles for a Material Design chip theme.
Expand Down
Loading