Jelajahi Sumber

[infra_ui][overlay] Impl overlay manager based on stack

Jaylen Bian 3 tahun lalu
induk
melakukan
9508ad84e4

+ 6 - 2
app_flowy/packages/flowy_infra_ui/example/lib/main.dart

@@ -1,4 +1,7 @@
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
 import 'package:flutter/material.dart';
+
 import 'home/home_screen.dart';
 
 void main() {
@@ -10,9 +13,10 @@ class ExampleApp extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return const MaterialApp(
+    return MaterialApp(
+      builder: overlayManagerBuilder(),
       title: "Flowy Infra Title",
-      home: HomeScreen(),
+      home: const HomeScreen(),
     );
   }
 }

+ 9 - 1
app_flowy/packages/flowy_infra_ui/example/lib/overlay/overlay_screen.dart

@@ -1,3 +1,4 @@
+import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
 import 'package:flutter/material.dart';
 
 import '../home/demo_item.dart';
@@ -42,7 +43,14 @@ class OverlayScreen extends StatelessWidget {
               ),
             ),
             ElevatedButton(
-              onPressed: () {},
+              onPressed: () {
+                FlowyOverlay.of(context).insert(
+                  const FlutterLogo(
+                    size: 200,
+                  ),
+                  'overlay_flutter_logo',
+                );
+              },
               child: const Text('Show Overlay'),
             ),
           ],

+ 3 - 0
app_flowy/packages/flowy_infra_ui/lib/flowy_infra_ui.dart

@@ -3,3 +3,6 @@ export 'basis.dart';
 
 // Keyboard
 export 'src/keyboard/keyboard_visibility_detector.dart';
+
+// Overlay
+export 'src/flowy_overlay/flowy_overlay.dart';

+ 3 - 0
app_flowy/packages/flowy_infra_ui/lib/flowy_infra_ui_web.dart

@@ -3,3 +3,6 @@ export 'basis.dart';
 
 // Keyboard
 export 'src/keyboard/keyboard_visibility_detector.dart';
+
+// Overlay
+export 'src/flowy_overlay/flowy_overlay.dart';

+ 157 - 0
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart

@@ -0,0 +1,157 @@
+import 'package:dartz/dartz.dart' show Tuple2;
+import 'package:flutter/material.dart';
+import 'package:flutter/scheduler.dart';
+
+/// Specifies how overlay are anchored to the SourceWidget
+enum AnchorDirection {
+  // Corner aligned with a corner of the SourceWidget
+  topLeft,
+  topRight,
+  bottomLeft,
+  bottomRight,
+
+  // Edge aligned with a edge of the SourceWidget
+  topWithLeftAligned,
+  topWithCenterAligned,
+  topWithRightAligned,
+  rightWithTopAligned,
+  rightWithCenterAligned,
+  rightWithBottomAligned,
+  bottomWithLeftAligned,
+  bottomWithCenterAligned,
+  bottomWithRightAligned,
+  leftWithTopAligned,
+  leftWithCenterAligned,
+  leftWithBottomAligned,
+
+  // Custom position
+  custom,
+}
+
+/// The behavior of overlay when user tapping system back button
+enum OnBackBehavior {
+  /// Won't handle the back action
+  none,
+
+  /// Animate to get the user's attention
+  alert,
+
+  /// Intercept the back action and abort directly
+  abort,
+
+  /// Intercept the back action and dismiss overlay
+  dismiss,
+}
+
+final GlobalKey<FlowyOverlayState> _key = GlobalKey<FlowyOverlayState>();
+
+/// Invoke this method in app generation process
+TransitionBuilder overlayManagerBuilder() {
+  return (context, child) {
+    assert(child != null, 'Child can\'t be null.');
+    return FlowyOverlay(key: _key, child: child!);
+  };
+}
+
+class FlowyOverlay extends StatefulWidget {
+  const FlowyOverlay({
+    Key? key,
+    required this.child,
+    this.barrierColor = Colors.transparent,
+  }) : super(key: key);
+
+  final Widget child;
+
+  final Color? barrierColor;
+
+  static FlowyOverlayState of(
+    BuildContext context, {
+    bool rootOverlay = false,
+  }) {
+    FlowyOverlayState? overlayManager;
+    if (rootOverlay) {
+      overlayManager = context.findRootAncestorStateOfType<FlowyOverlayState>() ?? overlayManager;
+    } else {
+      overlayManager = overlayManager ?? context.findAncestorStateOfType<FlowyOverlayState>();
+    }
+
+    assert(() {
+      if (overlayManager == null) {
+        throw FlutterError(
+          'Can\'t find overlay manager in current context, please check if already wrapped by overlay manager.',
+        );
+      }
+      return true;
+    }());
+    return overlayManager!;
+  }
+
+  static FlowyOverlayState? maybeOf(
+    BuildContext context, {
+    bool rootOverlay = false,
+  }) {
+    FlowyOverlayState? overlayManager;
+    if (rootOverlay) {
+      overlayManager = context.findRootAncestorStateOfType<FlowyOverlayState>() ?? overlayManager;
+    } else {
+      overlayManager = overlayManager ?? context.findAncestorStateOfType<FlowyOverlayState>();
+    }
+
+    return overlayManager;
+  }
+
+  @override
+  FlowyOverlayState createState() => FlowyOverlayState();
+}
+
+class FlowyOverlayState extends State<FlowyOverlay> {
+  List<Tuple2<Widget, String>> _overlayList = [];
+
+  void insert(Widget widget, String identifier) {
+    setState(() {
+      _overlayList.add(Tuple2(widget, identifier));
+    });
+  }
+
+  void remove(String identifier) {
+    setState(() {
+      _overlayList.removeWhere((ele) => ele.value2 == identifier);
+    });
+  }
+
+  void removeAll() {
+    setState(() {
+      _overlayList = [];
+    });
+  }
+
+  void _markDirty() {
+    if (mounted) {
+      setState(() {});
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final overlays = _overlayList.map((ele) => ele.value1);
+    final children = <Widget>[
+      widget.child,
+      if (overlays.isNotEmpty)
+        Container(
+          color: widget.barrierColor,
+          child: GestureDetector(
+            behavior: HitTestBehavior.opaque,
+            onTap: _handleTapOnBackground,
+          ),
+        ),
+    ];
+
+    return Stack(
+      children: children..addAll(overlays),
+    );
+  }
+
+  void _handleTapOnBackground() {
+    removeAll();
+  }
+}

+ 43 - 0
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_layout_delegate.dart

@@ -0,0 +1,43 @@
+// import 'dart:math' as math;
+// import 'dart:ui';
+
+// import 'package:flutter/material.dart';
+
+// import 'flowy_overlay.dart';
+
+// class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
+//   OverlayLayoutDelegate({
+//     required this.route,
+//     required this.padding,
+//     required this.anchorPosition,
+//     required this.anchorDirection,
+//   });
+
+//   final OverlayPannelRoute route;
+//   final EdgeInsets padding;
+//   final AnchorDirection anchorDirection;
+//   final Offset anchorPosition;
+
+//   @override
+//   bool shouldRelayout(OverlayLayoutDelegate oldDelegate) {
+//     return anchorPosition != oldDelegate.anchorPosition || anchorDirection != oldDelegate.anchorDirection;
+//   }
+
+//   @override
+//   Offset getPositionForChild(Size size, Size childSize) {
+//     // TODO: junlin - calculate child position
+//     return Offset.zero;
+//   }
+
+//   @override
+//   BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
+//     double maxHeight = math.max(0.0, constraints.maxHeight - padding.top - padding.bottom);
+//     double width = constraints.maxWidth;
+//     return BoxConstraints(
+//       minHeight: 0.0,
+//       maxHeight: maxHeight,
+//       minWidth: width,
+//       maxWidth: width,
+//     );
+//   }
+// }

+ 187 - 0
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_manager.dart

@@ -0,0 +1,187 @@
+// import 'package:flowy_infra_ui/src/overlay/overlay_basis.dart';
+// import 'package:flowy_infra_ui/src/overlay/overlay_route.dart';
+// import 'package:flutter/material.dart';
+
+// import 'overlay_hittest.dart';
+
+// final GlobalKey<OverlayManagerState> _key = GlobalKey<OverlayManagerState>();
+
+// /// Invoke this method in app generation process
+// TransitionBuilder overlayManagerBuilder() {
+//   return (context, child) {
+//     return OverlayManager(key: _key, child: child);
+//   };
+// }
+
+// class OverlayManager extends StatefulWidget {
+//   const OverlayManager({Key? key, required this.child}) : super(key: key);
+
+//   final Widget? child;
+
+//   static OverlayManagerState of(
+//     BuildContext context, {
+//     bool rootOverlay = false,
+//   }) {
+//     OverlayManagerState? overlayManager;
+//     if (rootOverlay) {
+//       overlayManager = context.findRootAncestorStateOfType<OverlayManagerState>() ?? overlayManager;
+//     } else {
+//       overlayManager = overlayManager ?? context.findAncestorStateOfType<OverlayManagerState>();
+//     }
+
+//     assert(() {
+//       if (overlayManager == null) {
+//         throw FlutterError(
+//           'Can\'t find overlay manager in current context, please check if already wrapped by overlay manager.',
+//         );
+//       }
+//       return true;
+//     }());
+//     return overlayManager!;
+//   }
+
+//   static OverlayManagerState? maybeOf(
+//     BuildContext context, {
+//     bool rootOverlay = false,
+//   }) {
+//     OverlayManagerState? overlayManager;
+//     if (rootOverlay) {
+//       overlayManager = context.findRootAncestorStateOfType<OverlayManagerState>() ?? overlayManager;
+//     } else {
+//       overlayManager = overlayManager ?? context.findAncestorStateOfType<OverlayManagerState>();
+//     }
+
+//     return overlayManager;
+//   }
+
+//   @override
+//   OverlayManagerState createState() => OverlayManagerState();
+// }
+
+// class OverlayManagerState extends State<OverlayManager> {
+//   final Map<String, Map<String, OverlayEntry>> _overlayEntrys = {};
+//   List<OverlayEntry> get _overlays => _overlayEntrys.values.fold<List<OverlayEntry>>(<OverlayEntry>[], (value, items) {
+//         return value..addAll(items.values);
+//       });
+//   OverlayPannelRoute? _overlayRoute;
+//   bool isShowingOverlayRoute = false;
+
+//   @override
+//   void initState() {
+//     super.initState();
+//     OverlayManagerNavigatorObserver.didPushCallback = _handleDidPush;
+//     OverlayManagerNavigatorObserver.didPopCallback = _handleDidPop;
+//   }
+
+//   void insert(Widget widget, String featureKey, String key) {
+//     final overlay = Overlay.of(context);
+//     assert(overlay != null);
+
+//     if (!isShowingOverlayRoute) {
+//       _showOverlayRoutePage(context: context);
+//     }
+
+//     final entry = OverlayEntry(builder: (_) => widget);
+//     _overlayEntrys[featureKey] ??= {};
+//     _overlayEntrys[featureKey]![key] = entry;
+//     overlay!.insert(entry);
+//   }
+
+//   void insertAll(List<Widget> widgets, String featureKey, List<String> keys) {
+//     assert(widgets.isNotEmpty);
+//     assert(widgets.length == keys.length);
+
+//     final overlay = Overlay.of(context);
+//     assert(overlay != null);
+
+//     List<OverlayEntry> entries = [];
+//     _overlayEntrys[featureKey] ??= {};
+//     for (int idx = 0; idx < widgets.length; idx++) {
+//       final entry = OverlayEntry(builder: (_) => widget);
+//       entries.add(entry);
+//       _overlayEntrys[featureKey]![keys[idx]] = entry;
+//     }
+//     overlay!.insertAll(entries);
+//   }
+
+//   void remove(String featureKey, String key) {
+//     if (_overlayEntrys.containsKey(featureKey)) {
+//       final entry = _overlayEntrys[featureKey]!.remove(key);
+//       entry?.remove();
+//     }
+//   }
+
+//   void removeAll(String featureKey) {
+//     if (_overlayEntrys.containsKey(featureKey)) {
+//       final entries = _overlayEntrys.remove(featureKey);
+//       entries?.forEach((_, overlay) {
+//         overlay.remove();
+//       });
+//     }
+//   }
+
+//   @override
+//   Widget build(BuildContext context) {
+//     assert(widget.child != null);
+//     return GestureDetector(
+//       behavior: _overlayEntrys.isEmpty ? HitTestBehavior.deferToChild : HitTestBehavior.opaque,
+//       onTapDown: _handleTapDown,
+//       child: widget.child,
+//     );
+//   }
+
+//   void _showOverlayRoutePage({
+//     required BuildContext context,
+//   }) {
+//     _overlayRoute = OverlayPannelRoute(
+//       barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
+//     );
+//     final navigator = Navigator.of(context);
+//     // TODO: junlin - Use Navigation Overservers
+//     navigator.push(_overlayRoute!);
+//   }
+
+//   void _handleTapDown(TapDownDetails tapDownDetails) {
+//     bool hitOnOverlay = false;
+//     _overlays.forEach((overlay) {});
+//   }
+
+//   void _handleDidPush(Route route, Route? previousRoute) {
+//     if (route is OverlayPannelRoute) {
+//       isShowingOverlayRoute = true;
+//       _showPendingOverlays();
+//     }
+//   }
+
+//   void _handleDidPop(Route route, Route? previousRoute) {
+//     if (previousRoute is OverlayPannelRoute) {
+//       isShowingOverlayRoute = false;
+//       _removeOverlays();
+//     }
+//   }
+
+//   void _showPendingOverlays() {}
+
+//   void _removeOverlays() {}
+// }
+
+// class OverlayManagerNavigatorObserver extends NavigatorObserver {
+//   static void Function(Route route, Route? previousRoute)? didPushCallback;
+//   static void Function(Route route, Route? previousRoute)? didPopCallback;
+
+//   @override
+//   void didPush(Route route, Route? previousRoute) {
+//     if (didPushCallback != null) {
+//       didPushCallback!(route, previousRoute);
+//     }
+//     super.didPush(route, previousRoute);
+//   }
+
+//   @override
+//   void didPop(Route route, Route? previousRoute) {
+//     if (didPopCallback != null) {
+//       didPopCallback!(route, previousRoute);
+//     }
+//     super.didPop(route, previousRoute);
+//   }
+// }

+ 123 - 0
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_pannel.dart

@@ -0,0 +1,123 @@
+// import 'dart:ui' show window;
+
+// import 'package:flowy_infra_ui/src/overlay/overlay_route.dart';
+// import 'package:flutter/material.dart';
+
+// import 'overlay_.dart';
+
+// class OverlayPannel extends StatefulWidget {
+//   const OverlayPannel({
+//     Key? key,
+//     this.focusNode,
+//     this.padding = EdgeInsets.zero,
+//     this.anchorDirection = AnchorDirection.topRight,
+//     required this.anchorPosition,
+//     required this.route,
+//   }) : super(key: key);
+
+//   final FocusNode? focusNode;
+//   final EdgeInsetsGeometry padding;
+//   final AnchorDirection anchorDirection;
+//   final Offset anchorPosition;
+//   final OverlayPannelRoute route;
+
+//   @override
+//   _OverlayPannelState createState() => _OverlayPannelState();
+// }
+
+// class _OverlayPannelState extends State<OverlayPannel> with WidgetsBindingObserver {
+//   FocusNode? _internalNode;
+//   FocusNode? get focusNode => widget.focusNode ?? _internalNode;
+//   late FocusHighlightMode _focusHighlightMode;
+//   bool _hasPrimaryFocus = false;
+//   late CurvedAnimation _fadeOpacity;
+//   late CurvedAnimation _resize;
+//   OverlayPannelRoute? _overlayRoute;
+
+//   @override
+//   void initState() {
+//     super.initState();
+//     _fadeOpacity = CurvedAnimation(
+//       parent: widget.route.animation!,
+//       curve: const Interval(0.0, 0.25),
+//       reverseCurve: const Interval(0.75, 1.0),
+//     );
+//     _resize = CurvedAnimation(
+//       parent: widget.route.animation!,
+//       curve: const Interval(0.25, 0.5),
+//       reverseCurve: const Threshold(0.0),
+//     );
+
+//     // TODO: junlin - handle focus action or remove it
+//     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 FadeTransition(
+//       opacity: _fadeOpacity,
+//     );
+//   }
+
+//   @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;
+//     });
+//   }
+
+//   // MARK: Layout
+
+//   Orientation _getOrientation(BuildContext context) {
+//     Orientation? result = MediaQuery.maybeOf(context)?.orientation;
+//     if (result == null) {
+//       final Size size = window.physicalSize;
+//       result = size.width > size.height ? Orientation.landscape : Orientation.portrait;
+//     }
+//     return result;
+//   }
+// }

+ 55 - 0
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_route.dart

@@ -0,0 +1,55 @@
+// import 'package:flutter/material.dart';
+
+// class _OverlayRouteResult {}
+
+// const Duration _kOverlayDuration = Duration(milliseconds: 0);
+
+// class OverlayPannelRoute extends PopupRoute<_OverlayRouteResult> {
+//   OverlayPannelRoute({
+//     this.barrierColor,
+//     required this.barrierLabel,
+//   });
+
+//   @override
+//   bool get barrierDismissible => true;
+
+//   @override
+//   Color? barrierColor;
+
+//   @override
+//   String? barrierLabel;
+
+//   @override
+//   Duration get transitionDuration => _kOverlayDuration;
+
+//   @override
+//   Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
+//     return LayoutBuilder(builder: (context, contraints) {
+//       return const _OverlayRoutePage();
+//     });
+//   }
+// }
+
+// class _OverlayRoutePage extends StatelessWidget {
+//   const _OverlayRoutePage({
+//     Key? key,
+//   }) : super(key: key);
+
+//   @override
+//   Widget build(BuildContext context) {
+//     assert(debugCheckHasDirectionality(context));
+//     final TextDirection? textDirection = Directionality.maybeOf(context);
+//     // TODO: junlin - Use overlay pannel to manage focus node
+
+//     return MediaQuery.removePadding(
+//       context: context,
+//       removeTop: true,
+//       removeBottom: true,
+//       removeLeft: true,
+//       removeRight: true,
+//       child: Container(
+//         color: Colors.blue[100],
+//       ),
+//     );
+//   }
+// }

+ 0 - 40
app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_basis.dart

@@ -1,40 +0,0 @@
-/// Specifies how overlay are anchored to the SourceWidget
-enum AnchorDirection {
-  // Corner aligned with a corner of the SourceWidget
-  topLeft,
-  topRight,
-  bottomLeft,
-  bottomRight,
-
-  // Edge aligned with a edge of the SourceWidget
-  topWithLeftAligned,
-  topWithCenterAligned,
-  topWithRightAligned,
-  rightWithTopAligned,
-  rightWithCenterAligned,
-  rightWithBottomAligned,
-  bottomWithLeftAligned,
-  bottomWithCenterAligned,
-  bottomWithRightAligned,
-  leftWithTopAligned,
-  leftWithCenterAligned,
-  leftWithBottomAligned,
-
-  // Custom position
-  custom,
-}
-
-/// The behavior of overlay when user tapping system back button
-enum OnBackBehavior {
-  /// Won't handle the back action
-  none,
-
-  /// Animate to get the user's attention
-  alert,
-
-  /// Intercept the back action and abort directly
-  abort,
-
-  /// Intercept the back action and dismiss overlay
-  dismiss,
-}

+ 0 - 22
app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_hittest.dart

@@ -1,22 +0,0 @@
-import 'dart:developer';
-
-import 'package:flutter/material.dart';
-import 'package:flutter/rendering.dart';
-
-class OverlayHitTestArea extends SingleChildRenderObjectWidget {
-  const OverlayHitTestArea({
-    Key? key,
-    Widget? child,
-  }) : super(key: key, child: child);
-
-  @override
-  RenderObject createRenderObject(BuildContext context) => RenderOverlayHitTestArea();
-}
-
-class RenderOverlayHitTestArea extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
-  @override
-  bool hitTest(BoxHitTestResult result, {required Offset position}) {
-    print('hitTesting');
-    return super.hitTest(result, position: position);
-  }
-}

+ 0 - 47
app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_layout_delegate.dart

@@ -1,47 +0,0 @@
-import 'dart:math' as math;
-import 'dart:ui';
-
-import 'package:flutter/material.dart';
-
-import 'overlay_route.dart';
-import 'overlay_basis.dart';
-
-class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
-  OverlayLayoutDelegate({
-    required this.route,
-    required this.padding,
-    required this.anchorPosition,
-    required this.anchorDirection,
-  });
-
-  final OverlayPannelRoute route;
-  final EdgeInsets padding;
-  final AnchorDirection anchorDirection;
-  final Offset anchorPosition;
-
-  @override
-  bool shouldRelayout(OverlayLayoutDelegate oldDelegate) {
-    return anchorPosition != oldDelegate.anchorPosition || anchorDirection != oldDelegate.anchorDirection;
-  }
-
-  @override
-  Offset getPositionForChild(Size size, Size childSize) {
-    // TODO: junlin - calculate child position
-    return Offset.zero;
-  }
-
-  @override
-  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
-    double maxHeight = math.max(
-      0.0,
-      math.min(route.maxHeight, constraints.maxHeight - padding.top - padding.bottom),
-    );
-    double width = math.min(route.maxWidth, constraints.maxWidth);
-    return BoxConstraints(
-      minHeight: 0.0,
-      maxHeight: maxHeight,
-      minWidth: width,
-      maxWidth: width,
-    );
-  }
-}

+ 0 - 113
app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_manager.dart

@@ -1,113 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'overlay_hittest.dart';
-
-final GlobalKey<OverlayManagerState> _key = GlobalKey<OverlayManagerState>();
-
-/// Invoke this method in app generation process
-TransitionBuilder overlayManagerBuilder() {
-  return (context, child) {
-    return OverlayManager(key: _key, child: child);
-  };
-}
-
-class OverlayManager extends StatefulWidget {
-  const OverlayManager({Key? key, required this.child}) : super(key: key);
-
-  final Widget? child;
-
-  static OverlayManagerState of(
-    BuildContext context, {
-    bool rootOverlay = false,
-  }) {
-    OverlayManagerState? overlayManager;
-    if (rootOverlay) {
-      overlayManager = context.findRootAncestorStateOfType<OverlayManagerState>() ?? overlayManager;
-    } else {
-      overlayManager = overlayManager ?? context.findAncestorStateOfType<OverlayManagerState>();
-    }
-
-    assert(() {
-      if (overlayManager == null) {
-        throw FlutterError(
-          'Can\'t find overlay manager in current context, please check if already wrapped by overlay manager.',
-        );
-      }
-      return true;
-    }());
-    return overlayManager!;
-  }
-
-  static OverlayManagerState? maybeOf(
-    BuildContext context, {
-    bool rootOverlay = false,
-  }) {
-    OverlayManagerState? overlayManager;
-    if (rootOverlay) {
-      overlayManager = context.findRootAncestorStateOfType<OverlayManagerState>() ?? overlayManager;
-    } else {
-      overlayManager = overlayManager ?? context.findAncestorStateOfType<OverlayManagerState>();
-    }
-
-    return overlayManager;
-  }
-
-  @override
-  OverlayManagerState createState() => OverlayManagerState();
-}
-
-class OverlayManagerState extends State<OverlayManager> {
-  final Map<String, Map<String, OverlayEntry>> _overlayEntrys = {};
-
-  void insert(Widget widget, String featureKey, String key) {
-    final overlay = Overlay.of(context);
-    assert(overlay != null);
-
-    final entry = OverlayEntry(builder: (_) => widget);
-    _overlayEntrys[featureKey] ??= {};
-    _overlayEntrys[featureKey]![key] = entry;
-    overlay!.insert(entry);
-  }
-
-  void insertAll(List<Widget> widgets, String featureKey, List<String> keys) {
-    assert(widgets.isNotEmpty);
-    assert(widgets.length == keys.length);
-
-    final overlay = Overlay.of(context);
-    assert(overlay != null);
-
-    List<OverlayEntry> entries = [];
-    _overlayEntrys[featureKey] ??= {};
-    for (int idx = 0; idx < widgets.length; idx++) {
-      final entry = OverlayEntry(builder: (_) => widget);
-      entries.add(entry);
-      _overlayEntrys[featureKey]![keys[idx]] = entry;
-    }
-    overlay!.insertAll(entries);
-  }
-
-  void remove(String featureKey, String key) {
-    if (_overlayEntrys.containsKey(featureKey)) {
-      final entry = _overlayEntrys[featureKey]!.remove(key);
-      entry?.remove();
-    }
-  }
-
-  void removeAll(String featureKey) {
-    if (_overlayEntrys.containsKey(featureKey)) {
-      final entries = _overlayEntrys.remove(featureKey);
-      entries?.forEach((_, overlay) {
-        overlay.remove();
-      });
-    }
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    assert(widget.child != null);
-    return GestureDetector(
-      behavior: HitTestBehavior.translucent,
-      child: OverlayHitTestArea(child: widget.child),
-    );
-  }
-}

+ 0 - 124
app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_pannel.dart

@@ -1,124 +0,0 @@
-import 'dart:ui' show window;
-
-import 'package:flowy_infra_ui/src/overlay/overlay_route.dart';
-import 'package:flutter/material.dart';
-
-import 'overlay_basis.dart';
-
-class OverlayPannel extends StatefulWidget {
-  const OverlayPannel({
-    Key? key,
-    this.focusNode,
-    this.padding = EdgeInsets.zero,
-    this.anchorDirection = AnchorDirection.topRight,
-    required this.anchorPosition,
-    required this.route,
-  }) : super(key: key);
-
-  final FocusNode? focusNode;
-  final EdgeInsetsGeometry padding;
-  final AnchorDirection anchorDirection;
-  final Offset anchorPosition;
-  final OverlayPannelRoute route;
-
-  @override
-  _OverlayPannelState createState() => _OverlayPannelState();
-}
-
-class _OverlayPannelState extends State<OverlayPannel> with WidgetsBindingObserver {
-  FocusNode? _internalNode;
-  FocusNode? get focusNode => widget.focusNode ?? _internalNode;
-  late FocusHighlightMode _focusHighlightMode;
-  bool _hasPrimaryFocus = false;
-  late CurvedAnimation _fadeOpacity;
-  late CurvedAnimation _resize;
-  OverlayPannelRoute? _overlayRoute;
-
-  @override
-  void initState() {
-    super.initState();
-    _fadeOpacity = CurvedAnimation(
-      parent: widget.route.animation!,
-      curve: const Interval(0.0, 0.25),
-      reverseCurve: const Interval(0.75, 1.0),
-    );
-    _resize = CurvedAnimation(
-      parent: widget.route.animation!,
-      curve: const Interval(0.25, 0.5),
-      reverseCurve: const Threshold(0.0),
-    );
-
-    // TODO: junlin - handle focus action or remove it
-    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 FadeTransition(
-      opacity: _fadeOpacity,
-      child: widget.route.widgetBuilder(context),
-    );
-  }
-
-  @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;
-    });
-  }
-
-  // MARK: Layout
-
-  Orientation _getOrientation(BuildContext context) {
-    Orientation? result = MediaQuery.maybeOf(context)?.orientation;
-    if (result == null) {
-      final Size size = window.physicalSize;
-      result = size.width > size.height ? Orientation.landscape : Orientation.portrait;
-    }
-    return result;
-  }
-}

+ 0 - 98
app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_route.dart

@@ -1,98 +0,0 @@
-import 'package:flowy_infra_ui/src/overlay/overlay_pannel.dart';
-import 'package:flutter/material.dart';
-
-import 'overlay_basis.dart';
-import 'overlay_layout_delegate.dart';
-
-class _OverlayRouteResult {}
-
-const Duration _kOverlayDurationDuration = Duration(milliseconds: 500);
-
-class OverlayPannelRoute extends PopupRoute<_OverlayRouteResult> {
-  final EdgeInsetsGeometry padding;
-  final AnchorDirection anchorDirection;
-  final Offset anchorPosition;
-  final double maxWidth;
-  final double maxHeight;
-  final WidgetBuilder widgetBuilder;
-
-  OverlayPannelRoute({
-    this.padding = EdgeInsets.zero,
-    required this.anchorDirection,
-    this.barrierColor,
-    required this.barrierLabel,
-    required this.anchorPosition,
-    required this.maxWidth,
-    required this.maxHeight,
-    required this.widgetBuilder,
-  });
-
-  @override
-  bool get barrierDismissible => true;
-
-  @override
-  Color? barrierColor;
-
-  @override
-  String? barrierLabel;
-
-  @override
-  Duration get transitionDuration => _kOverlayDurationDuration;
-
-  @override
-  Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
-    return LayoutBuilder(builder: (context, contraints) {
-      return _OverlayRoutePage(
-        route: this,
-        anchorDirection: anchorDirection,
-        anchorPosition: anchorPosition,
-      );
-    });
-  }
-}
-
-class _OverlayRoutePage extends StatelessWidget {
-  const _OverlayRoutePage({
-    Key? key,
-    required this.route,
-    this.padding = EdgeInsets.zero,
-    required this.anchorDirection,
-    required this.anchorPosition,
-  }) : super(key: key);
-
-  final OverlayPannelRoute route;
-  final EdgeInsetsGeometry padding;
-  final AnchorDirection anchorDirection;
-  final Offset anchorPosition;
-
-  @override
-  Widget build(BuildContext context) {
-    assert(debugCheckHasDirectionality(context));
-    final TextDirection? textDirection = Directionality.maybeOf(context);
-    final OverlayPannel overlayPannel = OverlayPannel(
-      route: route,
-      padding: padding,
-      anchorDirection: anchorDirection,
-      anchorPosition: anchorPosition,
-    );
-
-    return MediaQuery.removePadding(
-      context: context,
-      removeTop: true,
-      removeBottom: true,
-      removeLeft: true,
-      removeRight: true,
-      child: Builder(
-        builder: (context) => CustomSingleChildLayout(
-          delegate: OverlayLayoutDelegate(
-            route: route,
-            padding: padding.resolve(textDirection),
-            anchorPosition: anchorPosition,
-            anchorDirection: anchorDirection,
-          ),
-          child: overlayPannel,
-        ),
-      ),
-    );
-  }
-}