瀏覽代碼

[flutter]:enable add doc with FlowyOverlay

appflowy 3 年之前
父節點
當前提交
4afbe62475

+ 4 - 1
app_flowy/lib/startup/tasks/application_task.dart

@@ -20,6 +20,8 @@ class AppWidgetTask extends LaunchTask {
   }
 }
 
+final GlobalKey<FlowyOverlayState> _key = GlobalKey<FlowyOverlayState>();
+
 class ApplicationWidget extends StatelessWidget {
   final Widget child;
   const ApplicationWidget({
@@ -36,10 +38,11 @@ class ApplicationWidget extends StatelessWidget {
     setWindowFrame(const Rect.fromLTRB(0, 0, launchWidth, launchWidth / ratio));
 
     final theme = AppTheme.fromType(ThemeType.light);
+    FlowyOverlayConfig config = FlowyOverlayConfig(barrierColor: theme.bg3.withOpacity(0.3));
     return Provider.value(
         value: theme,
         child: MaterialApp(
-          builder: overlayManagerBuilder(),
+          builder: overlayManagerBuilder(config: config),
           debugShowCheckedModeBanner: false,
           theme: theme.themeData,
           navigatorKey: AppGlobals.rootNavKey,

+ 78 - 24
app_flowy/lib/workspace/presentation/widgets/menu/widget/app/header.dart

@@ -1,16 +1,19 @@
-import 'package:app_flowy/workspace/application/app/app_bloc.dart';
 import 'package:expandable/expandable.dart';
+import 'package:flowy_infra/flowy_icon_data_icons.dart';
+import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/theme.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/icon_button.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
-import 'package:flowy_infra/flowy_icon_data_icons.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:styled_widget/styled_widget.dart';
 
+import 'package:app_flowy/workspace/application/app/app_bloc.dart';
+
 import 'menu_app.dart';
 
 class MenuAppHeader extends StatelessWidget {
@@ -55,37 +58,88 @@ class MenuAppHeader extends StatelessWidget {
               fontSize: 12,
             ),
           )),
-
-          ViewAddButton(
-            onPressed: () {
-              debugPrint('add view');
-              // FlowyOverlay.of(context)
-              //     .insert(widget: Text('test'), identifier: 'identifier');
+          DisclosureButton(
+            onSelected: (viewType) {
+              context.read<AppBloc>().add(AppEvent.createView("New view", "", viewType));
             },
           ).padding(right: MenuAppSizes.expandedIconPadding),
-          // PopupMenuButton(
-          //     iconSize: 16,
-          //     tooltip: 'create new view',
-          //     icon: svg("home/add"),
-          //     padding: EdgeInsets.zero,
-          //     onSelected: (viewType) => _createView(viewType as ViewType, context),
-          //     itemBuilder: (context) => menuItemBuilder())
         ],
       ),
     );
   }
+}
 
-  List<PopupMenuEntry> menuItemBuilder() {
-    return ViewType.values.where((element) => element != ViewType.Blank).map((ty) {
-      return PopupMenuItem<ViewType>(
-          value: ty,
-          child: Row(
-            children: <Widget>[Text(ty.name)],
-          ));
+class DisclosureButton extends StatelessWidget {
+  final Function(ViewType) onSelected;
+  const DisclosureButton({
+    Key? key,
+    required this.onSelected,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return FlowyIconButton(
+      width: 16,
+      onPressed: () {
+        DisclosureButtonActionList(
+          anchorContext: context,
+          onSelected: onSelected,
+        ).show(context);
+      },
+      icon: svg("home/add"),
+    );
+  }
+}
+
+class DisclosureButtonActionList {
+  final Function(ViewType) onSelected;
+  final BuildContext anchorContext;
+  final String _identifier = 'DisclosureButtonActionList';
+
+  const DisclosureButtonActionList({required this.anchorContext, required this.onSelected});
+
+  void show(BuildContext buildContext) {
+    final items = ViewType.values.where((element) => element != ViewType.Blank).map((ty) {
+      return CreateItem(
+          viewType: ty,
+          onSelected: (viewType) {
+            FlowyOverlay.of(buildContext).remove(_identifier);
+            onSelected(viewType);
+          });
     }).toList();
+
+    ListOverlay.showWithAnchor(
+      buildContext,
+      identifier: _identifier,
+      itemCount: items.length,
+      itemBuilder: (context, index) => items[index],
+      anchorContext: anchorContext,
+      anchorDirection: AnchorDirection.bottomRight,
+      maxWidth: 120,
+      maxHeight: 80,
+    );
   }
+}
 
-  void _createView(ViewType viewType, BuildContext context) {
-    context.read<AppBloc>().add(AppEvent.createView("New view", "", viewType));
+class CreateItem extends StatelessWidget {
+  final ViewType viewType;
+  final Function(ViewType) onSelected;
+  const CreateItem({
+    Key? key,
+    required this.viewType,
+    required this.onSelected,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return GestureDetector(
+      onTap: () {
+        onSelected(viewType);
+      },
+      child: FlowyText.medium(
+        viewType.name,
+        fontSize: 12,
+      ).padding(horizontal: 10, vertical: 10),
+    );
   }
 }

+ 24 - 34
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/flowy_overlay.dart

@@ -1,7 +1,7 @@
 // ignore_for_file: unused_element
 
 import 'package:dartz/dartz.dart' show Tuple3;
-import 'package:flowy_infra_ui/src/flowy_overlay/overlay_layout_delegate.dart';
+import 'package:flowy_infra_ui/src/flowy_overlay/layout.dart';
 import 'package:flutter/material.dart';
 
 /// Specifies how overlay are anchored to the SourceWidget
@@ -55,13 +55,21 @@ enum OnBackBehavior {
   dismiss,
 }
 
+class FlowyOverlayConfig {
+  final Color barrierColor;
+
+  FlowyOverlayConfig({required this.barrierColor});
+
+  const FlowyOverlayConfig.defualt() : barrierColor = Colors.transparent;
+}
+
 final GlobalKey<FlowyOverlayState> _key = GlobalKey<FlowyOverlayState>();
 
 /// Invoke this method in app generation process
-TransitionBuilder overlayManagerBuilder() {
+TransitionBuilder overlayManagerBuilder({FlowyOverlayConfig config = const FlowyOverlayConfig.defualt()}) {
   return (context, child) {
     assert(child != null, 'Child can\'t be null.');
-    return FlowyOverlay(key: _key, child: child!);
+    return FlowyOverlay(key: _key, child: child!, config: config);
   };
 }
 
@@ -70,50 +78,33 @@ abstract class FlowyOverlayDelegate {
 }
 
 class FlowyOverlay extends StatefulWidget {
-  const FlowyOverlay({
-    Key? key,
-    required this.child,
-    this.barrierColor = Colors.transparent,
-  }) : super(key: key);
+  const FlowyOverlay({Key? key, required this.child, required this.config}) : 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>();
-    }
+  final FlowyOverlayConfig config;
 
+  static FlowyOverlayState of(BuildContext context, {bool rootOverlay = false}) {
+    FlowyOverlayState? state = maybeOf(context, rootOverlay: rootOverlay);
     assert(() {
-      if (overlayManager == null) {
+      if (state == null) {
         throw FlutterError(
           'Can\'t find overlay manager in current context, please check if already wrapped by overlay manager.',
         );
       }
       return true;
     }());
-    return overlayManager!;
+    return state!;
   }
 
-  static FlowyOverlayState? maybeOf(
-    BuildContext context, {
-    bool rootOverlay = false,
-  }) {
-    FlowyOverlayState? overlayManager;
+  static FlowyOverlayState? maybeOf(BuildContext context, {bool rootOverlay = false}) {
+    FlowyOverlayState? state;
     if (rootOverlay) {
-      overlayManager = context.findRootAncestorStateOfType<FlowyOverlayState>() ?? overlayManager;
+      state = context.findRootAncestorStateOfType<FlowyOverlayState>();
     } else {
-      overlayManager = overlayManager ?? context.findAncestorStateOfType<FlowyOverlayState>();
+      state = context.findAncestorStateOfType<FlowyOverlayState>();
     }
-
-    return overlayManager;
+    return state;
   }
 
   @override
@@ -239,8 +230,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
       overlay = CustomSingleChildLayout(
         delegate: OverlayLayoutDelegate(
           anchorRect: anchorRect,
-          anchorDirection:
-              shouldAnchor ? anchorDirection ?? AnchorDirection.rightWithTopAligned : AnchorDirection.custom,
+          anchorDirection: anchorDirection ?? AnchorDirection.rightWithTopAligned,
           overlapBehaviour: overlapBehaviour ?? OverlapBehaviour.stretch,
         ),
         child: widget,
@@ -259,7 +249,7 @@ class FlowyOverlayState extends State<FlowyOverlay> {
       widget.child,
       if (overlays.isNotEmpty)
         Container(
-          color: widget.barrierColor,
+          color: widget.config.barrierColor,
           child: GestureDetector(
             behavior: HitTestBehavior.opaque,
             onTap: _handleTapOnBackground,

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


+ 20 - 19
app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart

@@ -17,6 +17,26 @@ class ListOverlay extends StatelessWidget {
   final double maxWidth;
   final double maxHeight;
 
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      constraints: BoxConstraints.tight(Size(maxWidth, maxHeight)),
+      decoration: BoxDecoration(
+        color: Colors.white,
+        borderRadius: const BorderRadius.all(Radius.circular(6)),
+        boxShadow: [
+          BoxShadow(color: Colors.black.withOpacity(0.1), spreadRadius: 1, blurRadius: 20.0),
+        ],
+      ),
+      child: ListView.builder(
+        shrinkWrap: true,
+        itemBuilder: itemBuilder,
+        itemCount: itemCount,
+        controller: controller,
+      ),
+    );
+  }
+
   static void showWithAnchor(
     BuildContext context, {
     required String identifier,
@@ -77,23 +97,4 @@ class ListOverlay extends StatelessWidget {
       overlapBehaviour: overlapBehaviour,
     );
   }
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      constraints: BoxConstraints.tight(Size(maxWidth, maxHeight)),
-      decoration: BoxDecoration(
-        color: Colors.white,
-        borderRadius: const BorderRadius.all(Radius.circular(6)),
-        boxShadow: [
-          BoxShadow(color: Colors.black.withOpacity(0.1), spreadRadius: 1, blurRadius: 20.0),
-        ],
-      ),
-      child: ListView.builder(
-        shrinkWrap: true,
-        itemBuilder: itemBuilder,
-        itemCount: itemCount,
-      ),
-    );
-  }
 }

+ 0 - 17
app_flowy/packages/flowy_infra_ui/lib/style_widget/icon_button.dart

@@ -48,23 +48,6 @@ class FlowyDropdownButton extends StatelessWidget {
   }
 }
 
-class ViewAddButton extends StatelessWidget {
-  final VoidCallback? onPressed;
-  const ViewAddButton({
-    Key? key,
-    this.onPressed,
-  }) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    return FlowyIconButton(
-      width: 16,
-      onPressed: onPressed,
-      icon: svg("home/add"),
-    );
-  }
-}
-
 class ViewMoreButton extends StatelessWidget {
   final VoidCallback? onPressed;
   const ViewMoreButton({