Add AccessibilityFeatures to media query and fix Snackbar a11y behavior (#19336)
This commit is contained in:
@@ -1162,12 +1162,18 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
|
||||
assert(reason != null);
|
||||
if (_snackBars.isEmpty || _snackBarController.status == AnimationStatus.dismissed)
|
||||
return;
|
||||
final MediaQueryData mediaQuery = MediaQuery.of(context);
|
||||
final Completer<SnackBarClosedReason> completer = _snackBars.first._completer;
|
||||
_snackBarController.reverse().then<void>((Null _) {
|
||||
assert(mounted);
|
||||
if (!completer.isCompleted)
|
||||
completer.complete(reason);
|
||||
});
|
||||
if (mediaQuery.accessibleNavigation) {
|
||||
_snackBarController.value = 0.0;
|
||||
completer.complete(reason);
|
||||
} else {
|
||||
_snackBarController.reverse().then<void>((Null _) {
|
||||
assert(mounted);
|
||||
if (!completer.isCompleted)
|
||||
completer.complete(reason);
|
||||
});
|
||||
}
|
||||
_snackBarTimer?.cancel();
|
||||
_snackBarTimer = null;
|
||||
}
|
||||
@@ -1480,12 +1486,19 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
|
||||
if (_snackBars.isNotEmpty) {
|
||||
final ModalRoute<dynamic> route = ModalRoute.of(context);
|
||||
if (route == null || route.isCurrent) {
|
||||
if (_snackBarController.isCompleted && _snackBarTimer == null)
|
||||
_snackBarTimer = new Timer(_snackBars.first._widget.duration, () {
|
||||
if (_snackBarController.isCompleted && _snackBarTimer == null) {
|
||||
final SnackBar snackBar = _snackBars.first._widget;
|
||||
_snackBarTimer = new Timer.periodic(snackBar.duration, (Timer timer) {
|
||||
assert(_snackBarController.status == AnimationStatus.forward ||
|
||||
_snackBarController.status == AnimationStatus.completed);
|
||||
_snackBarController.status == AnimationStatus.completed);
|
||||
// Look up MediaQuery again in case the setting changed.
|
||||
final MediaQueryData mediaQuery = MediaQuery.of(context);
|
||||
if (mediaQuery.accessibleNavigation && snackBar.action != null)
|
||||
return;
|
||||
timer.cancel();
|
||||
hideCurrentSnackBar(reason: SnackBarClosedReason.timeout);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_snackBarTimer?.cancel();
|
||||
_snackBarTimer = null;
|
||||
|
||||
@@ -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 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'button_theme.dart';
|
||||
@@ -46,6 +47,9 @@ enum SnackBarClosedReason {
|
||||
/// The snack bar was closed after the user tapped a [SnackBarAction].
|
||||
action,
|
||||
|
||||
/// The snack bar was closed through a [SemanticAction.dismiss].
|
||||
dismiss,
|
||||
|
||||
/// The snack bar was closed by a user's swipe.
|
||||
swipe,
|
||||
|
||||
@@ -126,6 +130,9 @@ class _SnackBarActionState extends State<SnackBarAction> {
|
||||
///
|
||||
/// To control how long the [SnackBar] remains visible, specify a [duration].
|
||||
///
|
||||
/// A SnackBar with an action will not time out when TalkBack or VoiceOver are
|
||||
/// enabled. This is controlled by [AccessibilityFeatures.accessibleNavigation].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Scaffold.of], to obtain the current [ScaffoldState], which manages the
|
||||
@@ -183,6 +190,7 @@ class SnackBar extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final MediaQueryData mediaQueryData = MediaQuery.of(context);
|
||||
assert(animation != null);
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ThemeData darkTheme = new ThemeData(
|
||||
@@ -213,8 +221,41 @@ class SnackBar extends StatelessWidget {
|
||||
}
|
||||
final CurvedAnimation heightAnimation = new CurvedAnimation(parent: animation, curve: _snackBarHeightCurve);
|
||||
final CurvedAnimation fadeAnimation = new CurvedAnimation(parent: animation, curve: _snackBarFadeCurve, reverseCurve: const Threshold(0.0));
|
||||
Widget snackbar = new SafeArea(
|
||||
top: false,
|
||||
child: new Row(
|
||||
children: children,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
),
|
||||
);
|
||||
snackbar = new Semantics(
|
||||
container: true,
|
||||
liveRegion: true,
|
||||
onDismiss: () {
|
||||
Scaffold.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.dismiss);
|
||||
},
|
||||
child: new Dismissible(
|
||||
key: const Key('dismissible'),
|
||||
direction: DismissDirection.down,
|
||||
resizeDuration: null,
|
||||
onDismissed: (DismissDirection direction) {
|
||||
Scaffold.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.swipe);
|
||||
},
|
||||
child: new Material(
|
||||
elevation: 6.0,
|
||||
color: backgroundColor ?? _kSnackBackground,
|
||||
child: new Theme(
|
||||
data: darkTheme,
|
||||
child: mediaQueryData.accessibleNavigation ? snackbar : new FadeTransition(
|
||||
opacity: fadeAnimation,
|
||||
child: snackbar,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
return new ClipRect(
|
||||
child: new AnimatedBuilder(
|
||||
child: mediaQueryData.accessibleNavigation ? snackbar : new AnimatedBuilder(
|
||||
animation: heightAnimation,
|
||||
builder: (BuildContext context, Widget child) {
|
||||
return new Align(
|
||||
@@ -223,38 +264,7 @@ class SnackBar extends StatelessWidget {
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: new Semantics(
|
||||
liveRegion: true,
|
||||
container: true,
|
||||
onDismiss: () {
|
||||
Scaffold.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.swipe);
|
||||
},
|
||||
child: new Dismissible(
|
||||
key: const Key('dismissible'),
|
||||
direction: DismissDirection.down,
|
||||
resizeDuration: null,
|
||||
onDismissed: (DismissDirection direction) {
|
||||
Scaffold.of(context).removeCurrentSnackBar(reason: SnackBarClosedReason.swipe);
|
||||
},
|
||||
child: new Material(
|
||||
elevation: 6.0,
|
||||
color: backgroundColor ?? _kSnackBackground,
|
||||
child: new Theme(
|
||||
data: darkTheme,
|
||||
child: new FadeTransition(
|
||||
opacity: fadeAnimation,
|
||||
child: new SafeArea(
|
||||
top: false,
|
||||
child: new Row(
|
||||
children: children,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: snackbar,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -153,6 +153,12 @@ abstract class RendererBinding extends BindingBase with ServicesBinding, Schedul
|
||||
@protected
|
||||
void handleTextScaleFactorChanged() { }
|
||||
|
||||
/// Called when the platform accessibility features change.
|
||||
///
|
||||
/// See [Window.onAccessibilityFeaturesChanged].
|
||||
@protected
|
||||
void handleAccessibilityFeaturesChanged() {}
|
||||
|
||||
/// Returns a [ViewConfiguration] configured for the [RenderView] based on the
|
||||
/// current environment.
|
||||
///
|
||||
|
||||
@@ -527,6 +527,16 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
||||
yield DefaultWidgetsLocalizations.delegate;
|
||||
}
|
||||
|
||||
// ACCESSIBILITY
|
||||
|
||||
@override
|
||||
void didChangeAccessibilityFeatures() {
|
||||
setState(() {
|
||||
// The properties of ui.window have changed. We use them in our build
|
||||
// function, so we need setState(), but we don't cache anything locally.
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// METRICS
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:developer' as developer;
|
||||
import 'dart:ui' show AppLifecycleState, Locale;
|
||||
import 'dart:ui' show AppLifecycleState, Locale, AccessibilityFeatures;
|
||||
import 'dart:ui' as ui show window;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
@@ -229,6 +229,12 @@ abstract class WidgetsBindingObserver {
|
||||
/// This method exposes the `memoryPressure` notification from
|
||||
/// [SystemChannels.system].
|
||||
void didHaveMemoryPressure() { }
|
||||
|
||||
/// Called when the system changes the set of currently active accessibility
|
||||
/// features.
|
||||
///
|
||||
/// This method exposes notifications from [Window.onAccessibilityFeaturesChanged].
|
||||
void didChangeAccessibilityFeatures() {}
|
||||
}
|
||||
|
||||
/// The glue between the widgets layer and the Flutter engine.
|
||||
@@ -243,6 +249,7 @@ abstract class WidgetsBinding extends BindingBase with SchedulerBinding, Gesture
|
||||
_instance = this;
|
||||
buildOwner.onBuildScheduled = _handleBuildScheduled;
|
||||
ui.window.onLocaleChanged = handleLocaleChanged;
|
||||
ui.window.onAccessibilityFeaturesChanged = handleAccessibilityFeaturesChanged;
|
||||
SystemChannels.navigation.setMethodCallHandler(_handleNavigationInvocation);
|
||||
SystemChannels.system.setMessageHandler(_handleSystemMessage);
|
||||
}
|
||||
@@ -368,6 +375,13 @@ abstract class WidgetsBinding extends BindingBase with SchedulerBinding, Gesture
|
||||
observer.didChangeTextScaleFactor();
|
||||
}
|
||||
|
||||
@override
|
||||
void handleAccessibilityFeaturesChanged() {
|
||||
super.handleAccessibilityFeaturesChanged();
|
||||
for (WidgetsBindingObserver observer in _observers)
|
||||
observer.didChangeAccessibilityFeatures();
|
||||
}
|
||||
|
||||
/// Called when the system locale changes.
|
||||
///
|
||||
/// Calls [dispatchLocaleChanged] to notify the binding observers.
|
||||
@@ -392,6 +406,19 @@ abstract class WidgetsBinding extends BindingBase with SchedulerBinding, Gesture
|
||||
observer.didChangeLocale(locale);
|
||||
}
|
||||
|
||||
/// Notify all the observers that the active set of [AccessibilityFeatures]
|
||||
/// has changed (using [WidgetsBindingObserver.didChangeAccessibilityFeatures]),
|
||||
/// giving them the `features` argument.
|
||||
///
|
||||
/// This is called by [handleAccessibilityFeaturesChanged] when the
|
||||
/// [Window.onAccessibilityFeaturesChanged] notification is recieved.
|
||||
@protected
|
||||
@mustCallSuper
|
||||
void dispatchAccessibilityFeaturesChanged() {
|
||||
for (WidgetsBindingObserver observer in _observers)
|
||||
observer.didChangeAccessibilityFeatures();
|
||||
}
|
||||
|
||||
/// Called when the system pops the current route.
|
||||
///
|
||||
/// This first notifies the binding observers (using
|
||||
|
||||
@@ -43,6 +43,9 @@ class MediaQueryData {
|
||||
this.padding = EdgeInsets.zero,
|
||||
this.viewInsets = EdgeInsets.zero,
|
||||
this.alwaysUse24HourFormat = false,
|
||||
this.accessibleNavigation = false,
|
||||
this.invertColors = false,
|
||||
this.disableAnimations = false,
|
||||
});
|
||||
|
||||
/// Creates data for a media query based on the given window.
|
||||
@@ -57,6 +60,9 @@ class MediaQueryData {
|
||||
textScaleFactor = window.textScaleFactor,
|
||||
padding = new EdgeInsets.fromWindowPadding(window.padding, window.devicePixelRatio),
|
||||
viewInsets = new EdgeInsets.fromWindowPadding(window.viewInsets, window.devicePixelRatio),
|
||||
accessibleNavigation = window.accessibilityFeatures.accessibleNavigation,
|
||||
invertColors = window.accessibilityFeatures.accessibleNavigation,
|
||||
disableAnimations = window.accessibilityFeatures.disableAnimations,
|
||||
alwaysUse24HourFormat = window.alwaysUse24HourFormat;
|
||||
|
||||
/// The size of the media in logical pixel (e.g, the size of the screen).
|
||||
@@ -120,6 +126,33 @@ class MediaQueryData {
|
||||
/// formatting.
|
||||
final bool alwaysUse24HourFormat;
|
||||
|
||||
/// Whether the user is using an accessibility service like TalkBack or
|
||||
/// VoiceOver to interact with the application.
|
||||
///
|
||||
/// When this setting is true, features such as timeouts should be disabled or
|
||||
/// have minimum durations increased.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Window.AccessibilityFeatures], where the setting originates.
|
||||
final bool accessibleNavigation;
|
||||
|
||||
/// Whether the device is inverting the colors of the platform.
|
||||
///
|
||||
/// This flag is currently only updated on iOS devices.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Window.AccessibilityFeatures], where the setting originates.
|
||||
final bool invertColors;
|
||||
|
||||
/// Whether the platform is requesting that animations be disabled or reduced
|
||||
/// as much as possible.
|
||||
///
|
||||
/// * [Window.AccessibilityFeatures], where the setting originates.
|
||||
///
|
||||
final bool disableAnimations;
|
||||
|
||||
/// The orientation of the media (e.g., whether the device is in landscape or portrait mode).
|
||||
Orientation get orientation {
|
||||
return size.width > size.height ? Orientation.landscape : Orientation.portrait;
|
||||
@@ -134,6 +167,9 @@ class MediaQueryData {
|
||||
EdgeInsets padding,
|
||||
EdgeInsets viewInsets,
|
||||
bool alwaysUse24HourFormat,
|
||||
bool disableAnimations,
|
||||
bool invertColors,
|
||||
bool accessibleNavigation,
|
||||
}) {
|
||||
return new MediaQueryData(
|
||||
size: size ?? this.size,
|
||||
@@ -142,6 +178,9 @@ class MediaQueryData {
|
||||
padding: padding ?? this.padding,
|
||||
viewInsets: viewInsets ?? this.viewInsets,
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat ?? this.alwaysUse24HourFormat,
|
||||
invertColors: invertColors ?? this.invertColors,
|
||||
disableAnimations: disableAnimations ?? this.disableAnimations,
|
||||
accessibleNavigation: accessibleNavigation ?? this.accessibleNavigation,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -179,6 +218,9 @@ class MediaQueryData {
|
||||
),
|
||||
viewInsets: viewInsets,
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat,
|
||||
disableAnimations: disableAnimations,
|
||||
invertColors: invertColors,
|
||||
accessibleNavigation: accessibleNavigation,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -214,6 +256,9 @@ class MediaQueryData {
|
||||
bottom: removeBottom ? 0.0 : null,
|
||||
),
|
||||
alwaysUse24HourFormat: alwaysUse24HourFormat,
|
||||
disableAnimations: disableAnimations,
|
||||
invertColors: invertColors,
|
||||
accessibleNavigation: accessibleNavigation,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -227,11 +272,26 @@ class MediaQueryData {
|
||||
&& typedOther.textScaleFactor == textScaleFactor
|
||||
&& typedOther.padding == padding
|
||||
&& typedOther.viewInsets == viewInsets
|
||||
&& typedOther.alwaysUse24HourFormat == alwaysUse24HourFormat;
|
||||
&& typedOther.alwaysUse24HourFormat == alwaysUse24HourFormat
|
||||
&& typedOther.disableAnimations == disableAnimations
|
||||
&& typedOther.invertColors == invertColors
|
||||
&& typedOther.accessibleNavigation == accessibleNavigation;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => hashValues(size, devicePixelRatio, textScaleFactor, padding, viewInsets, alwaysUse24HourFormat);
|
||||
int get hashCode {
|
||||
return hashValues(
|
||||
size,
|
||||
devicePixelRatio,
|
||||
textScaleFactor,
|
||||
padding,
|
||||
viewInsets,
|
||||
alwaysUse24HourFormat,
|
||||
disableAnimations,
|
||||
invertColors,
|
||||
accessibleNavigation,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
@@ -241,7 +301,10 @@ class MediaQueryData {
|
||||
'textScaleFactor: $textScaleFactor, '
|
||||
'padding: $padding, '
|
||||
'viewInsets: $viewInsets, '
|
||||
'alwaysUse24HourFormat: $alwaysUse24HourFormat'
|
||||
'alwaysUse24HourFormat: $alwaysUse24HourFormat, '
|
||||
'accessibleNavigation: $accessibleNavigation'
|
||||
'disableAnimations: $disableAnimations'
|
||||
'invertColors: $invertColors'
|
||||
')';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,6 +482,90 @@ void main() {
|
||||
expect(closedReason, equals(SnackBarClosedReason.timeout));
|
||||
});
|
||||
|
||||
testWidgets('accessible navigation behavior with action', (WidgetTester tester) async {
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
await tester.pumpWidget(new MaterialApp(
|
||||
home: new MediaQuery(
|
||||
data: const MediaQueryData(accessibleNavigation: true),
|
||||
child: Scaffold(
|
||||
key: scaffoldKey,
|
||||
body: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
return new GestureDetector(
|
||||
onTap: () {
|
||||
Scaffold.of(context).showSnackBar(new SnackBar(
|
||||
content: const Text('snack'),
|
||||
duration: const Duration(seconds: 1),
|
||||
action: new SnackBarAction(
|
||||
label: 'ACTION',
|
||||
onPressed: () {}
|
||||
),
|
||||
));
|
||||
},
|
||||
child: const Text('X')
|
||||
);
|
||||
},
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pump();
|
||||
// Find action immediately
|
||||
expect(find.text('ACTION'), findsOneWidget);
|
||||
// Snackbar doesn't close
|
||||
await tester.pump(const Duration(seconds: 10));
|
||||
expect(find.text('ACTION'), findsOneWidget);
|
||||
await tester.tap(find.text('ACTION'));
|
||||
await tester.pump();
|
||||
// Snackbar closes immediately
|
||||
expect(find.text('ACTION'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('contributes dismiss semantics', (WidgetTester tester) async {
|
||||
final SemanticsHandle handle = tester.ensureSemantics();
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
|
||||
|
||||
await tester.pumpWidget(new MaterialApp(
|
||||
home: new MediaQuery(
|
||||
data: const MediaQueryData(accessibleNavigation: true),
|
||||
child: Scaffold(
|
||||
key: scaffoldKey,
|
||||
body: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
return new GestureDetector(
|
||||
onTap: () {
|
||||
Scaffold.of(context).showSnackBar(new SnackBar(
|
||||
content: const Text('snack'),
|
||||
duration: const Duration(seconds: 1),
|
||||
action: new SnackBarAction(
|
||||
label: 'ACTION',
|
||||
onPressed: () {}
|
||||
),
|
||||
));
|
||||
},
|
||||
child: const Text('X')
|
||||
);
|
||||
},
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(tester.getSemanticsData(find.text('snack')), matchesSemanticsData(
|
||||
isLiveRegion: true,
|
||||
hasDismissAction: true,
|
||||
hasScrollDownAction: true,
|
||||
hasScrollUpAction: true,
|
||||
label: 'snack',
|
||||
textDirection: TextDirection.ltr,
|
||||
));
|
||||
handle.dispose();
|
||||
});
|
||||
|
||||
testWidgets('SnackBar default display duration test', (WidgetTester tester) async {
|
||||
const String helloSnackBar = 'Hello SnackBar';
|
||||
const Key tapTarget = Key('tap-target');
|
||||
@@ -530,4 +614,52 @@ void main() {
|
||||
expect(find.text(helloSnackBar), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('SnackBar handles updates to accessibleNavigation', (WidgetTester tester) async {
|
||||
Future<void> boilerplate({bool accessibleNavigation}) {
|
||||
return tester.pumpWidget(new MaterialApp(
|
||||
home: new MediaQuery(
|
||||
data: new MediaQueryData(accessibleNavigation: accessibleNavigation),
|
||||
child: new Scaffold(
|
||||
body: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
return new GestureDetector(
|
||||
onTap: () {
|
||||
Scaffold.of(context).showSnackBar(new SnackBar(
|
||||
content: const Text('test'),
|
||||
action: new SnackBarAction(label: 'foo', onPressed: () {}),
|
||||
));
|
||||
},
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: const Text('X'),
|
||||
);
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
await boilerplate(accessibleNavigation: false);
|
||||
expect(find.text('test'), findsNothing);
|
||||
await tester.tap(find.text('X'));
|
||||
await tester.pump(); // schedule animation
|
||||
expect(find.text('test'), findsOneWidget);
|
||||
await tester.pump(); // begin animation
|
||||
await tester.pump(const Duration(milliseconds: 4750)); // 4.75s
|
||||
expect(find.text('test'), findsOneWidget);
|
||||
|
||||
// Enabled accessible navigation
|
||||
await boilerplate(accessibleNavigation: true);
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 4000)); // 8.75s
|
||||
await tester.pump();
|
||||
expect(find.text('test'), findsOneWidget);
|
||||
|
||||
// disable accessible navigation
|
||||
await boilerplate(accessibleNavigation: false);
|
||||
await tester.pumpAndSettle(const Duration(milliseconds: 5750));
|
||||
|
||||
expect(find.text('test'), findsNothing);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ void main() {
|
||||
expect(data, hasOneLineDescription);
|
||||
expect(data.hashCode, equals(data.copyWith().hashCode));
|
||||
expect(data.size, equals(ui.window.physicalSize / ui.window.devicePixelRatio));
|
||||
expect(data.accessibleNavigation, false);
|
||||
expect(data.invertColors, false);
|
||||
expect(data.disableAnimations, false);
|
||||
});
|
||||
|
||||
testWidgets('MediaQueryData.copyWith defaults to source', (WidgetTester tester) async {
|
||||
@@ -54,6 +57,9 @@ void main() {
|
||||
expect(copied.padding, data.padding);
|
||||
expect(copied.viewInsets, data.viewInsets);
|
||||
expect(copied.alwaysUse24HourFormat, data.alwaysUse24HourFormat);
|
||||
expect(copied.accessibleNavigation, data.accessibleNavigation);
|
||||
expect(copied.invertColors, data.invertColors);
|
||||
expect(copied.disableAnimations, data.disableAnimations);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.copyWith copies specified values', (WidgetTester tester) async {
|
||||
@@ -65,6 +71,9 @@ void main() {
|
||||
padding: const EdgeInsets.all(9.10938),
|
||||
viewInsets: const EdgeInsets.all(1.67262),
|
||||
alwaysUse24HourFormat: true,
|
||||
accessibleNavigation: true,
|
||||
invertColors: true,
|
||||
disableAnimations: true,
|
||||
);
|
||||
expect(copied.size, const Size(3.14, 2.72));
|
||||
expect(copied.devicePixelRatio, 1.41);
|
||||
@@ -72,6 +81,9 @@ void main() {
|
||||
expect(copied.padding, const EdgeInsets.all(9.10938));
|
||||
expect(copied.viewInsets, const EdgeInsets.all(1.67262));
|
||||
expect(copied.alwaysUse24HourFormat, true);
|
||||
expect(copied.accessibleNavigation, true);
|
||||
expect(copied.invertColors, true);
|
||||
expect(copied.disableAnimations, true);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.removePadding removes specified padding', (WidgetTester tester) async {
|
||||
@@ -91,6 +103,9 @@ void main() {
|
||||
padding: padding,
|
||||
viewInsets: viewInsets,
|
||||
alwaysUse24HourFormat: true,
|
||||
accessibleNavigation: true,
|
||||
invertColors: true,
|
||||
disableAnimations: true,
|
||||
),
|
||||
child: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
@@ -118,6 +133,9 @@ void main() {
|
||||
expect(unpadded.padding, EdgeInsets.zero);
|
||||
expect(unpadded.viewInsets, viewInsets);
|
||||
expect(unpadded.alwaysUse24HourFormat, true);
|
||||
expect(unpadded.accessibleNavigation, true);
|
||||
expect(unpadded.invertColors, true);
|
||||
expect(unpadded.disableAnimations, true);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.removeViewInsets removes specified viewInsets', (WidgetTester tester) async {
|
||||
@@ -137,6 +155,9 @@ void main() {
|
||||
padding: padding,
|
||||
viewInsets: viewInsets,
|
||||
alwaysUse24HourFormat: true,
|
||||
accessibleNavigation: true,
|
||||
invertColors: true,
|
||||
disableAnimations: true,
|
||||
),
|
||||
child: new Builder(
|
||||
builder: (BuildContext context) {
|
||||
@@ -164,6 +185,9 @@ void main() {
|
||||
expect(unpadded.padding, padding);
|
||||
expect(unpadded.viewInsets, EdgeInsets.zero);
|
||||
expect(unpadded.alwaysUse24HourFormat, true);
|
||||
expect(unpadded.accessibleNavigation, true);
|
||||
expect(unpadded.invertColors, true);
|
||||
expect(unpadded.disableAnimations, true);
|
||||
});
|
||||
|
||||
testWidgets('MediaQuery.textScaleFactorOf', (WidgetTester tester) async {
|
||||
|
||||
Reference in New Issue
Block a user