Browse Source

[infra_ui][overlay] (WIP) Temp submit before refactor

Jaylen Bian 3 years ago
parent
commit
7efbf03030

+ 3 - 0
app_flowy/packages/flowy_infra_ui/example/lib/home/home_screen.dart

@@ -1,4 +1,6 @@
 import 'package:flutter/material.dart';
+
+import '../overlay/overlay_screen.dart';
 import '../keyboard/keyboard_screen.dart';
 import 'demo_item.dart';
 
@@ -8,6 +10,7 @@ class HomeScreen extends StatelessWidget {
   static List<ListItem> items = [
     SectionHeaderItem('Widget Demos'),
     KeyboardItem(),
+    OverlayItem(),
   ];
 
   @override

+ 51 - 0
app_flowy/packages/flowy_infra_ui/example/lib/overlay/overlay_screen.dart

@@ -0,0 +1,51 @@
+import 'package:flutter/material.dart';
+
+import '../home/demo_item.dart';
+
+class OverlayItem extends DemoItem {
+  @override
+  String buildTitle() => 'Overlay';
+
+  @override
+  void handleTap(BuildContext context) {
+    Navigator.of(context).push(
+      MaterialPageRoute(
+        builder: (context) {
+          return const OverlayScreen();
+        },
+      ),
+    );
+  }
+}
+
+class OverlayScreen extends StatelessWidget {
+  const OverlayScreen({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+        appBar: AppBar(
+          title: const Text('Overlay Demo'),
+        ),
+        body: Column(
+          children: [
+            Flexible(
+              child: Padding(
+                padding: const EdgeInsets.all(16.0),
+                child: Container(
+                  height: 300.0,
+                  decoration: BoxDecoration(
+                    borderRadius: BorderRadius.circular(15.0),
+                    color: Colors.grey[200],
+                  ),
+                ),
+              ),
+            ),
+            ElevatedButton(
+              onPressed: () {},
+              child: const Text('Show Overlay'),
+            ),
+          ],
+        ));
+  }
+}

+ 5 - 0
app_flowy/packages/flowy_infra_ui/lib/basis.dart

@@ -0,0 +1,5 @@
+import 'package:flutter/material.dart';
+
+// MARK: - Shared Builder
+
+typedef WidgetBuilder = Widget Function();

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

@@ -1,2 +1,5 @@
+// Basis
+export 'basis.dart';
+
 // Keyboard
 export 'src/keyboard/keyboard_visibility_detector.dart';

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

@@ -1,2 +1,5 @@
+// Basis
+export 'basis.dart';
+
 // Keyboard
 export 'src/keyboard/keyboard_visibility_detector.dart';

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

@@ -1,5 +1,3 @@
-import 'package:flutter/material.dart';
-
 /// Specifies how overlay are anchored to the SourceWidget
 enum AnchorDirection {
   // Corner aligned with a corner of the SourceWidget

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

@@ -0,0 +1,50 @@
+import 'dart:ui';
+
+import 'package:flutter/material.dart';
+import 'overlay_basis.dart';
+
+class OverlayLayoutDelegate extends SingleChildLayoutDelegate {
+  OverlayLayoutDelegate({
+    required this.anchorRect,
+    required this.targetRect,
+    required this.anchorDirection,
+    required this.safeAreaEnabled,
+    required this.insets,
+  });
+
+  final AnchorDirection anchorDirection;
+  final bool safeAreaEnabled;
+  final EdgeInsets insets;
+  final Rect anchorRect;
+  final Rect targetRect;
+
+  @override
+  bool shouldRelayout(OverlayLayoutDelegate oldDelegate) {
+    return anchorRect != oldDelegate.anchorRect ||
+        insets != oldDelegate.insets ||
+        safeAreaEnabled != oldDelegate.safeAreaEnabled ||
+        anchorDirection != oldDelegate.anchorDirection;
+  }
+
+  @override
+  Offset getPositionForChild(Size size, Size childSize) {
+    // calculate the pannel maximum available rect
+    var pannelRect = Rect.fromLTWH(0, 0, size.width, size.height);
+    pannelRect = insets.deflateRect(pannelRect);
+    // apply safearea
+    if (safeAreaEnabled) {
+      final safeArea = MediaQueryData.fromWindow(window).padding;
+      pannelRect = safeArea.deflateRect(pannelRect);
+    }
+
+    // clip pannel rect
+
+    // TODO: junlin - calculate child position
+    return Offset.zero;
+  }
+
+  @override
+  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
+    return constraints.loosen();
+  }
+}

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

@@ -0,0 +1,52 @@
+import 'package:flutter/material.dart';
+
+class OverlayManager extends StatefulWidget {
+  const OverlayManager({Key? key}) : super(key: key);
+
+  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> {
+  @override
+  Widget build(BuildContext context) {
+    Navigator.of(context, rootNavigator: true);
+    return Container();
+  }
+}

+ 22 - 28
app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_pannel.dart

@@ -1,43 +1,37 @@
-import 'dart:ui';
-
 import 'package:flutter/material.dart';
+
 import 'overlay_basis.dart';
+import 'overlay_layout_delegate.dart';
 
-class OverlayPannel extends SingleChildLayoutDelegate {
-  OverlayPannel({
+class OverlayPannel extends StatelessWidget {
+  const OverlayPannel({
+    Key? key,
+    required this.child,
     required this.targetRect,
+    required this.anchorRect,
+    this.safeAreaEnabled = true,
     this.anchorDirection = AnchorDirection.topRight,
-    this.safeAreaEnabled = false,
     this.insets = EdgeInsets.zero,
-  });
+  }) : super(key: key);
 
   final AnchorDirection anchorDirection;
   final bool safeAreaEnabled;
   final EdgeInsets insets;
   final Rect targetRect;
+  final Rect anchorRect;
+  final Widget child;
 
   @override
-  bool shouldRelayout(OverlayPannel oldDelegate) {
-    return targetRect != oldDelegate.targetRect ||
-        insets != oldDelegate.insets ||
-        safeAreaEnabled != oldDelegate.safeAreaEnabled ||
-        anchorDirection != oldDelegate.anchorDirection;
-  }
-
-  @override
-  Offset getPositionForChild(Size size, Size childSize) {
-    var pannelRect = targetRect;
-    if (safeAreaEnabled) {
-      final safeArea = MediaQueryData.fromWindow(window).padding;
-      pannelRect = safeArea.deflateRect(pannelRect);
-    }
-
-    // TODO: junlin - calculate child position
-    return Offset.zero;
-  }
-
-  @override
-  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
-    return constraints.loosen();
+  Widget build(BuildContext context) {
+    return CustomSingleChildLayout(
+      delegate: OverlayLayoutDelegate(
+        targetRect: targetRect,
+        anchorRect: anchorRect,
+        safeAreaEnabled: safeAreaEnabled,
+        anchorDirection: anchorDirection,
+        insets: insets,
+      ),
+      child: child,
+    );
   }
 }

+ 0 - 15
app_flowy/packages/flowy_infra_ui/lib/src/overlay/overlay_widget.dart

@@ -1,15 +0,0 @@
-import 'package:flutter/material.dart';
-
-class Overlay extends StatelessWidget {
-  const Overlay({
-    Key? key,
-    this.safeAreaEnabled = true,
-  }) : super(key: key);
-
-  final bool safeAreaEnabled;
-
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}

+ 2 - 6
app_flowy/packages/flowy_infra_ui/lib/widget/mouse_hover_builder.dart

@@ -6,9 +6,7 @@ typedef HoverBuilder = Widget Function(BuildContext context, bool isHovering);
 class MouseHoverBuilder extends StatefulWidget {
   final bool isClickable;
 
-  const MouseHoverBuilder(
-      {Key? key, required this.builder, this.isClickable = false})
-      : super(key: key);
+  const MouseHoverBuilder({Key? key, required this.builder, this.isClickable = false}) : super(key: key);
 
   final HoverBuilder builder;
 
@@ -22,9 +20,7 @@ class _MouseHoverBuilderState extends State<MouseHoverBuilder> {
   @override
   Widget build(BuildContext context) {
     return MouseRegion(
-      cursor: widget.isClickable
-          ? SystemMouseCursors.click
-          : SystemMouseCursors.basic,
+      cursor: widget.isClickable ? SystemMouseCursors.click : SystemMouseCursors.basic,
       onEnter: (p) => setOver(true),
       onExit: (p) => setOver(false),
       child: widget.builder(context, isOver),