Unverified Commit a13fdbcf authored by Matt Carroll's avatar Matt Carroll Committed by GitHub

Implemented Dark Mode for Android (#25525) (#26605)

parent 0aee2f50
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment