Fix Status Bar Icon Brightness (#162297)
On Android devices, the statusBar is now by default transparent starting android API 35 [here](https://developer.android.com/develop/ui/views/layout/edge-to-edge#:~:text=system%20bars%20transparent) (due to automatic opt-in to edge to edge mode [here](https://developer.android.com/develop/ui/views/layout/edge-to-edge#:~:text=Important%3A%20Edge%2Dto%2Dedge%20is%20enforced%20on%20Android%2015%20(API%20level%2035)%20and%20higher%20once%20your%20app%20targets%20SDK%2035.%20If%20your%20app%20is%20not%20already%20edge%2Dto%2Dedge%2C%20portions%20of%20your%20app%20may%20be%20obscured%20and%20you%20must%20handle%20insets.%20Depending%20on%20the%20app%2C%20this%20work%20may%20or%20may%20not%20be%20significant.)), which is making the statusBar icons difficult to see. We decided to make the change in Cupertino/Material layer as opposed to the embedder layer becasue we cannot make assumptions on the defaults when we don't know what kind of Widgets the Flutter dev will be using. In MaterialApp, the `statusBarIconBrightness` is made to be dark because the system's brightness (dark mode or light mode) **does not affect** the brightness of the default app. This means when I turn on dark mode on my phone, the app does not use a dark theme—it uses the same light theme. In CupertinoApp, the `statusBarIconBrightness` is made to be opposite of the system's brightness (dark mode or light mode) because the system **does affect** the brightness of the default app. The system and the default app have the same brightness. This means when I turn on dark mode on my phone, the app also uses a dark theme. Fixes #160305 ## 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. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This commit is contained in:
parent
41c3008afb
commit
75df59e62f
@ -10,6 +10,7 @@
|
||||
library;
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'button.dart';
|
||||
@ -652,6 +653,14 @@ class _CupertinoAppState extends State<CupertinoApp> {
|
||||
final CupertinoThemeData effectiveThemeData = (widget.theme ?? const CupertinoThemeData())
|
||||
.resolveFrom(context);
|
||||
|
||||
// Prefer theme brightness if set, otherwise check system brightness.
|
||||
final Brightness brightness =
|
||||
effectiveThemeData.brightness ?? MediaQuery.platformBrightnessOf(context);
|
||||
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
|
||||
);
|
||||
|
||||
return ScrollConfiguration(
|
||||
behavior: widget.scrollBehavior ?? const CupertinoScrollBehavior(),
|
||||
child: CupertinoUserInterfaceLevel(
|
||||
|
@ -1009,6 +1009,10 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||
theme = widget.highContrastTheme;
|
||||
}
|
||||
theme ??= widget.theme ?? ThemeData.light();
|
||||
SystemChrome.setSystemUIOverlayStyle(
|
||||
theme.brightness == Brightness.dark ? SystemUiOverlayStyle.light : SystemUiOverlayStyle.dark,
|
||||
);
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,13 @@ export 'dart:ui' show Brightness, Color;
|
||||
|
||||
export 'binding.dart' show SystemUiChangeCallback;
|
||||
|
||||
// Examples can assume:
|
||||
// import 'dart:ui' as ui;
|
||||
// import 'package:flutter/services.dart';
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:flutter/widgets.dart';
|
||||
// late BuildContext context;
|
||||
|
||||
/// Specifies a particular device orientation.
|
||||
///
|
||||
/// To determine which values correspond to which orientations, first position
|
||||
@ -644,6 +651,20 @@ abstract final class SystemChrome {
|
||||
/// ** See code in examples/api/lib/services/system_chrome/system_chrome.set_system_u_i_overlay_style.1.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// To imperatively set the style of the system overlays, use [SystemChrome.setSystemUIOverlayStyle].
|
||||
///
|
||||
/// {@tool snippet}
|
||||
/// The following example uses SystemChrome to set the status bar icon brightness based on system brightness.
|
||||
/// ```dart
|
||||
/// final Brightness brightness = MediaQuery.platformBrightnessOf(context);
|
||||
/// SystemChrome.setSystemUIOverlayStyle(
|
||||
/// SystemUiOverlayStyle(
|
||||
/// statusBarIconBrightness: brightness == Brightness.dark ? Brightness.light : Brightness.dark,
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [AppBar.systemOverlayStyle], a convenient property for declaratively setting
|
||||
|
@ -481,6 +481,72 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('CupertinoApp uses the dark SystemUIOverlayStyle when the background is light', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
theme: CupertinoThemeData(brightness: Brightness.light),
|
||||
home: CupertinoPageScaffold(child: Text('Hello')),
|
||||
),
|
||||
);
|
||||
|
||||
expect(SystemChrome.latestStyle, SystemUiOverlayStyle.dark);
|
||||
});
|
||||
|
||||
testWidgets('CupertinoApp uses the light SystemUIOverlayStyle when the background is dark', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
await tester.pumpWidget(
|
||||
const CupertinoApp(
|
||||
theme: CupertinoThemeData(brightness: Brightness.dark),
|
||||
home: CupertinoPageScaffold(child: Text('Hello')),
|
||||
),
|
||||
);
|
||||
|
||||
expect(SystemChrome.latestStyle, SystemUiOverlayStyle.light);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'CupertinoApp uses the dark SystemUIOverlayStyle when theme brightness is null and the system is in light mode',
|
||||
(WidgetTester tester) async {
|
||||
// The theme brightness is null by default.
|
||||
// The system is in light mode by default.
|
||||
await tester.pumpWidget(
|
||||
MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: CupertinoApp(
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return const Placeholder();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(SystemChrome.latestStyle, SystemUiOverlayStyle.dark);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'CupertinoApp uses the light SystemUIOverlayStyle when theme brightness is null and the system is in dark mode',
|
||||
(WidgetTester tester) async {
|
||||
// The theme brightness is null by default.
|
||||
// Simulates setting the system to dark mode.
|
||||
await tester.pumpWidget(
|
||||
MediaQuery(
|
||||
data: const MediaQueryData(platformBrightness: Brightness.dark),
|
||||
child: CupertinoApp(
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
return const Placeholder();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(SystemChrome.latestStyle, SystemUiOverlayStyle.light);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('Text color is correctly resolved when CupertinoThemeData.brightness is null', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
|
@ -9,6 +9,7 @@ library;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
|
||||
import '../widgets/multi_view_testing.dart';
|
||||
@ -284,6 +285,30 @@ void main() {
|
||||
expect(pressed, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('Material uses the dark SystemUIOverlayStyle when the background is light', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final ThemeData lightTheme = ThemeData();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(theme: lightTheme, home: const Scaffold(body: Center(child: Text('test')))),
|
||||
);
|
||||
|
||||
expect(lightTheme.colorScheme.brightness, Brightness.light);
|
||||
expect(SystemChrome.latestStyle, SystemUiOverlayStyle.dark);
|
||||
});
|
||||
|
||||
testWidgets('Material uses the light SystemUIOverlayStyle when the background is dark', (
|
||||
WidgetTester tester,
|
||||
) async {
|
||||
final ThemeData darkTheme = ThemeData.dark();
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(theme: darkTheme, home: const Scaffold(body: Center(child: Text('test')))),
|
||||
);
|
||||
|
||||
expect(darkTheme.colorScheme.brightness, Brightness.dark);
|
||||
expect(SystemChrome.latestStyle, SystemUiOverlayStyle.light);
|
||||
});
|
||||
|
||||
group('Surface Tint Overlay', () {
|
||||
testWidgets(
|
||||
'applyElevationOverlayColor does not effect anything with useMaterial3 set to true',
|
||||
|
Loading…
x
Reference in New Issue
Block a user