Skip to content

Commit

Permalink
Revert "Override MediaQuery for WidgetsApp (#81295)"
Browse files Browse the repository at this point in the history
This reverts commit b9bf576.
  • Loading branch information
renyou committed Jun 24, 2021
1 parent 144af6c commit 316b431
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 221 deletions.
104 changes: 85 additions & 19 deletions packages/flutter/lib/src/widgets/app.dart
Expand Up @@ -236,9 +236,6 @@ typedef InitialRouteListFactory = List<Route<dynamic>> Function(String initialRo
/// It is used by both [MaterialApp] and [CupertinoApp] to implement base
/// functionality for an app.
///
/// If a [MediaQuery] is not available above [WidgetsApp], a [MediaQuery] is
/// built using [MediaQuery.fromWindow].
///
/// Find references to many of the widgets that [WidgetsApp] wraps in the "See
/// also" section.
///
Expand All @@ -250,8 +247,6 @@ typedef InitialRouteListFactory = List<Route<dynamic>> Function(String initialRo
/// without an explicit style.
/// * [MediaQuery], which establishes a subtree in which media queries resolve
/// to a [MediaQueryData].
/// * [MediaQuery.fromWindow], which builds a [MediaQuery] with data derived
/// from [WidgetsBinding.window].
/// * [Localizations], which defines the [Locale] for its `child`.
/// * [Title], a widget that describes this app in the operating system.
/// * [Navigator], a widget that manages a set of child widgets with a stack
Expand Down Expand Up @@ -1640,19 +1635,6 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {

assert(_debugCheckLocalizations(appLocale));

Widget child = Localizations(
locale: appLocale,
delegates: _localizationsDelegates.toList(),
child: title,
);

final MediaQueryData? data = MediaQuery.maybeOf(context);
if (data == null) {
child = MediaQuery.fromWindow(
child: child,
);
}

return RootRestorationScope(
restorationId: widget.restorationScopeId,
child: Shortcuts(
Expand All @@ -1666,7 +1648,13 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
child: DefaultTextEditingActions(
child: FocusTraversalGroup(
policy: ReadingOrderTraversalPolicy(),
child: child,
child: _MediaQueryFromWindow(
child: Localizations(
locale: appLocale,
delegates: _localizationsDelegates.toList(),
child: title,
),
),
),
),
),
Expand All @@ -1675,3 +1663,81 @@ class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
);
}
}

/// Builds [MediaQuery] from `window` by listening to [WidgetsBinding].
///
/// It is performed in a standalone widget to rebuild **only** [MediaQuery] and
/// its dependents when `window` changes, instead of rebuilding the entire widget tree.
class _MediaQueryFromWindow extends StatefulWidget {
const _MediaQueryFromWindow({Key? key, required this.child}) : super(key: key);

final Widget child;

@override
_MediaQueryFromWindowsState createState() => _MediaQueryFromWindowsState();
}

class _MediaQueryFromWindowsState extends State<_MediaQueryFromWindow> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
}

// ACCESSIBILITY

@override
void didChangeAccessibilityFeatures() {
setState(() {
// The properties of window have changed. We use them in our build
// function, so we need setState(), but we don't cache anything locally.
});
}

// METRICS

@override
void didChangeMetrics() {
setState(() {
// The properties of window have changed. We use them in our build
// function, so we need setState(), but we don't cache anything locally.
});
}

@override
void didChangeTextScaleFactor() {
setState(() {
// The textScaleFactor 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.
});
}

// 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.
});
}

@override
Widget build(BuildContext context) {
MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance!.window);
if (!kReleaseMode) {
data = data.copyWith(platformBrightness: debugBrightnessOverride);
}
return MediaQuery(
data: data,
child: widget.child,
);
}

@override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
}
124 changes: 0 additions & 124 deletions packages/flutter/lib/src/widgets/media_query.dart
Expand Up @@ -9,7 +9,6 @@ import 'dart:ui' show Brightness;
import 'package:flutter/foundation.dart';

import 'basic.dart';
import 'binding.dart';
import 'debug.dart';
import 'framework.dart';

Expand Down Expand Up @@ -788,32 +787,6 @@ class MediaQuery extends InheritedWidget {
);
}

/// Creates a [_MediaQueryFromWindow] which builds and updates a
/// [MediaQuery] using the latest [WidgetsBinding.window] values.
///
/// The [MediaQuery] is wrapped in a separate widget to ensure that only it
/// and its dependents are updated when `window` changes, instead of
/// rebuilding the whole widget tree.
///
/// This should be inserted into the widget tree when the [MediaQuery] view
/// padding is consumed by a widget in such a way that the view padding is no
/// longer exposed to the widget's descendants or siblings.
///
/// The [child] argument is required and must not be null.
///
/// See also:
///
/// * [_MediaQueryFromWindow], the underlying widget.
static Widget fromWindow({
Key? key,
required Widget child,
}) {
return _MediaQueryFromWindow(
key: key,
child: child,
);
}

/// Contains information about the current media.
///
/// For example, the [MediaQueryData.size] property contains the width and
Expand Down Expand Up @@ -949,100 +922,3 @@ enum NavigationMode {
/// focus (although they remain disabled) when traversed.
directional,
}

/// Provides a [MediaQuery] which is built and updated using the latest
/// [WidgetsBinding.window] values.
///
/// Receives `window` updates by listening to [WidgetsBinding].
///
/// The standalone widget ensures that it rebuilds **only** [MediaQuery] and
/// its dependents when `window` changes, instead of rebuilding the entire
/// widget tree.
///
/// It is used by [WidgetsApp] if no other [MediaQuery] is available above it.
///
/// See also:
///
/// * [MediaQuery], which establishes a subtree in which media queries resolve
/// to a [MediaQueryData].
class _MediaQueryFromWindow extends StatefulWidget {
/// Creates a [_MediaQueryFromWindow] that provides a [MediaQuery] to its
/// descendants using the `window` to keep [MediaQueryData] up to date.
///
/// The [child] must not be null.
const _MediaQueryFromWindow({
Key? key,
required this.child,
}) : super(key: key);

/// {@macro flutter.widgets.ProxyWidget.child}
final Widget child;

@override
State<_MediaQueryFromWindow> createState() => _MediaQueryFromWindowState();
}

class _MediaQueryFromWindowState extends State<_MediaQueryFromWindow> with WidgetsBindingObserver {
@override
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
}

// ACCESSIBILITY

@override
void didChangeAccessibilityFeatures() {
setState(() {
// The properties of window have changed. We use them in our build
// function, so we need setState(), but we don't cache anything locally.
});
}

// METRICS

@override
void didChangeMetrics() {
setState(() {
// The properties of window have changed. We use them in our build
// function, so we need setState(), but we don't cache anything locally.
});
}

@override
void didChangeTextScaleFactor() {
setState(() {
// The textScaleFactor 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.
});
}

// 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.
});
}

@override
Widget build(BuildContext context) {
MediaQueryData data = MediaQueryData.fromWindow(WidgetsBinding.instance!.window);
if (!kReleaseMode) {
data = data.copyWith(platformBrightness: debugBrightnessOverride);
}
return MediaQuery(
data: data,
child: widget.child,
);
}

@override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
}
33 changes: 0 additions & 33 deletions packages/flutter/test/widgets/app_test.dart
Expand Up @@ -455,39 +455,6 @@ void main() {
const Locale('zh'),
);
});

testWidgets('WidgetsApp creates a MediaQuery', (WidgetTester tester) async {
late BuildContext capturedContext;
await tester.pumpWidget(
WidgetsApp(
builder: (BuildContext context, Widget? child) {
capturedContext = context;
return const Placeholder();
},
color: const Color(0xFF123456),
),
);
expect(MediaQuery.of(capturedContext), isNotNull);
});

testWidgets('WidgetsApp does not create MediaQuery if one is already available', (WidgetTester tester) async {
late BuildContext capturedContext;
final UniqueKey uniqueKey = UniqueKey();
await tester.pumpWidget(
MediaQuery(
key: uniqueKey,
data: const MediaQueryData(),
child: WidgetsApp(
builder: (BuildContext context, Widget? child) {
capturedContext = context;
return const Placeholder();
},
color: const Color(0xFF123456),
),
),
);
expect(capturedContext.dependOnInheritedWidgetOfExactType<MediaQuery>()?.key, uniqueKey);
});
}

typedef SimpleRouterDelegateBuilder = Widget Function(BuildContext, RouteInformation);
Expand Down
45 changes: 0 additions & 45 deletions packages/flutter/test/widgets/media_query_test.dart
Expand Up @@ -627,49 +627,4 @@ void main() {
expect(outsideBoldTextOverride, false);
expect(insideBoldTextOverride, true);
});

testWidgets('MediaQuery.fromWindow creates a MediaQuery', (WidgetTester tester) async {
bool hasMediaQueryAsParentOutside = false;
bool hasMediaQueryAsParentInside = false;

await tester.pumpWidget(
Builder(
builder: (BuildContext context) {
hasMediaQueryAsParentOutside =
context.findAncestorWidgetOfExactType<MediaQuery>() != null;
return MediaQuery.fromWindow(
child: Builder(
builder: (BuildContext context) {
hasMediaQueryAsParentInside =
context.findAncestorWidgetOfExactType<MediaQuery>() != null;
return const SizedBox();
},
),
);
},
),
);

expect(hasMediaQueryAsParentOutside, false);
expect(hasMediaQueryAsParentInside, true);
});

testWidgets('MediaQueryData.fromWindow is created using window values', (WidgetTester tester)
async {
final MediaQueryData windowData = MediaQueryData.fromWindow(WidgetsBinding.instance!.window);
late MediaQueryData fromWindowData;

await tester.pumpWidget(
MediaQuery.fromWindow(
child: Builder(
builder: (BuildContext context) {
fromWindowData = MediaQuery.of(context);
return const SizedBox();
},
),
),
);

expect(windowData, equals(fromWindowData));
});
}

0 comments on commit 316b431

Please sign in to comment.