diff --git a/app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_pannel.dart b/app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_pannel.dart index c82efa9976..2317d54dfb 100644 --- a/app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_pannel.dart +++ b/app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_pannel.dart @@ -1,37 +1,104 @@ +import 'dart:ui' show window; + import 'package:flutter/material.dart'; import 'overlay_basis.dart'; import 'overlay_layout_delegate.dart'; -class OverlayPannel extends StatelessWidget { +class OverlayPannel extends StatefulWidget { const OverlayPannel({ Key? key, - required this.child, - required this.targetRect, - required this.anchorRect, - this.safeAreaEnabled = true, - this.anchorDirection = AnchorDirection.topRight, - this.insets = EdgeInsets.zero, + this.focusNode, }) : super(key: key); - final AnchorDirection anchorDirection; - final bool safeAreaEnabled; - final EdgeInsets insets; - final Rect targetRect; - final Rect anchorRect; - final Widget child; + final FocusNode? focusNode; + + @override + _OverlayPannelState createState() => _OverlayPannelState(); +} + +class _OverlayPannelState extends State with WidgetsBindingObserver { + FocusNode? _internalNode; + FocusNode? get focusNode => widget.focusNode ?? _internalNode; + late FocusHighlightMode _focusHighlightMode; + bool _hasPrimaryFocus = false; + + @override + void initState() { + super.initState(); + if (widget.focusNode == null) { + _internalNode ??= _createFocusNode(); + } + focusNode!.addListener(_handleFocusChanged); + final FocusManager focusManager = WidgetsBinding.instance!.focusManager; + _focusHighlightMode = focusManager.highlightMode; + focusManager.addHighlightModeListener(_handleFocusHighlightModeChanged); + } + + @override + void dispose() { + WidgetsBinding.instance!.removeObserver(this); + focusNode!.removeListener(_handleFocusChanged); + WidgetsBinding.instance!.focusManager.removeHighlightModeListener(_handleFocusHighlightModeChanged); + _internalNode?.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { - return CustomSingleChildLayout( - delegate: OverlayLayoutDelegate( - targetRect: targetRect, - anchorRect: anchorRect, - safeAreaEnabled: safeAreaEnabled, - anchorDirection: anchorDirection, - insets: insets, - ), - child: child, - ); + return Container(); + } + + @override + void didUpdateWidget(OverlayPannel oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.focusNode != oldWidget.focusNode) { + oldWidget.focusNode?.removeListener(_handleFocusChanged); + if (widget.focusNode == null) { + _internalNode ??= _createFocusNode(); + } + _hasPrimaryFocus = focusNode!.hasPrimaryFocus; + focusNode!.addListener(_handleFocusChanged); + } + } + + // MARK: Focus & Route + + FocusNode _createFocusNode() { + return FocusNode(debugLabel: '${widget.runtimeType}'); + } + + void _handleFocusChanged() { + if (_hasPrimaryFocus != focusNode!.hasPrimaryFocus) { + setState(() { + _hasPrimaryFocus = focusNode!.hasPrimaryFocus; + }); + } + } + + void _handleFocusHighlightModeChanged(FocusHighlightMode mode) { + if (!mounted) { + return; + } + setState(() { + _focusHighlightMode = mode; + }); + } + + void _removeOverlayRoute() { + // TODO: junlin + } + + // MARK: Layout + + Orientation _getOrientation(BuildContext context) { + Orientation? result = MediaQuery.maybeOf(context)?.orientation; + if (result == null) { + // If there's no MediaQuery, then use the window aspect to determine + // orientation. + final Size size = window.physicalSize; + result = size.width > size.height ? Orientation.landscape : Orientation.portrait; + } + return result; } }