-
Notifications
You must be signed in to change notification settings - Fork 28.2k
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
Feat: Add brightnessOf method for theme #163733
base: master
Are you sure you want to change the base?
Conversation
This PR doesn't include implementation of InheritedModel for Theme. |
return inheritedTheme?.theme.data.brightness ?? MediaQuery.platformBrightnessOf(context); | ||
} | ||
|
||
/// Retrieves the [Brightness] to use for descendant Cupertino widgets, based |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
/// Retrieves the [Brightness] to use for descendant Cupertino widgets, based | |
/// Retrieves the [Brightness] to use for descendant Material widgets, based | |
/// on the value of [ThemeData.brightness] in the given [context]. | |
/// | |
/// If no [InheritedTheme] can be found in the given [context], it will fall | |
/// back to [MediaQueryData.platformBrightness]. | |
/// | |
/// Returns null if no valid [InheritedTheme] or [MediaQuery] widgets exist in | |
/// the ancestry tree. | |
/// | |
/// See also: | |
/// | |
/// * [ThemeData.brightness], the property that takes precedence over | |
/// [MediaQueryData.platformBrightness] for descendant Material widgets. | |
/// * [brightnessOf], which throws if no valid [InheritedTheme] or | |
/// [MediaQuery] exists, instead of returning null. |
@@ -44,7 +44,7 @@ void main() { | |||
await tester.tap(find.byKey(popupMenuButtonKey)); | |||
await tester.pump(const Duration(seconds: 1)); | |||
|
|||
expect(Theme.of(tester.element(find.text('menuItem'))).brightness, equals(Brightness.dark)); | |||
expect(Theme.brightnessOf(tester.element(find.text('menuItem'))), equals(Brightness.dark)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would propose to not do this change in this PR, we can probably do all the ThemeData.brightness
changes in a follow up PR, after this one lands. (which probably makes it a bit easier to review)
Instead, I would test the behavior of brightnessOf
/ maybeBrightnessOf
in separate tests:
- brightnessOf returns the correct brightness if only a MediaQuery is provided
- brightnessOf returns the correct brightness if both a MediaQuery & ThemeData are provided
- brightnessOf throws if neither a MediaQuery or ThemeData is provided
- maybeBrightnessOf returns the correct brightness if only a MediaQuery is provided
- maybeBrightnessOf returns the correct brightness if both a MediaQuery & ThemeData are provided
- maybeBrightnessOf returns null if neither a MediaQuery or ThemeData is provided
I will file a follow up issue to do the former sparately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, let me create another test which just verify that Theme.brightnessOf works in all scenario
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@navaronbracke I don't think scenario 3 and 6 can be produced, because in testing media query always return platform brightness.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For these tests I would just pump a widget with the WidgetTester:
- Only pumps a
MediaQuery
widget with aBuilder
as child (to get the context for the brightness test) - Pumps both a MediaQuery & a Theme widget, with a
Builder
as child - Pumps only a
Builder
widget and never pumps aMediaQuery
orTheme
widget
Cases 4-6 are variations, but use the other method.
You should be able to give the MediaQuery a custom MediaQueryData, to force the brightness?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, MediaQuery takes data as input.
4226de7
to
c2e7da0
Compare
await tester.pumpWidget( | ||
MediaQuery( | ||
data: const MediaQueryData(platformBrightness: Brightness.dark), | ||
child: Container(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use a SizedBox
, instead of a Container
to make the tests a little lighter.
await tester.pumpWidget( | ||
Theme( | ||
data: ThemeData(brightness: Brightness.light), | ||
child: MediaQuery( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the MediaQuery be above the Theme, for consistency with the real widget tree in MaterialApp?
/// | ||
/// See also: | ||
/// | ||
/// * [ThemeData.brightness], the property takes precedence over |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// * [ThemeData.brightness], the property takes precedence over | |
/// * [ThemeData.brightness], the property that takes precedence over |
/// | ||
/// * [maybeBrightnessOf], which returns null if no valid [InheritedTheme] or | ||
/// [MediaQuery] exists, instead of throwing. | ||
/// * [ThemeData.brightness], the property takes precedence over |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// * [ThemeData.brightness], the property takes precedence over | |
/// * [ThemeData.brightness], the property that takes precedence over |
/// * [maybeBrightnessOf], which returns null if no valid [InheritedTheme] or | ||
/// [MediaQuery] exists, instead of throwing. | ||
/// * [ThemeData.brightness], the property takes precedence over | ||
/// [MediaQueryData.platformBrightness] for descendant widgets. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would keep the mention of Material
, since Theme
is a Material
thing and not under the widgets library.
/// [MediaQueryData.platformBrightness] for descendant widgets. | |
/// [MediaQueryData.platformBrightness] for descendant Material widgets. |
@@ -161,6 +161,48 @@ class Theme extends StatelessWidget { | |||
.resolveFrom(context); | |||
} | |||
|
|||
/// Retrieves the [Brightness] to use for descendant widgets, based |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would keep the mention of Material
, since Theme
is a Material
thing and not under the widgets library.
/// Retrieves the [Brightness] to use for descendant widgets, based | |
/// Retrieves the [Brightness] to use for descendant Material widgets, based |
return inheritedTheme?.theme.data.brightness ?? MediaQuery.platformBrightnessOf(context); | ||
} | ||
|
||
/// Retrieves the [Brightness] to use for descendant widgets, based |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would keep the mention of Material
, since Theme
is a Material
thing and not under the widgets library.
/// Retrieves the [Brightness] to use for descendant widgets, based | |
/// Retrieves the [Brightness] to use for descendant Material widgets, based |
/// See also: | ||
/// | ||
/// * [ThemeData.brightness], the property takes precedence over | ||
/// [MediaQueryData.platformBrightness] for descendant widgets. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would keep the mention of Material
, since Theme
is a Material
thing and not under the widgets library.
/// [MediaQueryData.platformBrightness] for descendant widgets. | |
/// [MediaQueryData.platformBrightness] for descendant Material widgets. |
c2e7da0
to
f1770bd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor docs correction and a suggestion for some missing tests.
/// If no [InheritedTheme] can be found in the given [context], or its `brightness` | ||
/// is null, it will fall back to [MediaQueryData.platformBrightness]. | ||
/// | ||
/// Throws an exception if no valid [InheritedTheme] or [MediaQuery] widgets |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Throws an exception if no valid [InheritedTheme] or [MediaQuery] widgets |
I had a look at the implementation of https://api.flutter.dev/flutter/widgets/MediaQuery/platformBrightnessOf.html
and it returns Brightness.light
instead of throwing if there is no MediaQuery.
So you can remove the phrase that says it throws.
3cfa06b
to
b6c93e8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some minor docs adjustments, to match the actual behavior of the method that is used, along with a clarification for one test.
/// See also: | ||
/// | ||
/// * [maybeBrightnessOf], which returns null if no valid [InheritedTheme] or | ||
/// [MediaQuery] exists, instead of throwing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since platformBrightnessOf
does not throw, but returns a default, I think we can tweak the wording here.
/// [MediaQuery] exists, instead of throwing. | |
/// [MediaQuery] exists. |
/// If no [InheritedTheme] or [MediaQuery] can be found in the given [context], it will | ||
/// return null. | ||
/// | ||
/// Returns null if no valid [InheritedTheme] or [MediaQuery] widgets exist in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we remove this phrase? Currently it says returns null
twice
/// | ||
/// * [ThemeData.brightness], the property that takes precedence over | ||
/// [MediaQueryData.platformBrightness] for descendant Material widgets. | ||
/// * [brightnessOf], which throws if no valid [InheritedTheme] or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same tweak here, since that method does not throw.
/// * [brightnessOf], which throws if no valid [InheritedTheme] or | |
/// * [brightnessOf], which returns a default value if no valid [InheritedTheme] or |
testWidgets('returns Brightness.light when no theme or media query is present', ( | ||
WidgetTester tester, | ||
) async { | ||
await tester.pumpWidget(const SizedBox()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to prevent the View
from adding the MediaQuery here, otherwise there is an implicit MediaQuery
await tester.pumpWidget(const SizedBox()); | |
// Prevent the implicitly added View from adding a MediaQuery | |
await tester.pumpWidget( | |
RawView(view: FakeFlutterView(tester.view, viewId: 77), child: const SizedBox()), | |
wrapWithView: false, | |
); |
b6c93e8
to
26f49a7
Compare
@rkishan516 While to me this PR looks good now, I will have to defer to people on the framework team for a review / explicit approval. So you will have to be patient a little :) See https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#when for more info on the review process. |
Sure and Thanks for helping @navaronbracke. |
95dd5a5
to
227f414
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use Theme.of(context).brightness
to detect the brightness?
That is how you would do this today. However, this PR aims to make it explicit, using a named method, and is a step towards eventually making Theme an InheritedModel. The latter is the main reasoning behind this change. |
@navaronbracke I'm not familiar with this work, but is there an issue tracking our progress (and discussions, if any) towards making |
@nate-thegrate made a design doc that talks about this a little in https://docs.google.com/document/d/1MfU6gkgIgXCxa5E25sPYuAP5Bmgehyl3Hk7yDH24zl0/edit?tab=t.0 |
I've asked @MitchellGoodwin and it seems the conversation didn't reached a point were a decision was made. Although I agree with the motivation of the work, I think it'd be better not to move forward until we have agreed on the exact design and plan. If you would like to drive this project, you can start by writing a more detailed design doc with thorough planning and introduction, and we can seek comments or even host a Dash forum for discussion. |
Outside of InheritedModel, there is value in adding a brightnessOf method to Material for the sake of API parity since Cupertino has a brightnessOf method. Material and Cupertino handle their brightness differently though, in such a way were I don't think this method would decrease rebuilds the way it does for Cupertino theme. |
Yes, feature parity between the two was also something I mentioned in the OP of #163393 |
If we are able to push Theme as InheritedModel, then later part will not be an issue. If we decide to go with migrating Theme to InheritedModel, I won't mind doing that change. |
bf5e57e
to
1f075f8
Compare
Feat: Add brightnessOf method for theme
fixes: #163393
Pre-launch Checklist
///
).