diff --git a/packages/flutter/lib/src/widgets/media_query.dart b/packages/flutter/lib/src/widgets/media_query.dart index a8fdda349ddd..e128baf8e0b3 100644 --- a/packages/flutter/lib/src/widgets/media_query.dart +++ b/packages/flutter/lib/src/widgets/media_query.dart @@ -667,6 +667,7 @@ class MediaQueryData { && other.padding == padding && other.viewPadding == viewPadding && other.viewInsets == viewInsets + && other.systemGestureInsets == systemGestureInsets && other.alwaysUse24HourFormat == alwaysUse24HourFormat && other.highContrast == highContrast && other.disableAnimations == disableAnimations @@ -708,6 +709,7 @@ class MediaQueryData { 'padding: $padding', 'viewPadding: $viewPadding', 'viewInsets: $viewInsets', + 'systemGestureInsets: $systemGestureInsets', 'alwaysUse24HourFormat: $alwaysUse24HourFormat', 'accessibleNavigation: $accessibleNavigation', 'highContrast: $highContrast', @@ -1282,23 +1284,103 @@ class MediaQuery extends InheritedModel<_MediaQueryAspect> { @override bool updateShouldNotifyDependent(MediaQuery oldWidget, Set dependencies) { - return (data.size != oldWidget.data.size && dependencies.contains(_MediaQueryAspect.size)) - || (data.orientation != oldWidget.data.orientation && dependencies.contains(_MediaQueryAspect.orientation)) - || (data.devicePixelRatio != oldWidget.data.devicePixelRatio && dependencies.contains(_MediaQueryAspect.devicePixelRatio)) - || (data.textScaleFactor != oldWidget.data.textScaleFactor && dependencies.contains(_MediaQueryAspect.textScaleFactor)) - || (data.platformBrightness != oldWidget.data.platformBrightness && dependencies.contains(_MediaQueryAspect.platformBrightness)) - || (data.viewInsets != oldWidget.data.viewInsets && dependencies.contains(_MediaQueryAspect.viewInsets)) - || (data.systemGestureInsets != oldWidget.data.systemGestureInsets && dependencies.contains(_MediaQueryAspect.systemGestureInsets)) - || (data.viewPadding != oldWidget.data.viewPadding && dependencies.contains(_MediaQueryAspect.viewPadding)) - || (data.alwaysUse24HourFormat != oldWidget.data.alwaysUse24HourFormat && dependencies.contains(_MediaQueryAspect.alwaysUse24HourFormat)) - || (data.accessibleNavigation != oldWidget.data.accessibleNavigation && dependencies.contains(_MediaQueryAspect.accessibleNavigation)) - || (data.invertColors != oldWidget.data.invertColors && dependencies.contains(_MediaQueryAspect.invertColors)) - || (data.highContrast != oldWidget.data.highContrast && dependencies.contains(_MediaQueryAspect.highContrast)) - || (data.disableAnimations != oldWidget.data.disableAnimations && dependencies.contains(_MediaQueryAspect.disableAnimations)) - || (data.boldText != oldWidget.data.boldText && dependencies.contains(_MediaQueryAspect.boldText)) - || (data.navigationMode != oldWidget.data.navigationMode && dependencies.contains(_MediaQueryAspect.navigationMode)) - || (data.gestureSettings != oldWidget.data.gestureSettings && dependencies.contains(_MediaQueryAspect.gestureSettings)) - || (data.displayFeatures != oldWidget.data.displayFeatures && dependencies.contains(_MediaQueryAspect.displayFeatures)); + for (final Object dependency in dependencies) { + if (dependency is _MediaQueryAspect) { + switch (dependency) { + case _MediaQueryAspect.size: + if (data.size != oldWidget.data.size) { + return true; + } + break; + case _MediaQueryAspect.orientation: + if (data.orientation != oldWidget.data.orientation) { + return true; + } + break; + case _MediaQueryAspect.devicePixelRatio: + if (data.devicePixelRatio != oldWidget.data.devicePixelRatio) { + return true; + } + break; + case _MediaQueryAspect.textScaleFactor: + if (data.textScaleFactor != oldWidget.data.textScaleFactor) { + return true; + } + break; + case _MediaQueryAspect.platformBrightness: + if (data.platformBrightness != oldWidget.data.platformBrightness) { + return true; + } + break; + case _MediaQueryAspect.padding: + if (data.padding != oldWidget.data.padding) { + return true; + } + break; + case _MediaQueryAspect.viewInsets: + if (data.viewInsets != oldWidget.data.viewInsets) { + return true; + } + break; + case _MediaQueryAspect.systemGestureInsets: + if (data.systemGestureInsets != oldWidget.data.systemGestureInsets) { + return true; + } + break; + case _MediaQueryAspect.viewPadding: + if (data.viewPadding != oldWidget.data.viewPadding) { + return true; + } + break; + case _MediaQueryAspect.alwaysUse24HourFormat: + if (data.alwaysUse24HourFormat != oldWidget.data.alwaysUse24HourFormat) { + return true; + } + break; + case _MediaQueryAspect.accessibleNavigation: + if (data.accessibleNavigation != oldWidget.data.accessibleNavigation) { + return true; + } + break; + case _MediaQueryAspect.invertColors: + if (data.invertColors != oldWidget.data.invertColors) { + return true; + } + break; + case _MediaQueryAspect.highContrast: + if (data.highContrast != oldWidget.data.highContrast) { + return true; + } + break; + case _MediaQueryAspect.disableAnimations: + if (data.disableAnimations != oldWidget.data.disableAnimations) { + return true; + } + break; + case _MediaQueryAspect.boldText: + if (data.boldText != oldWidget.data.boldText) { + return true; + } + break; + case _MediaQueryAspect.navigationMode: + if (data.navigationMode != oldWidget.data.navigationMode) { + return true; + } + break; + case _MediaQueryAspect.gestureSettings: + if (data.gestureSettings != oldWidget.data.gestureSettings) { + return true; + } + break; + case _MediaQueryAspect.displayFeatures: + if (data.displayFeatures != oldWidget.data.displayFeatures) { + return true; + } + break; + } + } + } + return false; } } diff --git a/packages/flutter/test/widgets/media_query_test.dart b/packages/flutter/test/widgets/media_query_test.dart index d5d66b38fc33..9be4d6522387 100644 --- a/packages/flutter/test/widgets/media_query_test.dart +++ b/packages/flutter/test/widgets/media_query_test.dart @@ -8,6 +8,40 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +class _MediaQueryAspectCase { + const _MediaQueryAspectCase(this.method, this.data); + final Function(BuildContext) method; + final MediaQueryData data; +} + +class _MediaQueryAspectVariant extends TestVariant<_MediaQueryAspectCase> { + _MediaQueryAspectVariant({ + required this.values + }); + + @override + final List<_MediaQueryAspectCase> values; + + static _MediaQueryAspectCase? aspect; + + @override + String describeValue(_MediaQueryAspectCase value) { + return value.method.toString(); + } + + @override + Future<_MediaQueryAspectCase?> setUp(_MediaQueryAspectCase value) async { + final _MediaQueryAspectCase? oldAspect = aspect; + aspect = value; + return oldAspect; + } + + @override + Future tearDown(_MediaQueryAspectCase value, _MediaQueryAspectCase? memento) async { + aspect = memento; + } +} + void main() { testWidgets('MediaQuery does not have a default', (WidgetTester tester) async { bool tested = false; @@ -1013,4 +1047,101 @@ void main() { expect(sizeBuildCount, 2); expect(textScaleFactorBuildCount, 2); }); + + testWidgets('MediaQuery partial dependencies', (WidgetTester tester) async { + MediaQueryData data = const MediaQueryData(); + + int buildCount = 0; + + final Widget builder = Builder( + builder: (BuildContext context) { + _MediaQueryAspectVariant.aspect!.method(context); + buildCount++; + return const SizedBox.shrink(); + } + ); + + final Widget page = StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return MediaQuery( + data: data, + child: ListView( + children: [ + builder, + ElevatedButton( + onPressed: () { + setState(() { + data = _MediaQueryAspectVariant.aspect!.data; + }); + }, + child: const Text('Change data') + ), + ElevatedButton( + onPressed: () { + setState(() { + data = data.copyWith(); + }); + }, + child: const Text('Copy data') + ) + ] + ) + ); + }, + ); + + await tester.pumpWidget(MaterialApp(home: page)); + expect(buildCount, 1); + + await tester.tap(find.text('Copy data')); + await tester.pumpAndSettle(); + expect(buildCount, 1); + + await tester.tap(find.text('Change data')); + await tester.pumpAndSettle(); + expect(buildCount, 2); + + await tester.tap(find.text('Copy data')); + await tester.pumpAndSettle(); + expect(buildCount, 2); + }, variant: _MediaQueryAspectVariant( + values: <_MediaQueryAspectCase>[ + const _MediaQueryAspectCase(MediaQuery.sizeOf, MediaQueryData(size: Size(1, 1))), + const _MediaQueryAspectCase(MediaQuery.maybeSizeOf, MediaQueryData(size: Size(1, 1))), + const _MediaQueryAspectCase(MediaQuery.orientationOf, MediaQueryData(size: Size(2, 1))), + const _MediaQueryAspectCase(MediaQuery.maybeOrientationOf, MediaQueryData(size: Size(2, 1))), + const _MediaQueryAspectCase(MediaQuery.devicePixelRatioOf, MediaQueryData(devicePixelRatio: 1.1)), + const _MediaQueryAspectCase(MediaQuery.maybeDevicePixelRatioOf, MediaQueryData(devicePixelRatio: 1.1)), + const _MediaQueryAspectCase(MediaQuery.textScaleFactorOf, MediaQueryData(textScaleFactor: 1.1)), + const _MediaQueryAspectCase(MediaQuery.maybeTextScaleFactorOf, MediaQueryData(textScaleFactor: 1.1)), + const _MediaQueryAspectCase(MediaQuery.platformBrightnessOf, MediaQueryData(platformBrightness: Brightness.dark)), + const _MediaQueryAspectCase(MediaQuery.maybePlatformBrightnessOf, MediaQueryData(platformBrightness: Brightness.dark)), + const _MediaQueryAspectCase(MediaQuery.paddingOf, MediaQueryData(padding: EdgeInsets.all(1))), + const _MediaQueryAspectCase(MediaQuery.maybePaddingOf, MediaQueryData(padding: EdgeInsets.all(1))), + const _MediaQueryAspectCase(MediaQuery.viewInsetsOf, MediaQueryData(viewInsets: EdgeInsets.all(1))), + const _MediaQueryAspectCase(MediaQuery.maybeViewInsetsOf, MediaQueryData(viewInsets: EdgeInsets.all(1))), + const _MediaQueryAspectCase(MediaQuery.systemGestureInsetsOf, MediaQueryData(systemGestureInsets: EdgeInsets.all(1))), + const _MediaQueryAspectCase(MediaQuery.maybeSystemGestureInsetsOf, MediaQueryData(systemGestureInsets: EdgeInsets.all(1))), + const _MediaQueryAspectCase(MediaQuery.viewPaddingOf, MediaQueryData(viewPadding: EdgeInsets.all(1))), + const _MediaQueryAspectCase(MediaQuery.maybeViewPaddingOf, MediaQueryData(viewPadding: EdgeInsets.all(1))), + const _MediaQueryAspectCase(MediaQuery.alwaysUse24HourFormatOf, MediaQueryData(alwaysUse24HourFormat: true)), + const _MediaQueryAspectCase(MediaQuery.maybeAlwaysUse24HourFormatOf, MediaQueryData(alwaysUse24HourFormat: true)), + const _MediaQueryAspectCase(MediaQuery.accessibleNavigationOf, MediaQueryData(accessibleNavigation: true)), + const _MediaQueryAspectCase(MediaQuery.maybeAccessibleNavigationOf, MediaQueryData(accessibleNavigation: true)), + const _MediaQueryAspectCase(MediaQuery.invertColorsOf, MediaQueryData(invertColors: true)), + const _MediaQueryAspectCase(MediaQuery.maybeInvertColorsOf, MediaQueryData(invertColors: true)), + const _MediaQueryAspectCase(MediaQuery.highContrastOf, MediaQueryData(highContrast: true)), + const _MediaQueryAspectCase(MediaQuery.maybeHighContrastOf, MediaQueryData(highContrast: true)), + const _MediaQueryAspectCase(MediaQuery.disableAnimationsOf, MediaQueryData(disableAnimations: true)), + const _MediaQueryAspectCase(MediaQuery.maybeDisableAnimationsOf, MediaQueryData(disableAnimations: true)), + const _MediaQueryAspectCase(MediaQuery.boldTextOf, MediaQueryData(boldText: true)), + const _MediaQueryAspectCase(MediaQuery.maybeBoldTextOf, MediaQueryData(boldText: true)), + const _MediaQueryAspectCase(MediaQuery.navigationModeOf, MediaQueryData(navigationMode: NavigationMode.directional)), + const _MediaQueryAspectCase(MediaQuery.maybeNavigationModeOf, MediaQueryData(navigationMode: NavigationMode.directional)), + const _MediaQueryAspectCase(MediaQuery.gestureSettingsOf, MediaQueryData(gestureSettings: DeviceGestureSettings(touchSlop: 1))), + const _MediaQueryAspectCase(MediaQuery.maybeGestureSettingsOf, MediaQueryData(gestureSettings: DeviceGestureSettings(touchSlop: 1))), + const _MediaQueryAspectCase(MediaQuery.displayFeaturesOf, MediaQueryData(displayFeatures: [DisplayFeature(bounds: Rect.zero, type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)])), + const _MediaQueryAspectCase(MediaQuery.maybeDisplayFeaturesOf, MediaQueryData(displayFeatures: [DisplayFeature(bounds: Rect.zero, type: DisplayFeatureType.unknown, state: DisplayFeatureState.unknown)])), + ] + )); }