Skip to content

Commit

Permalink
feat: Close Flyouts when window metrics change
Browse files Browse the repository at this point in the history
  • Loading branch information
bdlukaa committed Feb 1, 2025
1 parent 7533f8e commit 72600eb
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 18 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
- fix: Jitter when displaying flyouts and sub flyouts ([#1014](https://github.com/bdlukaa/fluent_ui/issues/1014))
- fix: Menu sub items have the same transition as their parents ([#1178](https://github.com/bdlukaa/fluent_ui/pull/1178))
- feat: Implemented [`MenuBar`](https://bdlukaa.github.io/fluent_ui/#/surfaces/menu_bar) ([#1107](https://github.com/bdlukaa/fluent_ui/issues/1107))
- `SubItemShowBehavior` was renamed to `SubItemShowAction` ([#1178](https://github.com/bdlukaa/fluent_ui/pull/1178))
- chore: `SubItemShowBehavior` was renamed to `SubItemShowAction` ([#1178](https://github.com/bdlukaa/fluent_ui/pull/1178))
- feat: Flyouts are closed when the window size changes ([#1178](https://github.com/bdlukaa/fluent_ui/pull/1178))
- feat: Added `CommandBarButton.closeAfterClick` ([#1149](https://github.com/bdlukaa/fluent_ui/issues/1149))
- fix: `CommandBar` secondary menu preferred placement mode ([#1174](https://github.com/bdlukaa/fluent_ui/pull/1174))
- feat: `CommandBarState` is now accessible, making it possible to open/close the secondary flyout programmatically ([#1174](https://github.com/bdlukaa/fluent_ui/pull/1174))
Expand Down
70 changes: 53 additions & 17 deletions lib/src/controls/flyouts/flyout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -449,9 +449,12 @@ typedef FlyoutTransitionBuilder = Widget Function(
);

/// Controls the state of a flyout
class FlyoutController with ChangeNotifier {
class FlyoutController with ChangeNotifier, WidgetsBindingObserver {
FlyoutController() {
WidgetsBinding.instance.addObserver(this);
}

_FlyoutTargetState? _attachState;
bool _open = false;

/// Whether this flyout controller is attached to any [FlyoutTarget]
bool get isAttached => _attachState != null;
Expand Down Expand Up @@ -489,7 +492,16 @@ class FlyoutController with ChangeNotifier {
/// See also:
///
/// * [showFlyout], which opens the flyout
bool get isOpen => _open;
bool get isOpen => _route != null;

PageRouteBuilder? _route;

/// Make sure the flyout is open.
void _ensureOpen() {
assert(isOpen, 'The flyout must be open');
}

NavigatorState? _currentNavigator;

/// Shows a flyout.
///
Expand Down Expand Up @@ -597,13 +609,14 @@ class FlyoutController with ChangeNotifier {
transitionDuration ??= theme.fastAnimationDuration;
reverseTransitionDuration ??= transitionDuration;

final navigator = navigatorKey ?? Navigator.of(context);
_currentNavigator = navigatorKey ?? Navigator.of(context);

final Offset targetOffset;
final Size targetSize;
final Rect targetRect;

final navigatorBox = navigator.context.findRenderObject() as RenderBox;
final navigatorBox =
_currentNavigator!.context.findRenderObject() as RenderBox;

final targetBox = context.findRenderObject() as RenderBox;
targetSize = targetBox.size;
Expand All @@ -618,12 +631,8 @@ class FlyoutController with ChangeNotifier {
) &
targetSize;

_open = true;
notifyListeners();

final flyoutKey = GlobalKey();

final result = await navigator.push<T>(PageRouteBuilder<T>(
_route = PageRouteBuilder<T>(
opaque: false,
transitionDuration: transitionDuration,
reverseTransitionDuration: reverseTransitionDuration,
Expand Down Expand Up @@ -659,7 +668,7 @@ class FlyoutController with ChangeNotifier {
};

return _FlyoutPage(
navigator: navigator,
navigator: _currentNavigator!,
targetRect: targetRect,
attachState: _attachState,
targetOffset: targetOffset,
Expand All @@ -686,9 +695,12 @@ class FlyoutController with ChangeNotifier {
buildTarget: buildTarget,
);
},
));
);
notifyListeners();
final result =
await _currentNavigator!.push<T>(_route! as PageRouteBuilder<T>);

_open = false;
_route = _currentNavigator = null;
notifyListeners();

return result;
Expand All @@ -697,11 +709,35 @@ class FlyoutController with ChangeNotifier {
/// Closes the flyout.
///
/// The flyout must be open, otherwise an error is thrown.
void close() {
///
/// If any other route is pushed above the Flyout, this route is likely to
/// be closed. It is a good practice to close the flyout before pushing new
/// routes.
///
/// If [force] is true, the flyout is removed from the navigator stack without
/// completing the transition.
void close([bool force = false]) {
_ensureAttached();
assert(_open);
if (!_open) return; // safe for release
Navigator.of(_attachState!.context).pop();
_ensureOpen();
if (_route == null) return; // safe for release
if (force) {
_currentNavigator!.removeRoute(_route!);
} else {
_currentNavigator!.maybePop();
}

_route = _currentNavigator = null;
}

@override
void didChangeMetrics() {
if (isOpen) close();
}

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

Expand Down

0 comments on commit 72600eb

Please sign in to comment.