Feat: Add brightnessOf method for theme (#163733)

Feat: Add brightnessOf method for theme
fixes: #163393 

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.
This commit is contained in:
Kishan Rathore
2025-04-01 00:16:44 +05:30
committed by GitHub
parent 53d93da57a
commit 082a24cdb2
2 changed files with 130 additions and 0 deletions

View File

@@ -161,6 +161,42 @@ class Theme extends StatelessWidget {
.resolveFrom(context);
}
/// 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], or its `brightness`
/// is null, it will fall back to [MediaQueryData.platformBrightness].
///
/// See also:
///
/// * [maybeBrightnessOf], which returns null if no valid [InheritedTheme] or
/// [MediaQuery] exists.
/// * [ThemeData.brightness], the property that takes precedence over
/// [MediaQueryData.platformBrightness] for descendant Material widgets.
static Brightness brightnessOf(BuildContext context) {
final _InheritedTheme? inheritedTheme =
context.dependOnInheritedWidgetOfExactType<_InheritedTheme>();
return inheritedTheme?.theme.data.brightness ?? MediaQuery.platformBrightnessOf(context);
}
/// Retrieves the [Brightness] to use for descendant Material widgets, based
/// on the value of [ThemeData.brightness] in the given [context].
///
/// If no [InheritedTheme] or [MediaQuery] can be found in the given [context], it will
/// return null.
///
/// See also:
///
/// * [ThemeData.brightness], the property that takes precedence over
/// [MediaQueryData.platformBrightness] for descendant Material widgets.
/// * [brightnessOf], which return a default value if no valid [InheritedTheme] or
/// [MediaQuery] exists, instead of returning null.
static Brightness? maybeBrightnessOf(BuildContext context) {
final _InheritedTheme? inheritedTheme =
context.dependOnInheritedWidgetOfExactType<_InheritedTheme>();
return inheritedTheme?.theme.data.brightness ?? MediaQuery.maybePlatformBrightnessOf(context);
}
@override
Widget build(BuildContext context) {
return _InheritedTheme(

View File

@@ -47,6 +47,92 @@ void main() {
expect(Theme.of(tester.element(find.text('menuItem'))).brightness, equals(Brightness.dark));
});
group('Theme.brightnessOf', () {
testWidgets('return correct brightness when just media query is given', (
WidgetTester tester,
) async {
await tester.pumpWidget(
const MediaQuery(
data: MediaQueryData(platformBrightness: Brightness.dark),
child: SizedBox(),
),
);
expect(Theme.brightnessOf(tester.element(find.byType(SizedBox))), equals(Brightness.dark));
});
testWidgets('return correct brightness with overriding theme brightness over media query', (
WidgetTester tester,
) async {
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark),
child: Theme(data: ThemeData(brightness: Brightness.light), child: const SizedBox()),
),
);
expect(Theme.brightnessOf(tester.element(find.byType(SizedBox))), equals(Brightness.light));
});
testWidgets('returns Brightness.light when no theme or media query is present', (
WidgetTester tester,
) async {
// Prevent the implicitly added View from adding a MediaQuery
await tester.pumpWidget(
RawView(view: FakeFlutterView(tester.view, viewId: 77), child: const SizedBox()),
wrapWithView: false,
);
expect(Theme.brightnessOf(tester.element(find.byType(SizedBox))), equals(Brightness.light));
});
});
group('Theme.maybeBrightnessOf', () {
testWidgets('return correct brightness when just media query is given', (
WidgetTester tester,
) async {
await tester.pumpWidget(
const MediaQuery(
data: MediaQueryData(platformBrightness: Brightness.dark),
child: SizedBox(),
),
);
expect(
Theme.maybeBrightnessOf(tester.element(find.byType(SizedBox))),
equals(Brightness.dark),
);
});
testWidgets('return correct brightness with overriding theme brightness over media query', (
WidgetTester tester,
) async {
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark),
child: Theme(data: ThemeData(brightness: Brightness.light), child: const SizedBox()),
),
);
expect(
Theme.maybeBrightnessOf(tester.element(find.byType(SizedBox))),
equals(Brightness.light),
);
});
testWidgets('returns null when no theme or media query is present', (
WidgetTester tester,
) async {
// Prevent the implicitly added View from adding a MediaQuery
await tester.pumpWidget(
RawView(view: FakeFlutterView(tester.view, viewId: 77), child: const SizedBox()),
wrapWithView: false,
);
expect(Theme.maybeBrightnessOf(tester.element(find.byType(SizedBox))), isNull);
});
});
testWidgets('Theme overrides selection style', (WidgetTester tester) async {
final Key key = UniqueKey();
const Color defaultSelectionColor = Color(0x11111111);
@@ -1242,3 +1328,11 @@ class _TextStyleProxy implements TextStyle {
throw UnimplementedError();
}
}
class FakeFlutterView extends TestFlutterView {
FakeFlutterView(TestFlutterView view, {required this.viewId})
: super(view: view, display: view.display, platformDispatcher: view.platformDispatcher);
@override
final int viewId;
}