// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:math' as math; import 'dart:ui' as ui; import 'dart:ui' show Brightness; import 'package:flutter/foundation.dart'; import 'basic.dart'; import 'framework.dart'; /// Whether in portrait or landscape. enum Orientation { /// Taller than wide. portrait, /// Wider than tall. landscape } /// Information about a piece of media (e.g., a window). /// /// For example, the [MediaQueryData.size] property contains the width and /// height of the current window. /// /// To obtain the current [MediaQueryData] for a given [BuildContext], use the /// [MediaQuery.of] function. For example, to obtain the size of the current /// window, use `MediaQuery.of(context).size`. /// /// If no [MediaQuery] is in scope then the [MediaQuery.of] method will throw an /// exception, unless the `nullOk` argument is set to true, in which case it /// returns null. /// /// ## Insets and Padding /// /// ![A diagram of padding, viewInsets, and viewPadding in correlation with each /// other](https://flutter.github.io/assets-for-api-docs/assets/widgets/media_query.png) /// /// This diagram illustrates how [padding] relates to [viewPadding] and /// [viewInsets], shown here in its simplest configuration, as the difference /// between the two. In cases when the viewInsets exceed the viewPadding, like /// when a software keyboard is shown below, padding goes to zero rather than a /// negative value. Therefore, padding is calculated by taking /// `max(0.0, viewPadding - viewInsets)`. /// /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/widgets/window_padding.mp4} /// /// In this diagram, the black areas represent system UI that the app cannot /// draw over. The red area represents view padding that the application may not /// be able to detect gestures in and may not want to draw in. The grey area /// represents the system keyboard, which can cover over the bottom view padding /// when visible. /// /// MediaQueryData includes three [EdgeInsets] values: /// [padding], [viewPadding], and [viewInsets]. These values reflect the /// configuration of the device and are used and optionally consumed by widgets /// that position content within these insets. The padding value defines areas /// that might not be completely visible, like the display "notch" on the iPhone /// X. The viewInsets value defines areas that aren't visible at all, typically /// because they're obscured by the device's keyboard. Similar to viewInsets, /// viewPadding does not differentiate padding in areas that may be obscured. /// For example, by using the viewPadding property, padding would defer to the /// iPhone "safe area" regardless of whether a keyboard is showing. /// /// The viewInsets and viewPadding are independent values, they're /// measured from the edges of the MediaQuery widget's bounds. Together they /// inform the [padding] property. The bounds of the top level MediaQuery /// created by [WidgetsApp] are the same as the window that contains the app. /// /// Widgets whose layouts consume space defined by [viewInsets], [viewPadding], /// or [padding] should enclose their children in secondary MediaQuery /// widgets that reduce those properties by the same amount. /// The [removePadding], [removeViewPadding], and [removeViewInsets] methods are /// useful for this. /// /// See also: /// /// * [Scaffold], [SafeArea], [CupertinoTabScaffold], and /// [CupertinoPageScaffold], all of which are informed by [padding], /// [viewPadding], and [viewInsets]. @immutable class MediaQueryData { /// Creates data for a media query with explicit values. /// /// Consider using [MediaQueryData.fromWindow] to create data based on a /// [Window]. const 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.systemGestureInsets = EdgeInsets.zero, this.viewPadding = EdgeInsets.zero, this.physicalDepth = double.maxFinite, this.alwaysUse24HourFormat = false, this.accessibleNavigation = false, this.invertColors = false, this.highContrast = false, this.disableAnimations = false, this.boldText = false, }); /// Creates data for a media query based on the given window. /// /// If you use this, you should ensure that you also register for /// notifications so that you can update your [MediaQueryData] when the /// window's metrics change. For example, see /// [WidgetsBindingObserver.didChangeMetrics] or [Window.onMetricsChanged]. MediaQueryData.fromWindow(ui.Window window) : size = window.physicalSize / window.devicePixelRatio, devicePixelRatio = window.devicePixelRatio, textScaleFactor = window.textScaleFactor, platformBrightness = window.platformBrightness, padding = EdgeInsets.fromWindowPadding(window.padding, window.devicePixelRatio), viewPadding = EdgeInsets.fromWindowPadding(window.viewPadding, window.devicePixelRatio), viewInsets = EdgeInsets.fromWindowPadding(window.viewInsets, window.devicePixelRatio), systemGestureInsets = EdgeInsets.fromWindowPadding(window.systemGestureInsets, window.devicePixelRatio), physicalDepth = window.physicalDepth, accessibleNavigation = window.accessibilityFeatures.accessibleNavigation, invertColors = window.accessibilityFeatures.invertColors, disableAnimations = window.accessibilityFeatures.disableAnimations, boldText = window.accessibilityFeatures.boldText, highContrast = false, alwaysUse24HourFormat = window.alwaysUse24HourFormat; /// The size of the media in logical pixels (e.g, the size of the screen). /// /// Logical pixels are roughly the same visual size across devices. Physical /// pixels are the size of the actual hardware pixels on the device. The /// number of physical pixels per logical pixel is described by the /// [devicePixelRatio]. final Size size; /// The number of device pixels for each logical pixel. This number might not /// be a power of two. Indeed, it might not even be an integer. For example, /// the Nexus 6 has a device pixel ratio of 3.5. final double devicePixelRatio; /// The number of font pixels for each logical pixel. /// /// For example, if the text scale factor is 1.5, text will be 50% larger than /// the specified font size. /// /// See also: /// /// * [MediaQuery.textScaleFactorOf], a convenience method which returns the /// 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. /// /// When a mobile device's keyboard is visible `viewInsets.bottom` /// corresponds to the top of the keyboard. /// /// This value is independent of the [padding] and [viewPadding]. viewPadding /// is measured from the edges of the [MediaQuery] widget's bounds. Padding is /// calculated based on the viewPadding and viewInsets. The bounds of the top /// level MediaQuery created by [WidgetsApp] are the same as the window /// (often the mobile device screen) that contains the app. /// /// See also: /// /// * [ui.window], which provides some additional detail about this property /// and how it relates to [padding] and [viewPadding]. final EdgeInsets viewInsets; /// The parts of the display that are partially obscured by system UI, /// typically by the hardware display "notches" or the system status bar. /// /// If you consumed this padding (e.g. by building a widget that envelops or /// accounts for this padding in its layout in such a way that children are /// no longer exposed to this padding), you should remove this padding /// for subsequent descendants in the widget tree by inserting a new /// [MediaQuery] widget using the [MediaQuery.removePadding] factory. /// /// Padding is derived from the values of viewInsets and viewPadding. /// /// See also: /// /// * [ui.window], which provides some additional detail about this /// property and how it relates to [viewInsets] and [viewPadding]. /// * [SafeArea], a widget that consumes this padding with a [Padding] widget /// and automatically removes it from the [MediaQuery] for its child. final EdgeInsets padding; /// The parts of the display that are partially obscured by system UI, /// typically by the hardware display "notches" or the system status bar. /// /// This value remains the same regardless of whether the system is reporting /// other obstructions in the same physical area of the screen. For example, a /// software keyboard on the bottom of the screen that may cover and consume /// the same area that requires bottom padding will not affect this value. /// /// This value is independent of the [padding] and [viewInsets]: their values /// are measured from the edges of the [MediaQuery] widget's bounds. The /// bounds of the top level MediaQuery created by [WidgetsApp] are the /// same as the window that contains the app. On mobile devices, this will /// typically be the full screen. /// /// See also: /// /// * [ui.window], which provides some additional detail about this /// property and how it relates to [padding] and [viewInsets]. final EdgeInsets viewPadding; /// The areas along the edges of the display where the system consumes /// certain input events and blocks delivery of those events to the app. /// /// Starting with Android Q, simple swipe gestures that start within the /// [systemGestureInsets] areas are used by the system for page navigation /// and may not be delivered to the app. Taps and swipe gestures that begin /// with a long-press are delivered to the app, but simple press-drag-release /// swipe gestures which begin within the area defined by [systemGestureInsets] /// may not be. /// /// Apps should avoid locating gesture detectors within the system gesture /// insets area. Apps should feel free to put visual elements within /// this area. /// /// This property is currently only expected to be set to a non-default value /// on Android starting with version Q. /// /// {@tool snippet --template=stateful_widget_material} /// /// For apps that might be deployed on Android Q devices with full gesture /// navigation enabled, use [MediaQuery.systemGestureInsets] with [Padding] /// to avoid having the left and right edges of the [Slider] from appearing /// within the area reserved for system gesture navigation. /// /// By default, [Slider]s expand to fill the available width. So, we pad the /// left and right sides. /// /// ```dart /// double _currentValue = 0.2; /// /// @override /// Widget build(BuildContext context) { /// EdgeInsets systemGestureInsets = MediaQuery.of(context).systemGestureInsets; /// return Scaffold( /// appBar: AppBar(title: Text('Pad Slider to avoid systemGestureInsets')), /// body: Padding( /// padding: EdgeInsets.only( // only left and right padding are needed here /// left: systemGestureInsets.left, /// right: systemGestureInsets.right, /// ), /// child: Slider( /// value: _currentValue.toDouble(), /// onChanged: (double newValue) { /// setState(() { /// _currentValue = newValue; /// }); /// }, /// ), /// ), /// ); /// } /// ``` /// {@end-tool} final EdgeInsets systemGestureInsets; /// The physical depth is the maximum elevation that the Window allows. /// /// Physical layers drawn at or above this elevation will have their elevation /// clamped to this value. This can happen if the physical layer itself has /// an elevation larger than the available depth, or if some ancestor of the /// layer causes it to have a cumulative elevation that is larger than the /// available depth. /// /// The default value is [double.maxFinite], which is used for platforms that /// do not specify a maximum elevation. This property is currently only /// expected to be set to a non-default value on Fuchsia. final double physicalDepth; /// Whether to use 24-hour format when formatting time. /// /// The behavior of this flag is different across platforms: /// /// - On Android this flag is reported directly from the user settings called /// "Use 24-hour format". It applies to any locale used by the application, /// whether it is the system-wide locale, or the custom locale set by the /// application. /// - On iOS this flag is set to true when the user setting called "24-Hour /// Time" is set or the system-wide locale's default uses 24-hour /// 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 user requested a high contrast between foreground and background /// content on iOS, via Settings -> Accessibility -> Increase Contrast. /// /// This flag is currently only updated on iOS devices that are running iOS 13 /// or above. final bool highContrast; /// Whether the platform is requesting that animations be disabled or reduced /// as much as possible. /// /// See also: /// /// * [Window.AccessibilityFeatures], where the setting originates. final bool disableAnimations; /// Whether the platform is requesting that text be drawn with a bold font /// weight. /// /// See also: /// /// * [Window.AccessibilityFeatures], where the setting originates. final bool boldText; /// 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; } /// Creates a copy of this media query data but with the given fields replaced /// with the new values. MediaQueryData copyWith({ Size size, double devicePixelRatio, double textScaleFactor, Brightness platformBrightness, EdgeInsets padding, EdgeInsets viewPadding, EdgeInsets viewInsets, EdgeInsets systemGestureInsets, double physicalDepth, bool alwaysUse24HourFormat, bool highContrast, bool disableAnimations, bool invertColors, bool accessibleNavigation, bool boldText, }) { return MediaQueryData( size: size ?? this.size, devicePixelRatio: devicePixelRatio ?? this.devicePixelRatio, textScaleFactor: textScaleFactor ?? this.textScaleFactor, platformBrightness: platformBrightness ?? this.platformBrightness, padding: padding ?? this.padding, viewPadding: viewPadding ?? this.viewPadding, viewInsets: viewInsets ?? this.viewInsets, systemGestureInsets: systemGestureInsets ?? this.systemGestureInsets, physicalDepth: physicalDepth ?? this.physicalDepth, alwaysUse24HourFormat: alwaysUse24HourFormat ?? this.alwaysUse24HourFormat, invertColors: invertColors ?? this.invertColors, highContrast: highContrast ?? this.highContrast, disableAnimations: disableAnimations ?? this.disableAnimations, accessibleNavigation: accessibleNavigation ?? this.accessibleNavigation, boldText: boldText ?? this.boldText, ); } /// Creates a copy of this media query data but with the given [padding]s /// replaced with zero. /// /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments /// must not be null. If all four are false (the default) then this /// [MediaQueryData] is returned unmodified. /// /// See also: /// /// * [MediaQuery.removePadding], which uses this method to remove [padding] /// from the ambient [MediaQuery]. /// * [SafeArea], which both removes the padding from the [MediaQuery] and /// adds a [Padding] widget. /// * [removeViewInsets], the same thing but for [viewInsets]. /// * [removeViewPadding], the same thing but for [viewPadding]. MediaQueryData removePadding({ bool removeLeft = false, bool removeTop = false, bool removeRight = false, bool removeBottom = false, }) { if (!(removeLeft || removeTop || removeRight || removeBottom)) return this; return MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, textScaleFactor: textScaleFactor, platformBrightness: platformBrightness, padding: padding.copyWith( left: removeLeft ? 0.0 : null, top: removeTop ? 0.0 : null, right: removeRight ? 0.0 : null, bottom: removeBottom ? 0.0 : null, ), viewPadding: viewPadding.copyWith( left: removeLeft ? math.max(0.0, viewPadding.left - padding.left) : null, top: removeTop ? math.max(0.0, viewPadding.top - padding.top) : null, right: removeRight ? math.max(0.0, viewPadding.right - padding.right) : null, bottom: removeBottom ? math.max(0.0, viewPadding.bottom - padding.bottom) : null, ), viewInsets: viewInsets, alwaysUse24HourFormat: alwaysUse24HourFormat, highContrast: highContrast, disableAnimations: disableAnimations, invertColors: invertColors, accessibleNavigation: accessibleNavigation, boldText: boldText, ); } /// Creates a copy of this media query data but with the given [viewInsets] /// replaced with zero. /// /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments /// must not be null. If all four are false (the default) then this /// [MediaQueryData] is returned unmodified. /// /// See also: /// /// * [MediaQuery.removeViewInsets], which uses this method to remove /// [viewInsets] from the ambient [MediaQuery]. /// * [removePadding], the same thing but for [padding]. /// * [removeViewPadding], the same thing but for [viewPadding]. MediaQueryData removeViewInsets({ bool removeLeft = false, bool removeTop = false, bool removeRight = false, bool removeBottom = false, }) { if (!(removeLeft || removeTop || removeRight || removeBottom)) return this; return MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, textScaleFactor: textScaleFactor, platformBrightness: platformBrightness, padding: padding, viewPadding: viewPadding.copyWith( left: removeLeft ? math.max(0.0, viewPadding.left - viewInsets.left) : null, top: removeTop ? math.max(0.0, viewPadding.top - viewInsets.top) : null, right: removeRight ? math.max(0.0, viewPadding.right - viewInsets.right) : null, bottom: removeBottom ? math.max(0.0, viewPadding.bottom - viewInsets.bottom) : null, ), viewInsets: viewInsets.copyWith( left: removeLeft ? 0.0 : null, top: removeTop ? 0.0 : null, right: removeRight ? 0.0 : null, bottom: removeBottom ? 0.0 : null, ), alwaysUse24HourFormat: alwaysUse24HourFormat, highContrast: highContrast, disableAnimations: disableAnimations, invertColors: invertColors, accessibleNavigation: accessibleNavigation, boldText: boldText, ); } /// Creates a copy of this media query data but with the given [viewPadding] /// replaced with zero. /// /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments /// must not be null. If all four are false (the default) then this /// [MediaQueryData] is returned unmodified. /// /// See also: /// /// * [MediaQuery.removeViewPadding], which uses this method to remove /// [viewPadding] from the ambient [MediaQuery]. /// * [removePadding], the same thing but for [padding]. /// * [removeViewInsets], the same thing but for [viewInsets]. MediaQueryData removeViewPadding({ bool removeLeft = false, bool removeTop = false, bool removeRight = false, bool removeBottom = false, }) { if (!(removeLeft || removeTop || removeRight || removeBottom)) return this; return MediaQueryData( size: size, devicePixelRatio: devicePixelRatio, textScaleFactor: textScaleFactor, platformBrightness: platformBrightness, padding: padding.copyWith( left: removeLeft ? 0.0 : null, top: removeTop ? 0.0 : null, right: removeRight ? 0.0 : null, bottom: removeBottom ? 0.0 : null, ), viewInsets: viewInsets, viewPadding: viewPadding.copyWith( left: removeLeft ? 0.0 : null, top: removeTop ? 0.0 : null, right: removeRight ? 0.0 : null, bottom: removeBottom ? 0.0 : null, ), alwaysUse24HourFormat: alwaysUse24HourFormat, highContrast: highContrast, disableAnimations: disableAnimations, invertColors: invertColors, accessibleNavigation: accessibleNavigation, boldText: boldText, ); } @override bool operator ==(Object other) { if (other.runtimeType != runtimeType) return false; final MediaQueryData typedOther = other; return typedOther.size == size && typedOther.devicePixelRatio == devicePixelRatio && typedOther.textScaleFactor == textScaleFactor && typedOther.platformBrightness == platformBrightness && typedOther.padding == padding && typedOther.viewPadding == viewPadding && typedOther.viewInsets == viewInsets && typedOther.physicalDepth == physicalDepth && typedOther.alwaysUse24HourFormat == alwaysUse24HourFormat && typedOther.highContrast == highContrast && typedOther.disableAnimations == disableAnimations && typedOther.invertColors == invertColors && typedOther.accessibleNavigation == accessibleNavigation && typedOther.boldText == boldText; } @override int get hashCode { return hashValues( size, devicePixelRatio, textScaleFactor, platformBrightness, padding, viewPadding, viewInsets, physicalDepth, alwaysUse24HourFormat, highContrast, disableAnimations, invertColors, accessibleNavigation, boldText, ); } @override String toString() { return '$runtimeType(' 'size: $size, ' 'devicePixelRatio: ${devicePixelRatio.toStringAsFixed(1)}, ' 'textScaleFactor: ${textScaleFactor.toStringAsFixed(1)}, ' 'platformBrightness: $platformBrightness, ' 'padding: $padding, ' 'viewPadding: $viewPadding, ' 'viewInsets: $viewInsets, ' 'physicalDepth: $physicalDepth, ' 'alwaysUse24HourFormat: $alwaysUse24HourFormat, ' 'accessibleNavigation: $accessibleNavigation, ' 'highContrast: $highContrast,' 'disableAnimations: $disableAnimations, ' 'invertColors: $invertColors, ' 'boldText: $boldText' ')'; } } /// Establishes a subtree in which media queries resolve to the given data. /// /// For example, to learn the size of the current media (e.g., the window /// containing your app), you can read the [MediaQueryData.size] property from /// the [MediaQueryData] returned by [MediaQuery.of]: /// `MediaQuery.of(context).size`. /// /// Querying the current media using [MediaQuery.of] will cause your widget to /// rebuild automatically whenever the [MediaQueryData] changes (e.g., if the /// user rotates their device). /// /// If no [MediaQuery] is in scope then the [MediaQuery.of] method will throw an /// exception, unless the `nullOk` argument is set to true, in which case it /// returns null. /// /// {@youtube 560 315 https://www.youtube.com/watch?v=A3WrA4zAaPw} /// /// See also: /// /// * [WidgetsApp] and [MaterialApp], which introduce a [MediaQuery] and keep /// it up to date with the current screen metrics as they change. /// * [MediaQueryData], the data structure that represents the metrics. class MediaQuery extends InheritedWidget { /// Creates a widget that provides [MediaQueryData] to its descendants. /// /// The [data] and [child] arguments must not be null. const MediaQuery({ Key key, @required this.data, @required Widget child, }) : assert(child != null), assert(data != null), super(key: key, child: child); /// Creates a new [MediaQuery] that inherits from the ambient [MediaQuery] /// from the given context, but removes the specified padding. /// /// This should be inserted into the widget tree when the [MediaQuery] padding /// is consumed by a widget in such a way that the padding is no longer /// exposed to the widget's descendants or siblings. /// /// The [context] argument is required, must not be null, and must have a /// [MediaQuery] in scope. /// /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments /// must not be null. If all four are false (the default) then the returned /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not /// particularly useful. /// /// The [child] argument is required and must not be null. /// /// See also: /// /// * [SafeArea], which both removes the padding from the [MediaQuery] and /// adds a [Padding] widget. /// * [MediaQueryData.padding], the affected property of the /// [MediaQueryData]. /// * [removeViewInsets], the same thing but for [MediaQueryData.viewInsets]. /// * [removeViewPadding], the same thing but for /// [MediaQueryData.viewPadding]. factory MediaQuery.removePadding({ Key key, @required BuildContext context, bool removeLeft = false, bool removeTop = false, bool removeRight = false, bool removeBottom = false, @required Widget child, }) { return MediaQuery( key: key, data: MediaQuery.of(context).removePadding( removeLeft: removeLeft, removeTop: removeTop, removeRight: removeRight, removeBottom: removeBottom, ), child: child, ); } /// Creates a new [MediaQuery] that inherits from the ambient [MediaQuery] /// from the given context, but removes the specified view insets. /// /// This should be inserted into the widget tree when the [MediaQuery] view /// insets are consumed by a widget in such a way that the view insets are no /// longer exposed to the widget's descendants or siblings. /// /// The [context] argument is required, must not be null, and must have a /// [MediaQuery] in scope. /// /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments /// must not be null. If all four are false (the default) then the returned /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not /// particularly useful. /// /// The [child] argument is required and must not be null. /// /// See also: /// /// * [MediaQueryData.viewInsets], the affected property of the /// [MediaQueryData]. /// * [removePadding], the same thing but for [MediaQueryData.padding]. /// * [removeViewPadding], the same thing but for /// [MediaQueryData.viewPadding]. factory MediaQuery.removeViewInsets({ Key key, @required BuildContext context, bool removeLeft = false, bool removeTop = false, bool removeRight = false, bool removeBottom = false, @required Widget child, }) { return MediaQuery( key: key, data: MediaQuery.of(context).removeViewInsets( removeLeft: removeLeft, removeTop: removeTop, removeRight: removeRight, removeBottom: removeBottom, ), child: child, ); } /// Creates a new [MediaQuery] that inherits from the ambient [MediaQuery] /// from the given context, but removes the specified view padding. /// /// 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 [context] argument is required, must not be null, and must have a /// [MediaQuery] in scope. /// /// The `removeLeft`, `removeTop`, `removeRight`, and `removeBottom` arguments /// must not be null. If all four are false (the default) then the returned /// [MediaQuery] reuses the ambient [MediaQueryData] unmodified, which is not /// particularly useful. /// /// The [child] argument is required and must not be null. /// /// See also: /// /// * [MediaQueryData.viewPadding], the affected property of the /// [MediaQueryData]. /// * [removePadding], the same thing but for [MediaQueryData.padding]. /// * [removeViewInsets], the same thing but for [MediaQueryData.viewInsets]. factory MediaQuery.removeViewPadding({ Key key, @required BuildContext context, bool removeLeft = false, bool removeTop = false, bool removeRight = false, bool removeBottom = false, @required Widget child, }) { return MediaQuery( key: key, data: MediaQuery.of(context).removeViewPadding( removeLeft: removeLeft, removeTop: removeTop, removeRight: removeRight, removeBottom: removeBottom, ), child: child, ); } /// Contains information about the current media. /// /// For example, the [MediaQueryData.size] property contains the width and /// height of the current window. final MediaQueryData data; /// The data from the closest instance of this class that encloses the given /// context. /// /// You can use this function to query the size an orientation of the screen. /// When that information changes, your widget will be scheduled to be /// rebuilt, keeping your widget up-to-date. /// /// Typical usage is as follows: /// /// ```dart /// MediaQueryData media = MediaQuery.of(context); /// ``` /// /// If there is no [MediaQuery] in scope, then this will throw an exception. /// To return null if there is no [MediaQuery], then pass `nullOk: true`. /// /// If you use this from a widget (e.g. in its build function), consider /// calling [debugCheckHasMediaQuery]. static MediaQueryData of(BuildContext context, { bool nullOk = false }) { assert(context != null); assert(nullOk != null); final MediaQuery query = context.inheritFromWidgetOfExactType(MediaQuery); if (query != null) return query.data; if (nullOk) return null; throw FlutterError( 'MediaQuery.of() called with a context that does not contain a MediaQuery.\n' 'No MediaQuery ancestor could be found starting from the context that was passed ' 'to MediaQuery.of(). This can happen because you do not have a WidgetsApp or ' 'MaterialApp widget (those widgets introduce a MediaQuery), or it can happen ' 'if the context you use comes from a widget above those widgets.\n' 'The context used was:\n' ' $context' ); } /// Returns textScaleFactor for the nearest MediaQuery ancestor or 1.0, if /// no such ancestor exists. static double textScaleFactorOf(BuildContext context) { 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) { return MediaQuery.of(context, nullOk: true)?.boldText ?? false; } @override bool updateShouldNotify(MediaQuery oldWidget) => data != oldWidget.data; @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty<MediaQueryData>('data', data, showName: false)); } }