@@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@@ -96,6 +98,7 @@ class MaterialApp extends StatefulWidget {
|
||||
this.onGenerateTitle,
|
||||
this.color,
|
||||
this.theme,
|
||||
this.darkTheme,
|
||||
this.locale,
|
||||
this.localizationsDelegates,
|
||||
this.localeListResolutionCallback,
|
||||
@@ -163,9 +166,44 @@ class MaterialApp extends StatefulWidget {
|
||||
/// This value is passed unmodified to [WidgetsApp.onGenerateTitle].
|
||||
final GenerateAppTitle onGenerateTitle;
|
||||
|
||||
/// The colors to use for the application's widgets.
|
||||
/// Default visual properties, like colors fonts and shapes, for this app's
|
||||
/// material widgets.
|
||||
///
|
||||
/// A second [darkTheme] [ThemeData] value, which is used when the underlying
|
||||
/// platform requests a "dark mode" UI, can also be specified.
|
||||
///
|
||||
/// The default value of this property is the value of [ThemeData.light()].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MediaQueryData.platformBrightness], which indicates the platform's
|
||||
/// desired brightness and is used to automatically toggle between [theme]
|
||||
/// and [darkTheme] in [MaterialApp].
|
||||
/// * [ThemeData.brightness], which indicates the [Brightness] of a theme's
|
||||
/// colors.
|
||||
final ThemeData theme;
|
||||
|
||||
/// The [ThemeData] to use when the platform specifically requests a dark
|
||||
/// themed UI.
|
||||
///
|
||||
/// Host platforms such as Android Pie can request a system-wide "dark mode"
|
||||
/// when entering battery saver mode.
|
||||
///
|
||||
/// When the host platform requests a [Brightness.dark] mode, you may want to
|
||||
/// supply a [ThemeData.brightness] that's also [Brightness.dark].
|
||||
///
|
||||
/// Uses [theme] instead when null. Defaults to the value of
|
||||
/// [ThemeData.light()] when both [darkTheme] and [theme] are null.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MediaQueryData.platformBrightness], which indicates the platform's
|
||||
/// desired brightness and is used to automatically toggle between [theme]
|
||||
/// and [darkTheme] in [MaterialApp].
|
||||
/// * [ThemeData.brightness], which is typically set to the value of
|
||||
/// [MediaQueryData.platformBrightness].
|
||||
final ThemeData darkTheme;
|
||||
|
||||
/// {@macro flutter.widgets.widgetsApp.color}
|
||||
final Color color;
|
||||
|
||||
@@ -403,45 +441,80 @@ class _MaterialAppState extends State<MaterialApp> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = widget.theme ?? ThemeData.fallback();
|
||||
Widget result = AnimatedTheme(
|
||||
data: theme,
|
||||
isMaterialAppTheme: true,
|
||||
child: WidgetsApp(
|
||||
key: GlobalObjectKey(this),
|
||||
navigatorKey: widget.navigatorKey,
|
||||
navigatorObservers: _navigatorObservers,
|
||||
Widget result = WidgetsApp(
|
||||
key: GlobalObjectKey(this),
|
||||
navigatorKey: widget.navigatorKey,
|
||||
navigatorObservers: _navigatorObservers,
|
||||
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) =>
|
||||
MaterialPageRoute<T>(settings: settings, builder: builder),
|
||||
home: widget.home,
|
||||
routes: widget.routes,
|
||||
initialRoute: widget.initialRoute,
|
||||
onGenerateRoute: widget.onGenerateRoute,
|
||||
onUnknownRoute: widget.onUnknownRoute,
|
||||
builder: widget.builder,
|
||||
title: widget.title,
|
||||
onGenerateTitle: widget.onGenerateTitle,
|
||||
textStyle: _errorTextStyle,
|
||||
// blue is the primary color of the default theme
|
||||
color: widget.color ?? theme?.primaryColor ?? Colors.blue,
|
||||
locale: widget.locale,
|
||||
localizationsDelegates: _localizationsDelegates,
|
||||
localeResolutionCallback: widget.localeResolutionCallback,
|
||||
localeListResolutionCallback: widget.localeListResolutionCallback,
|
||||
supportedLocales: widget.supportedLocales,
|
||||
showPerformanceOverlay: widget.showPerformanceOverlay,
|
||||
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
|
||||
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
|
||||
showSemanticsDebugger: widget.showSemanticsDebugger,
|
||||
debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner,
|
||||
inspectorSelectButtonBuilder: (BuildContext context, VoidCallback onPressed) {
|
||||
return FloatingActionButton(
|
||||
child: const Icon(Icons.search),
|
||||
onPressed: onPressed,
|
||||
mini: true,
|
||||
);
|
||||
},
|
||||
),
|
||||
MaterialPageRoute<T>(settings: settings, builder: builder),
|
||||
home: widget.home,
|
||||
routes: widget.routes,
|
||||
initialRoute: widget.initialRoute,
|
||||
onGenerateRoute: widget.onGenerateRoute,
|
||||
onUnknownRoute: widget.onUnknownRoute,
|
||||
builder: (BuildContext context, Widget child) {
|
||||
// Use a light theme, dark theme, or fallback theme.
|
||||
ThemeData theme;
|
||||
final ui.Brightness platformBrightness = MediaQuery.platformBrightnessOf(context);
|
||||
if (platformBrightness == ui.Brightness.dark && widget.darkTheme != null) {
|
||||
theme = widget.darkTheme;
|
||||
} else if (widget.theme != null) {
|
||||
theme = widget.theme;
|
||||
} else {
|
||||
theme = ThemeData.fallback();
|
||||
}
|
||||
|
||||
return AnimatedTheme(
|
||||
data: theme,
|
||||
isMaterialAppTheme: true,
|
||||
child: widget.builder != null
|
||||
? Builder(
|
||||
builder: (BuildContext context) {
|
||||
// Why are we surrounding a builder with a builder?
|
||||
//
|
||||
// The widget.builder may contain code that invokes
|
||||
// Theme.of(), which should return the theme we selected
|
||||
// above in AnimatedTheme. However, if we invoke
|
||||
// widget.builder() directly as the child of AnimatedTheme
|
||||
// then there is no Context separating them, and the
|
||||
// widget.builder() will not find the theme. Therefore, we
|
||||
// surround widget.builder with yet another builder so that
|
||||
// a context separates them and Theme.of() correctly
|
||||
// resolves to the theme we passed to AnimatedTheme.
|
||||
return widget.builder(context, child);
|
||||
},
|
||||
)
|
||||
: child,
|
||||
);
|
||||
},
|
||||
title: widget.title,
|
||||
onGenerateTitle: widget.onGenerateTitle,
|
||||
textStyle: _errorTextStyle,
|
||||
// The color property is always pulled from the light theme, even if dark
|
||||
// mode is activated. This was done to simplify the technical details
|
||||
// of switching themes and it was deemed acceptable because this color
|
||||
// property is only used on old Android OSes to color the app bar in
|
||||
// Android's switcher UI.
|
||||
//
|
||||
// blue is the primary color of the default theme
|
||||
color: widget.color ?? widget.theme?.primaryColor ?? Colors.blue,
|
||||
locale: widget.locale,
|
||||
localizationsDelegates: _localizationsDelegates,
|
||||
localeResolutionCallback: widget.localeResolutionCallback,
|
||||
localeListResolutionCallback: widget.localeListResolutionCallback,
|
||||
supportedLocales: widget.supportedLocales,
|
||||
showPerformanceOverlay: widget.showPerformanceOverlay,
|
||||
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
|
||||
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
|
||||
showSemanticsDebugger: widget.showSemanticsDebugger,
|
||||
debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner,
|
||||
inspectorSelectButtonBuilder: (BuildContext context, VoidCallback onPressed) {
|
||||
return FloatingActionButton(
|
||||
child: const Icon(Icons.search),
|
||||
onPressed: onPressed,
|
||||
mini: true,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
assert(() {
|
||||
|
||||
@@ -33,6 +33,7 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
|
||||
window
|
||||
..onMetricsChanged = handleMetricsChanged
|
||||
..onTextScaleFactorChanged = handleTextScaleFactorChanged
|
||||
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
|
||||
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
|
||||
..onSemanticsAction = _handleSemanticsAction;
|
||||
initRenderView();
|
||||
@@ -168,6 +169,38 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
|
||||
@protected
|
||||
void handleTextScaleFactorChanged() { }
|
||||
|
||||
/// {@template on_platform_brightness_change}
|
||||
/// Called when the platform brightness changes.
|
||||
///
|
||||
/// The current platform brightness can be queried either from a Flutter
|
||||
/// binding, or from a [MediaQuery] widget.
|
||||
///
|
||||
/// ## Sample Code
|
||||
///
|
||||
/// Querying [Window.platformBrightness]:
|
||||
///
|
||||
/// ```dart
|
||||
/// final Brightness brightness = WidgetsBinding.instance.window.platformBrightness;
|
||||
/// ```
|
||||
///
|
||||
/// Querying [MediaQuery] directly:
|
||||
///
|
||||
/// ```dart
|
||||
/// final Brightness brightness = MediaQuery.platformBrightnessOf(context);
|
||||
/// ```
|
||||
///
|
||||
/// Querying [MediaQueryData]:
|
||||
///
|
||||
/// ```dart
|
||||
/// final MediaQueryData mediaQueryData = MediaQuery.of(context);
|
||||
/// final Brightness brightness = mediaQueryData.platformBrightness;
|
||||
/// ```
|
||||
///
|
||||
/// See [Window.onPlatformBrightnessChanged].
|
||||
/// {@endtemplate}
|
||||
@protected
|
||||
void handlePlatformBrightnessChanged() { }
|
||||
|
||||
/// Returns a [ViewConfiguration] configured for the [RenderView] based on the
|
||||
/// current environment.
|
||||
///
|
||||
|
||||
@@ -1020,6 +1020,15 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
||||
});
|
||||
}
|
||||
|
||||
// RENDERING
|
||||
@override
|
||||
void didChangePlatformBrightness() {
|
||||
setState(() {
|
||||
// The platformBrightness property of window has changed. We reference
|
||||
// window in our build function, so we need to call setState(), but
|
||||
// we don't need to cache anything locally.
|
||||
});
|
||||
}
|
||||
|
||||
// BUILDER
|
||||
|
||||
|
||||
@@ -213,6 +213,9 @@ abstract class WidgetsBindingObserver {
|
||||
/// boilerplate.
|
||||
void didChangeTextScaleFactor() { }
|
||||
|
||||
/// {@macro on_platform_brightness_change}
|
||||
void didChangePlatformBrightness() { }
|
||||
|
||||
/// Called when the system tells the app that the user's locale has
|
||||
/// changed. For example, if the user changes the system language
|
||||
/// settings.
|
||||
@@ -408,6 +411,13 @@ mixin WidgetsBinding on BindingBase, SchedulerBinding, GestureBinding, RendererB
|
||||
observer.didChangeTextScaleFactor();
|
||||
}
|
||||
|
||||
@override
|
||||
void handlePlatformBrightnessChanged() {
|
||||
super.handlePlatformBrightnessChanged();
|
||||
for (WidgetsBindingObserver observer in _observers)
|
||||
observer.didChangePlatformBrightness();
|
||||
}
|
||||
|
||||
@override
|
||||
void handleAccessibilityFeaturesChanged() {
|
||||
super.handleAccessibilityFeaturesChanged();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' as ui;
|
||||
import 'dart:ui' show Brightness;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
@@ -59,6 +60,7 @@ class MediaQueryData {
|
||||
this.size = Size.zero,
|
||||
this.devicePixelRatio = 1.0,
|
||||
this.textScaleFactor = 1.0,
|
||||
this.platformBrightness = Brightness.light,
|
||||
this.padding = EdgeInsets.zero,
|
||||
this.viewInsets = EdgeInsets.zero,
|
||||
this.alwaysUse24HourFormat = false,
|
||||
@@ -78,6 +80,7 @@ class MediaQueryData {
|
||||
: size = window.physicalSize / window.devicePixelRatio,
|
||||
devicePixelRatio = window.devicePixelRatio,
|
||||
textScaleFactor = window.textScaleFactor,
|
||||
platformBrightness = window.platformBrightness,
|
||||
padding = EdgeInsets.fromWindowPadding(window.padding, window.devicePixelRatio),
|
||||
viewInsets = EdgeInsets.fromWindowPadding(window.viewInsets, window.devicePixelRatio),
|
||||
accessibleNavigation = window.accessibilityFeatures.accessibleNavigation,
|
||||
@@ -110,6 +113,15 @@ class MediaQueryData {
|
||||
/// textScaleFactor defined for a [BuildContext].
|
||||
final double textScaleFactor;
|
||||
|
||||
/// The current brightness mode of the host platform.
|
||||
///
|
||||
/// For example, starting in Android Pie, battery saver mode asks all apps to
|
||||
/// render in a "dark mode".
|
||||
///
|
||||
/// Not all platforms necessarily support a concept of brightness mode. Those
|
||||
/// platforms will report [Brightness.light] in this property.
|
||||
final Brightness platformBrightness;
|
||||
|
||||
/// The parts of the display that are completely obscured by system UI,
|
||||
/// typically by the device's keyboard.
|
||||
///
|
||||
@@ -204,6 +216,7 @@ class MediaQueryData {
|
||||
Size size,
|
||||
double devicePixelRatio,
|
||||
double textScaleFactor,
|
||||
Brightness platformBrightness,
|
||||
EdgeInsets padding,
|
||||
EdgeInsets viewInsets,
|
||||
bool alwaysUse24HourFormat,
|
||||
@@ -216,6 +229,7 @@ class MediaQueryData {
|
||||
size: size ?? this.size,
|
||||
devicePixelRatio: devicePixelRatio ?? this.devicePixelRatio,
|
||||
textScaleFactor: textScaleFactor ?? this.textScaleFactor,
|
||||
platformBrightness: platformBrightness ?? this.platformBrightness,
|
||||
padding: padding ?? this.padding,
|
||||
viewInsets: viewInsets ?? this.viewInsets,
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat ?? this.alwaysUse24HourFormat,
|
||||
@@ -252,6 +266,7 @@ class MediaQueryData {
|
||||
size: size,
|
||||
devicePixelRatio: devicePixelRatio,
|
||||
textScaleFactor: textScaleFactor,
|
||||
platformBrightness: platformBrightness,
|
||||
padding: padding.copyWith(
|
||||
left: removeLeft ? 0.0 : null,
|
||||
top: removeTop ? 0.0 : null,
|
||||
@@ -291,6 +306,7 @@ class MediaQueryData {
|
||||
size: size,
|
||||
devicePixelRatio: devicePixelRatio,
|
||||
textScaleFactor: textScaleFactor,
|
||||
platformBrightness: platformBrightness,
|
||||
padding: padding,
|
||||
viewInsets: viewInsets.copyWith(
|
||||
left: removeLeft ? 0.0 : null,
|
||||
@@ -314,6 +330,7 @@ class MediaQueryData {
|
||||
return typedOther.size == size
|
||||
&& typedOther.devicePixelRatio == devicePixelRatio
|
||||
&& typedOther.textScaleFactor == textScaleFactor
|
||||
&& typedOther.platformBrightness == platformBrightness
|
||||
&& typedOther.padding == padding
|
||||
&& typedOther.viewInsets == viewInsets
|
||||
&& typedOther.alwaysUse24HourFormat == alwaysUse24HourFormat
|
||||
@@ -329,6 +346,7 @@ class MediaQueryData {
|
||||
size,
|
||||
devicePixelRatio,
|
||||
textScaleFactor,
|
||||
platformBrightness,
|
||||
padding,
|
||||
viewInsets,
|
||||
alwaysUse24HourFormat,
|
||||
@@ -345,6 +363,7 @@ class MediaQueryData {
|
||||
'size: $size, '
|
||||
'devicePixelRatio: ${devicePixelRatio.toStringAsFixed(1)}, '
|
||||
'textScaleFactor: ${textScaleFactor.toStringAsFixed(1)}, '
|
||||
'platformBrightness: $platformBrightness, '
|
||||
'padding: $padding, '
|
||||
'viewInsets: $viewInsets, '
|
||||
'alwaysUse24HourFormat: $alwaysUse24HourFormat, '
|
||||
@@ -523,6 +542,15 @@ class MediaQuery extends InheritedWidget {
|
||||
return MediaQuery.of(context, nullOk: true)?.textScaleFactor ?? 1.0;
|
||||
}
|
||||
|
||||
/// Returns platformBrightness for the nearest MediaQuery ancestor or
|
||||
/// [Brightness.light], if no such ancestor exists.
|
||||
///
|
||||
/// Use of this method will cause the given [context] to rebuild any time that
|
||||
/// any property of the ancestor [MediaQuery] changes.
|
||||
static Brightness platformBrightnessOf(BuildContext context) {
|
||||
return MediaQuery.of(context, nullOk: true)?.platformBrightness ?? Brightness.light;
|
||||
}
|
||||
|
||||
/// Returns the boldText accessibility setting for the nearest MediaQuery
|
||||
/// ancestor, or false if no such ancestor exists.
|
||||
static bool boldTextOverride(BuildContext context) {
|
||||
|
||||
@@ -435,4 +435,165 @@ void main() {
|
||||
// Default Cupertino US "select all" text.
|
||||
expect(find.text('Select All'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('MaterialApp uses regular theme when platformBrightness is light', (WidgetTester tester) async {
|
||||
// Mock the Window to explicitly report a light platformBrightness.
|
||||
final TestWidgetsFlutterBinding binding = tester.binding;
|
||||
binding.window.platformBrightnessTestValue = Brightness.light;
|
||||
|
||||
ThemeData appliedTheme;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
brightness: Brightness.light
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
appliedTheme = Theme.of(context);
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(appliedTheme.brightness, Brightness.light);
|
||||
});
|
||||
|
||||
testWidgets('MaterialApp uses light theme when platformBrightness is dark but no dark theme is provided', (WidgetTester tester) async {
|
||||
// Mock the Window to explicitly report a dark platformBrightness.
|
||||
final TestWidgetsFlutterBinding binding = tester.binding;
|
||||
binding.window.platformBrightnessTestValue = Brightness.dark;
|
||||
|
||||
ThemeData appliedTheme;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
brightness: Brightness.light
|
||||
),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
appliedTheme = Theme.of(context);
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(appliedTheme.brightness, Brightness.light);
|
||||
});
|
||||
|
||||
testWidgets('MaterialApp uses fallback light theme when platformBrightness is dark but no theme is provided at all', (WidgetTester tester) async {
|
||||
// Mock the Window to explicitly report a dark platformBrightness.
|
||||
final TestWidgetsFlutterBinding binding = tester.binding;
|
||||
binding.window.platformBrightnessTestValue = Brightness.dark;
|
||||
|
||||
ThemeData appliedTheme;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
appliedTheme = Theme.of(context);
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(appliedTheme.brightness, Brightness.light);
|
||||
});
|
||||
|
||||
testWidgets('MaterialApp uses fallback light theme when platformBrightness is light and a dark theme is provided', (WidgetTester tester) async {
|
||||
// Mock the Window to explicitly report a dark platformBrightness.
|
||||
final TestWidgetsFlutterBinding binding = tester.binding;
|
||||
binding.window.platformBrightnessTestValue = Brightness.light;
|
||||
|
||||
ThemeData appliedTheme;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
darkTheme: ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
appliedTheme = Theme.of(context);
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(appliedTheme.brightness, Brightness.light);
|
||||
});
|
||||
|
||||
testWidgets('MaterialApp uses dark theme when platformBrightness is dark', (WidgetTester tester) async {
|
||||
// Mock the Window to explicitly report a dark platformBrightness.
|
||||
final TestWidgetsFlutterBinding binding = tester.binding;
|
||||
binding.window.platformBrightnessTestValue = Brightness.dark;
|
||||
|
||||
ThemeData appliedTheme;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
brightness: Brightness.light
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
appliedTheme = Theme.of(context);
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(appliedTheme.brightness, Brightness.dark);
|
||||
});
|
||||
|
||||
testWidgets('MaterialApp switches themes when the Window platformBrightness changes.', (WidgetTester tester) async {
|
||||
// Mock the Window to explicitly report a light platformBrightness.
|
||||
final TestWidgetsFlutterBinding binding = tester.binding;
|
||||
binding.window.platformBrightnessTestValue = Brightness.light;
|
||||
|
||||
ThemeData themeBeforeBrightnessChange;
|
||||
ThemeData themeAfterBrightnessChange;
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
brightness: Brightness.light
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
home: Builder(
|
||||
builder: (BuildContext context) {
|
||||
if (themeBeforeBrightnessChange == null) {
|
||||
themeBeforeBrightnessChange = Theme.of(context);
|
||||
} else {
|
||||
themeAfterBrightnessChange = Theme.of(context);
|
||||
}
|
||||
return const SizedBox();
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Switch the platformBrightness from light to dark and pump the widget tree
|
||||
// to process changes.
|
||||
binding.window.platformBrightnessTestValue = Brightness.dark;
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(themeBeforeBrightnessChange.brightness, Brightness.light);
|
||||
expect(themeAfterBrightnessChange.brightness, Brightness.dark);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:ui' show Brightness;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
@@ -45,6 +46,7 @@ void main() {
|
||||
expect(data.invertColors, false);
|
||||
expect(data.disableAnimations, false);
|
||||
expect(data.boldText, false);
|
||||
expect(data.platformBrightness, Brightness.light);
|
||||
});
|
||||
|
||||
testWidgets('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async {
|
||||
@@ -60,6 +62,7 @@ void main() {
|
||||
expect(copied.invertColors, data.invertColors);
|
||||
expect(copied.disableAnimations, data.disableAnimations);
|
||||
expect(copied.boldText, data.boldText);
|
||||
expect(copied.platformBrightness, data.platformBrightness);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.copyWith copies specified values', (WidgetTester tester) async {
|
||||
@@ -75,6 +78,7 @@ void main() {
|
||||
invertColors: true,
|
||||
disableAnimations: true,
|
||||
boldText: true,
|
||||
platformBrightness: Brightness.dark,
|
||||
);
|
||||
expect(copied.size, const Size(3.14, 2.72));
|
||||
expect(copied.devicePixelRatio, 1.41);
|
||||
@@ -86,6 +90,7 @@ void main() {
|
||||
expect(copied.invertColors, true);
|
||||
expect(copied.disableAnimations, true);
|
||||
expect(copied.boldText, true);
|
||||
expect(copied.platformBrightness, Brightness.dark);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.removePadding removes specified padding', (WidgetTester tester) async {
|
||||
@@ -223,6 +228,33 @@ void main() {
|
||||
expect(insideTextScaleFactor, 4.0);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.platformBrightnessOf', (WidgetTester tester) async {
|
||||
Brightness outsideBrightness;
|
||||
Brightness insideBrightness;
|
||||
|
||||
await tester.pumpWidget(
|
||||
Builder(
|
||||
builder: (BuildContext context) {
|
||||
outsideBrightness = MediaQuery.platformBrightnessOf(context);
|
||||
return MediaQuery(
|
||||
data: const MediaQueryData(
|
||||
platformBrightness: Brightness.dark,
|
||||
),
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
insideBrightness = MediaQuery.platformBrightnessOf(context);
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
expect(outsideBrightness, Brightness.light);
|
||||
expect(insideBrightness, Brightness.dark);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.boldTextOverride', (WidgetTester tester) async {
|
||||
bool outsideBoldTextOverride;
|
||||
bool insideBoldTextOverride;
|
||||
|
||||
@@ -59,10 +59,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real device pixel ratio and reports the given [devicePixelRatio] instead.
|
||||
set devicePixelRatioTestValue(double devicePixelRatio) {
|
||||
_devicePixelRatio = devicePixelRatio;
|
||||
onMetricsChanged();
|
||||
}
|
||||
/// Deletes any existing test device pixel ratio and returns to using the real device pixel ratio.
|
||||
void clearDevicePixelRatioTestValue() {
|
||||
_devicePixelRatio = null;
|
||||
onMetricsChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -71,10 +73,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real physical size and reports the given [physicalSizeTestValue] instead.
|
||||
set physicalSizeTestValue (Size physicalSizeTestValue) {
|
||||
_physicalSizeTestValue = physicalSizeTestValue;
|
||||
onMetricsChanged();
|
||||
}
|
||||
/// Deletes any existing test physical size and returns to using the real physical size.
|
||||
void clearPhysicalSizeTestValue() {
|
||||
_physicalSizeTestValue = null;
|
||||
onMetricsChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -83,10 +87,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real view insets and reports the given [viewInsetsTestValue] instead.
|
||||
set viewInsetsTestValue(WindowPadding viewInsetsTestValue) {
|
||||
_viewInsetsTestValue = viewInsetsTestValue;
|
||||
onMetricsChanged();
|
||||
}
|
||||
/// Deletes any existing test view insets and returns to using the real view insets.
|
||||
void clearViewInsetsTestValue() {
|
||||
_viewInsetsTestValue = null;
|
||||
onMetricsChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -95,10 +101,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real padding and reports the given [paddingTestValue] instead.
|
||||
set paddingTestValue(WindowPadding paddingTestValue) {
|
||||
_paddingTestValue = paddingTestValue;
|
||||
onMetricsChanged();
|
||||
}
|
||||
/// Deletes any existing test padding and returns to using the real padding.
|
||||
void clearPaddingTestValue() {
|
||||
_paddingTestValue = null;
|
||||
onMetricsChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -114,10 +122,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real locale and reports the given [localeTestValue] instead.
|
||||
set localeTestValue(Locale localeTestValue) {
|
||||
_localeTestValue = localeTestValue;
|
||||
onLocaleChanged();
|
||||
}
|
||||
/// Deletes any existing test locale and returns to using the real locale.
|
||||
void clearLocaleTestValue() {
|
||||
_localeTestValue = null;
|
||||
onLocaleChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -126,10 +136,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real locales and reports the given [localesTestValue] instead.
|
||||
set localesTestValue(List<Locale> localesTestValue) {
|
||||
_localesTestValue = localesTestValue;
|
||||
onLocaleChanged();
|
||||
}
|
||||
/// Deletes any existing test locales and returns to using the real locales.
|
||||
void clearLocalesTestValue() {
|
||||
_localesTestValue = null;
|
||||
onLocaleChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -145,10 +157,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real text scale factor and reports the given [textScaleFactorTestValue] instead.
|
||||
set textScaleFactorTestValue(double textScaleFactorTestValue) {
|
||||
_textScaleFactorTestValue = textScaleFactorTestValue;
|
||||
onTextScaleFactorChanged();
|
||||
}
|
||||
/// Deletes any existing test text scale factor and returns to using the real text scale factor.
|
||||
void clearTextScaleFactorTestValue() {
|
||||
_textScaleFactorTestValue = null;
|
||||
onTextScaleFactorChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -158,15 +172,17 @@ class TestWindow implements Window {
|
||||
VoidCallback get onPlatformBrightnessChanged => _window.onPlatformBrightnessChanged;
|
||||
@override
|
||||
set onPlatformBrightnessChanged(VoidCallback callback) {
|
||||
_window.onPlatformBrightnessChanged =callback;
|
||||
_window.onPlatformBrightnessChanged = callback;
|
||||
}
|
||||
/// Hides the real text scale factor and reports the given [platformBrightnessTestValue] instead.
|
||||
set platformBrightnessTestValue(Brightness platformBrightnessTestValue) {
|
||||
_platformBrightnessTestValue = platformBrightnessTestValue;
|
||||
onPlatformBrightnessChanged();
|
||||
}
|
||||
/// Deletes any existing test platform brightness and returns to using the real platform brightness.
|
||||
void clearPlatformBrightnessTestValue() {
|
||||
_platformBrightnessTestValue = null;
|
||||
onPlatformBrightnessChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -237,10 +253,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real semantics enabled and reports the given [semanticsEnabledTestValue] instead.
|
||||
set semanticsEnabledTestValue(bool semanticsEnabledTestValue) {
|
||||
_semanticsEnabledTestValue = semanticsEnabledTestValue;
|
||||
onSemanticsEnabledChanged();
|
||||
}
|
||||
/// Deletes any existing test semantics enabled and returns to using the real semantics enabled.
|
||||
void clearSemanticsEnabledTestValue() {
|
||||
_semanticsEnabledTestValue = null;
|
||||
onSemanticsEnabledChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -263,10 +281,12 @@ class TestWindow implements Window {
|
||||
/// Hides the real accessibility features and reports the given [accessibilityFeaturesTestValue] instead.
|
||||
set accessibilityFeaturesTestValue(AccessibilityFeatures accessibilityFeaturesTestValue) {
|
||||
_accessibilityFeaturesTestValue = accessibilityFeaturesTestValue;
|
||||
onAccessibilityFeaturesChanged();
|
||||
}
|
||||
/// Deletes any existing test accessibility features and returns to using the real accessibility features.
|
||||
void clearAccessibilityFeaturesTestValue() {
|
||||
_accessibilityFeaturesTestValue = null;
|
||||
onAccessibilityFeaturesChanged();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -136,20 +136,6 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('TestWindow can fake semantics enabled', (WidgetTester tester) async {
|
||||
verifyThatTestWindowCanFakeProperty<bool>(
|
||||
tester: tester,
|
||||
realValue: ui.window.semanticsEnabled,
|
||||
fakeValue: !ui.window.semanticsEnabled,
|
||||
propertyRetriever: () {
|
||||
return WidgetsBinding.instance.window.semanticsEnabled;
|
||||
},
|
||||
propertyFaker: (TestWidgetsFlutterBinding binding, bool fakeValue) {
|
||||
binding.window.semanticsEnabledTestValue = fakeValue;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('TestWindow can fake accessibility features', (WidgetTester tester) async {
|
||||
verifyThatTestWindowCanFakeProperty<AccessibilityFeatures>(
|
||||
tester: tester,
|
||||
|
||||
Reference in New Issue
Block a user