Skip to content

Commit

Permalink
feat: implemented WindowSize scope (#362)
Browse files Browse the repository at this point in the history
  • Loading branch information
hawkkiller authored Aug 19, 2024
1 parent dbee78d commit 5ff9877
Showing 1 changed file with 97 additions and 3 deletions.
100 changes: 97 additions & 3 deletions lib/src/core/utils/layout/window_size.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

/// A breakpoint that is used to determine the layout of the application.
///
/// It follows the Material Design guidelines for breakpoints.
Expand Down Expand Up @@ -55,15 +58,15 @@ enum WindowSize {

/// Returns whether the given width isless than
/// the minimum width of the breakpoint.
bool operator <(WindowSize other) => max < other.min;
bool operator <(WindowSize other) => min < other.min;

/// Returns whether the given width is greater than
/// the maximum width of the breakpoint.
bool operator >(WindowSize other) => min > other.max;
bool operator >(WindowSize other) => min > other.min;

/// Returns whether the given width is less than
/// or equal to the maximum width of the breakpoint.
bool operator <=(WindowSize other) => max <= other.max;
bool operator <=(WindowSize other) => min <= other.min;

/// Returns whether the given width is greater than
/// or equal to the minimum width of the breakpoint.
Expand All @@ -72,17 +75,108 @@ enum WindowSize {
/// If the breakpoint is compact.
bool get isCompact => this == WindowSize.compact;

/// If the breakpoint is compact or larger.
bool get isCompactUp => this >= WindowSize.compact;

/// If the breakpoint is medium.
bool get isMedium => this == WindowSize.medium;

/// If the breakpoint is medium or larger.
bool get isMediumUp => this >= WindowSize.medium;

/// If the breakpoint is expanded.
bool get isExpanded => this == WindowSize.expanded;

/// If the breakpoint is expanded or larger.
bool get isExpandedUp => this >= WindowSize.expanded;

/// If the breakpoint is large.
bool get isLarge => this == WindowSize.large;

/// If the breakpoint is large or larger.
bool get isLargeUp => this >= WindowSize.large;

/// If the breakpoint is extra-large.
bool get isExtraLarge => this == WindowSize.extraLarge;

/// If the breakpoint is extra-large or larger.
bool get isExtraLargeUp => this >= WindowSize.extraLarge;

const WindowSize._(this.min, this.max);
}

/// Scope that provides [WindowSize] to its descendants.
class WindowSizeScope extends StatefulWidget {
/// Creates a [WindowSizeScope] that provides [WindowSize] to its descendants.
const WindowSizeScope({
required this.child,
super.key,
});

/// The widget below this widget in the tree.
final Widget child;

/// Returns the [WindowSize] of the nearest [WindowSizeScope] ancestor.
static WindowSize of(BuildContext context, {bool listen = true}) {
final inherited = listen
? context.dependOnInheritedWidgetOfExactType<_InheritedWindowSize>()
: context.findAncestorWidgetOfExactType<_InheritedWindowSize>();

return inherited?.windowSize ??
(throw FlutterError('WindowSizeScope was not found in the widget tree'));
}

@override
State<WindowSizeScope> createState() => _WindowSizeScopeState();
}

class _WindowSizeScopeState extends State<WindowSizeScope> with WidgetsBindingObserver {
late WindowSize _windowSize;

Size _getScreenSize() {
final view = PlatformDispatcher.instance.views.first;
return view.physicalSize / view.devicePixelRatio;
}

@override
void initState() {
_windowSize = WindowSize.fromWidth(_getScreenSize().width);
WidgetsBinding.instance.addObserver(this);
super.initState();
}

@override
void didChangeMetrics() {
final windowSize = WindowSize.fromWidth(_getScreenSize().width);

if (_windowSize != windowSize) {
setState(() => _windowSize = windowSize);
}
super.didChangeMetrics();
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
Widget build(BuildContext context) => _InheritedWindowSize(
windowSize: _windowSize,
child: widget.child,
);
}

class _InheritedWindowSize extends InheritedWidget {
const _InheritedWindowSize({
required this.windowSize,
required super.child,
});

/// The [WindowSize] provided by this scope.
final WindowSize windowSize;

@override
bool updateShouldNotify(_InheritedWindowSize oldWidget) => windowSize != oldWidget.windowSize;
}

0 comments on commit 5ff9877

Please sign in to comment.