Created
December 28, 2025 18:36
-
-
Save fredgrott/44e5804a0c058f815231b6dd57630a98 to your computer and use it in GitHub Desktop.
window width
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Copyright 2025 Fredrick Allan Grott. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // | |
| // Modified from window_size_classes package by Yuna | |
| // Copyright 2025 under GNU LGPL 3.0 | |
| import 'package:flutter/widgets.dart'; | |
| import 'package:material_expressive_collection/src/adaptive/breakpoints.dart'; | |
| import 'package:meta/meta.dart'; | |
| /// Opinionated set of horizontal viewport breakpoints. | |
| /// | |
| /// ```dart | |
| /// final windowWidth = WindowWidth.of(context); | |
| /// | |
| /// return switch (widthClass) { | |
| /// WindowWidth.compact => CompactLayout(), | |
| /// WindowWidth.medium => MediumLayout(), | |
| /// WindowWidth.expanded => ExpandedLayout(), | |
| /// _ => LargeLayout(), // large and extraLarge | |
| /// }; | |
| /// ``` | |
| /// | |
| /// See also: | |
| /// | |
| /// * <https://m3.material.io/foundations/layout/applying-layout/window-size-classes> | |
| /// * [WindowHeight], for height-based classifications. | |
| /// * [FlutterView view.of(this).size], which provides the window dimensions. | |
| enum WindowWidth implements Comparable<WindowWidth> { | |
| /// Compact window width. | |
| /// | |
| /// Applies to windows with width less than [mediumWidthBreakpoint] (600 | |
| /// logical pixels). | |
| /// | |
| /// Common devices: | |
| /// | |
| /// - Phone in portrait | |
| /// | |
| /// See also: | |
| /// | |
| /// * <https://m3.material.io/foundations/layout/applying-layout/compact> | |
| compact(spacing: 16), | |
| /// Medium window width. | |
| /// | |
| /// Applies to windows with width of at least [mediumWidthBreakpoint] | |
| /// (600 logical pixels) and less than [expandedWidthBreakpoint] (840 | |
| /// logical pixels). | |
| /// | |
| /// Common devices: | |
| /// | |
| /// - Tablet in portrait | |
| /// - Foldable in portrait (unfolded) | |
| /// | |
| /// See also: | |
| /// | |
| /// * <https://m3.material.io/foundations/layout/applying-layout/medium> | |
| medium(spacing: 24), | |
| /// Expanded window width. | |
| /// | |
| /// Applies to windows with a width of at least [expandedWidthBreakpoint] | |
| /// (840 logical pixels) and less than [largeWidthBreakpoint] (1200 logical | |
| /// pixels). Enables multi-column layouts, side-by-side content, and expanded | |
| /// navigation patterns that take advantage of additional horizontal real | |
| /// estate. | |
| /// | |
| /// Common devices: | |
| /// | |
| /// - Phone in landscape | |
| /// - Tablet in landscape | |
| /// - Foldable in landscape (unfolded) | |
| /// - Desktop | |
| /// | |
| /// See also: | |
| /// | |
| /// * <https://m3.material.io/foundations/layout/applying-layout/expanded> | |
| expanded(spacing: 24), | |
| /// Large window width. | |
| /// | |
| /// Applies to windows with a width of at least [largeWidthBreakpoint] | |
| /// (1200 logical pixels) and less than [extraLargeWidthBreakpoint] | |
| /// (1600 logical pixels). Includes a [fixedPaneWidth] of 360.0 to maintain | |
| /// optimal content organization and reading lengths despite the generous | |
| /// horizontal space available. | |
| /// | |
| /// Common devices: | |
| /// | |
| /// - Desktop | |
| /// | |
| /// See also: | |
| /// | |
| /// * <https://m3.material.io/foundations/layout/applying-layout/large-extra-large> | |
| large(spacing: 24, fixedPaneWidth: 360), | |
| /// Extra large window width. | |
| /// | |
| /// Applies to windows with width of [extraLargeWidthBreakpoint] (1600 | |
| /// logical pixels) or more. | |
| /// Features a larger [fixedPaneWidth] of 412.0 logical pixels to maintain | |
| /// readable content proportions and prevent over-stretching of content | |
| /// across very wide horizontal spaces. | |
| /// | |
| /// Common devices: | |
| /// | |
| /// - Desktop | |
| /// - Ultra-wide | |
| /// | |
| /// See also: | |
| /// | |
| /// * <https://m3.material.io/foundations/layout/applying-layout/large-extra-large> | |
| extraLarge(spacing: 24, fixedPaneWidth: 412); | |
| /// Creates a window width class with the given [spacing] and optional | |
| /// [fixedPaneWidth]. | |
| const WindowWidth({required this.spacing, this.fixedPaneWidth}); | |
| /// Value used for layout margin and pane spacing. | |
| final double spacing; | |
| /// The fixed pane width for [large] and [extraLarge] width classes. | |
| /// | |
| /// When not null, this value suggests a width for fixed panes. | |
| final double? fixedPaneWidth; | |
| /// Returns the [WindowWidth] for the current screen width. | |
| /// | |
| /// Retrieves the screen width from [MediaQuery] and determines the | |
| /// appropriate [WindowWidth] based on the Material Design 3 breakpoints. | |
| /// | |
| /// The [context] must have a [MediaQuery] ancestor. | |
| /// | |
| /// ```dart | |
| /// Widget build(BuildContext context) { | |
| /// final windowWidth = WindowWidth.of(context); | |
| /// // Use width to adapt your layout... | |
| /// } | |
| /// ``` | |
| @useResult | |
| @pragma('vm:prefer-inline') | |
| static WindowWidth of(BuildContext context) { | |
| // changed from MediaQuery.sizeOf(context).width | |
| // for foldables | |
| return fromWidth(View.of(context).display.size.width); | |
| } | |
| /// Returns the [WindowWidth] for the given [width] value. | |
| /// | |
| /// The [width] parameter should be in logical pixels. | |
| /// This method applies Material Design 3 breakpoint logic to | |
| /// determine the appropriate width class. | |
| /// | |
| /// ```dart | |
| /// final windowWidth = WindowWidth.fromWidth(800); // Returns medium | |
| /// final windowWidth = WindowWidth.fromWidth(1400); // Returns large | |
| /// ``` | |
| @useResult | |
| static WindowWidth fromWidth(num width) { | |
| return switch (width) { | |
| >= extraLargeWidthBreakpoint => WindowWidth.extraLarge, | |
| >= largeWidthBreakpoint => WindowWidth.large, | |
| >= expandedWidthBreakpoint => WindowWidth.expanded, | |
| >= mediumWidthBreakpoint => WindowWidth.medium, | |
| _ => WindowWidth.compact, | |
| }; | |
| } | |
| /// Whether this height is smaller than [other]. | |
| /// | |
| /// Returns `true` if this height class is smaller than [other]. | |
| /// Returns `false` if this height class is greater than or equal to [other]. | |
| bool operator <(WindowWidth other) => index < other.index; | |
| /// Whether this height class is smaller than or equal to [other]. | |
| /// | |
| /// Returns `true` if this height class is smaller than or equal to [other]. | |
| /// Returns `false` if this height class is greater than [other]. | |
| bool operator <=(WindowWidth other) => index <= other.index; | |
| /// Whether this height is greater than [other]. | |
| /// | |
| /// Returns `true` if this height class is greater than [other]. | |
| /// Returns `false` if this height class is smaller than or equal to [other]. | |
| bool operator >(WindowWidth other) => index > other.index; | |
| /// Whether this height is greater than or equal to [other]. | |
| /// | |
| /// Returns `true` if this height is greater than or equal to [other]. | |
| /// Returns `false` if this height is smaller than [other]. | |
| bool operator >=(WindowWidth other) => index >= other.index; | |
| /// Compares this [WindowWidth] to [other]. | |
| /// | |
| /// Returns a negative integer if this [WindowWidth] represents a smaller | |
| /// width than [other], zero if they represent the same width class, or a | |
| /// positive integer if this [WindowWidth] represents a larger width than | |
| /// [other]. | |
| @override | |
| @pragma('dart2js:tryInline') | |
| @pragma('vm:prefer-inline') | |
| @pragma('wasm:prefer-inline') | |
| int compareTo(WindowWidth other) => index.compareTo(other.index); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment