Преглед изворни кода

feat: refactor multi select

Vincent Chan пре 2 година
родитељ
комит
bfb60dcaec

+ 32 - 10
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_editor.dart

@@ -1,5 +1,6 @@
 import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart';
 import 'package:app_flowy/plugins/grid/application/field/field_editor_bloc.dart';
 import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
 import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
+import 'package:appflowy_popover/popover.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
@@ -10,7 +11,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
 import 'field_name_input.dart';
 import 'field_name_input.dart';
 import 'field_type_option_editor.dart';
 import 'field_type_option_editor.dart';
 
 
-class FieldEditor extends StatelessWidget {
+class FieldEditor extends StatefulWidget {
   final String gridId;
   final String gridId;
   final String fieldName;
   final String fieldName;
 
 
@@ -22,13 +23,29 @@ class FieldEditor extends StatelessWidget {
     Key? key,
     Key? key,
   }) : super(key: key);
   }) : super(key: key);
 
 
+  @override
+  bool asBarrier() => true;
+
+  @override
+  State<StatefulWidget> createState() => _FieldEditorState();
+}
+
+class _FieldEditorState extends State<FieldEditor> {
+  late PopoverMutex popoverMutex;
+
+  @override
+  void initState() {
+    popoverMutex = PopoverMutex();
+    super.initState();
+  }
+
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return BlocProvider(
     return BlocProvider(
       create: (context) => FieldEditorBloc(
       create: (context) => FieldEditorBloc(
-        gridId: gridId,
-        fieldName: fieldName,
-        loader: typeOptionLoader,
+        gridId: widget.gridId,
+        fieldName: widget.fieldName,
+        loader: widget.typeOptionLoader,
       )..add(const FieldEditorEvent.initial()),
       )..add(const FieldEditorEvent.initial()),
       child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
       child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
         buildWhen: (p, c) => false,
         buildWhen: (p, c) => false,
@@ -41,20 +58,22 @@ class FieldEditor extends StatelessWidget {
               const VSpace(10),
               const VSpace(10),
               const _FieldNameCell(),
               const _FieldNameCell(),
               const VSpace(10),
               const VSpace(10),
-              const _FieldTypeOptionCell(),
+              _FieldTypeOptionCell(popoverMutex: popoverMutex),
             ],
             ],
           );
           );
         },
         },
       ),
       ),
     );
     );
   }
   }
-
-  @override
-  bool asBarrier() => true;
 }
 }
 
 
 class _FieldTypeOptionCell extends StatelessWidget {
 class _FieldTypeOptionCell extends StatelessWidget {
-  const _FieldTypeOptionCell({Key? key}) : super(key: key);
+  final PopoverMutex popoverMutex;
+
+  const _FieldTypeOptionCell({
+    Key? key,
+    required this.popoverMutex,
+  }) : super(key: key);
 
 
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
@@ -66,7 +85,10 @@ class _FieldTypeOptionCell extends StatelessWidget {
           (fieldContext) {
           (fieldContext) {
             final dataController =
             final dataController =
                 context.read<FieldEditorBloc>().dataController;
                 context.read<FieldEditorBloc>().dataController;
-            return FieldTypeOptionEditor(dataController: dataController);
+            return FieldTypeOptionEditor(
+              dataController: dataController,
+              popoverMutex: popoverMutex,
+            );
           },
           },
         );
         );
       },
       },

+ 11 - 2
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_option_editor.dart

@@ -26,9 +26,11 @@ typedef SwitchToFieldCallback
 
 
 class FieldTypeOptionEditor extends StatefulWidget {
 class FieldTypeOptionEditor extends StatefulWidget {
   final TypeOptionDataController dataController;
   final TypeOptionDataController dataController;
+  final PopoverMutex popoverMutex;
 
 
   const FieldTypeOptionEditor({
   const FieldTypeOptionEditor({
     required this.dataController,
     required this.dataController,
+    required this.popoverMutex,
     Key? key,
     Key? key,
   }) : super(key: key);
   }) : super(key: key);
 
 
@@ -37,9 +39,15 @@ class FieldTypeOptionEditor extends StatefulWidget {
 }
 }
 
 
 class _FieldTypeOptionEditorState extends State<FieldTypeOptionEditor> {
 class _FieldTypeOptionEditorState extends State<FieldTypeOptionEditor> {
-  final popover = PopoverController();
+  late PopoverController popover;
   String? currentOverlayIdentifier;
   String? currentOverlayIdentifier;
 
 
+  @override
+  void initState() {
+    popover = PopoverController(mutex: widget.popoverMutex);
+    super.initState();
+  }
+
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return BlocProvider(
     return BlocProvider(
@@ -114,6 +122,7 @@ class _FieldTypeOptionEditorState extends State<FieldTypeOptionEditor> {
       context: context,
       context: context,
       overlayDelegate: overlayDelegate,
       overlayDelegate: overlayDelegate,
       dataController: widget.dataController,
       dataController: widget.dataController,
+      popoverMutex: widget.popoverMutex,
     );
     );
   }
   }
 
 
@@ -138,6 +147,6 @@ class _FieldTypeOptionEditorState extends State<FieldTypeOptionEditor> {
   }
   }
 }
 }
 
 
-abstract class TypeOptionWidget extends StatelessWidget {
+abstract class TypeOptionWidget extends StatefulWidget {
   const TypeOptionWidget({Key? key}) : super(key: key);
   const TypeOptionWidget({Key? key}) : super(key: key);
 }
 }

+ 15 - 14
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/builder.dart

@@ -2,6 +2,7 @@ import 'dart:typed_data';
 
 
 import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
 import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart';
 import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_data_controller.dart';
 import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_data_controller.dart';
+import 'package:appflowy_popover/popover.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/multi_select_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/multi_select_type_option.pb.dart';
@@ -46,18 +47,19 @@ Widget? makeTypeOptionWidget({
   required BuildContext context,
   required BuildContext context,
   required TypeOptionDataController dataController,
   required TypeOptionDataController dataController,
   required TypeOptionOverlayDelegate overlayDelegate,
   required TypeOptionOverlayDelegate overlayDelegate,
+  required PopoverMutex popoverMutex,
 }) {
 }) {
   final builder = makeTypeOptionWidgetBuilder(
   final builder = makeTypeOptionWidgetBuilder(
-    dataController: dataController,
-    overlayDelegate: overlayDelegate,
-  );
+      dataController: dataController,
+      overlayDelegate: overlayDelegate,
+      popoverMutex: popoverMutex);
   return builder.build(context);
   return builder.build(context);
 }
 }
 
 
-TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
-  required TypeOptionDataController dataController,
-  required TypeOptionOverlayDelegate overlayDelegate,
-}) {
+TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
+    {required TypeOptionDataController dataController,
+    required TypeOptionOverlayDelegate overlayDelegate,
+    required PopoverMutex popoverMutex}) {
   final gridId = dataController.gridId;
   final gridId = dataController.gridId;
   final fieldType = dataController.field.fieldType;
   final fieldType = dataController.field.fieldType;
 
 
@@ -72,13 +74,12 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
       );
       );
     case FieldType.DateTime:
     case FieldType.DateTime:
       return DateTypeOptionWidgetBuilder(
       return DateTypeOptionWidgetBuilder(
-        makeTypeOptionContextWithDataController<DateTypeOptionPB>(
-          gridId: gridId,
-          fieldType: fieldType,
-          dataController: dataController,
-        ),
-        overlayDelegate,
-      );
+          makeTypeOptionContextWithDataController<DateTypeOptionPB>(
+            gridId: gridId,
+            fieldType: fieldType,
+            dataController: dataController,
+          ),
+          popoverMutex);
     case FieldType.SingleSelect:
     case FieldType.SingleSelect:
       return SingleSelectTypeOptionWidgetBuilder(
       return SingleSelectTypeOptionWidgetBuilder(
         makeTypeOptionContextWithDataController<SingleSelectTypeOptionPB>(
         makeTypeOptionContextWithDataController<SingleSelectTypeOptionPB>(

+ 83 - 33
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart

@@ -11,6 +11,7 @@ import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:appflowy_popover/popover.dart';
 import '../../../layout/sizes.dart';
 import '../../../layout/sizes.dart';
 import '../field_type_option_editor.dart';
 import '../field_type_option_editor.dart';
 import 'builder.dart';
 import 'builder.dart';
@@ -20,10 +21,10 @@ class DateTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
 
 
   DateTypeOptionWidgetBuilder(
   DateTypeOptionWidgetBuilder(
     DateTypeOptionContext typeOptionContext,
     DateTypeOptionContext typeOptionContext,
-    TypeOptionOverlayDelegate overlayDelegate,
+    PopoverMutex popoverMutex,
   ) : _widget = DateTypeOptionWidget(
   ) : _widget = DateTypeOptionWidget(
           typeOptionContext: typeOptionContext,
           typeOptionContext: typeOptionContext,
-          overlayDelegate: overlayDelegate,
+          popoverMutex: popoverMutex,
         );
         );
 
 
   @override
   @override
@@ -34,22 +35,36 @@ class DateTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder {
 
 
 class DateTypeOptionWidget extends TypeOptionWidget {
 class DateTypeOptionWidget extends TypeOptionWidget {
   final DateTypeOptionContext typeOptionContext;
   final DateTypeOptionContext typeOptionContext;
-  final TypeOptionOverlayDelegate overlayDelegate;
-
+  final PopoverMutex popoverMutex;
   const DateTypeOptionWidget({
   const DateTypeOptionWidget({
     required this.typeOptionContext,
     required this.typeOptionContext,
-    required this.overlayDelegate,
+    required this.popoverMutex,
     Key? key,
     Key? key,
   }) : super(key: key);
   }) : super(key: key);
 
 
+  @override
+  State<StatefulWidget> createState() => _DateTypeOptionWidgetState();
+}
+
+class _DateTypeOptionWidgetState extends State<DateTypeOptionWidget> {
+  late PopoverController dateFormatPopover;
+  late PopoverController timeFormatPopover;
+
+  @override
+  void initState() {
+    dateFormatPopover = PopoverController(mutex: widget.popoverMutex);
+    timeFormatPopover = PopoverController(mutex: widget.popoverMutex);
+    super.initState();
+  }
+
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return BlocProvider(
     return BlocProvider(
       create: (context) =>
       create: (context) =>
-          DateTypeOptionBloc(typeOptionContext: typeOptionContext),
+          DateTypeOptionBloc(typeOptionContext: widget.typeOptionContext),
       child: BlocConsumer<DateTypeOptionBloc, DateTypeOptionState>(
       child: BlocConsumer<DateTypeOptionBloc, DateTypeOptionState>(
         listener: (context, state) =>
         listener: (context, state) =>
-            typeOptionContext.typeOption = state.typeOption,
+            widget.typeOptionContext.typeOption = state.typeOption,
         builder: (context, state) {
         builder: (context, state) {
           return Column(children: [
           return Column(children: [
             _renderDateFormatButton(context, state.typeOption.dateFormat),
             _renderDateFormatButton(context, state.typeOption.dateFormat),
@@ -62,39 +77,71 @@ class DateTypeOptionWidget extends TypeOptionWidget {
   }
   }
 
 
   Widget _renderDateFormatButton(BuildContext context, DateFormat dataFormat) {
   Widget _renderDateFormatButton(BuildContext context, DateFormat dataFormat) {
-    return DateFormatButton(onTap: () {
-      final list = DateFormatList(
-        selectedFormat: dataFormat,
-        onSelected: (format) {
-          context
-              .read<DateTypeOptionBloc>()
-              .add(DateTypeOptionEvent.didSelectDateFormat(format));
-        },
-      );
-      overlayDelegate.showOverlay(context, list);
-    });
-  }
-
-  Widget _renderTimeFormatButton(BuildContext context, TimeFormat timeFormat) {
-    return TimeFormatButton(
-      timeFormat: timeFormat,
-      onTap: () {
-        final list = TimeFormatList(
-            selectedFormat: timeFormat,
+    return Popover(
+      controller: dateFormatPopover,
+      child: DateFormatButton(onTap: () {
+        dateFormatPopover.show();
+      }, onHover: ((hover) {
+        if (hover) {
+          dateFormatPopover.show();
+        }
+      })),
+      targetAnchor: Alignment.topRight,
+      followerAnchor: Alignment.topLeft,
+      offset: const Offset(20, 0),
+      popupBuilder: (context) {
+        return OverlayContainer(
+          constraints: BoxConstraints.loose(const Size(460, 440)),
+          child: DateFormatList(
+            selectedFormat: dataFormat,
             onSelected: (format) {
             onSelected: (format) {
               context
               context
                   .read<DateTypeOptionBloc>()
                   .read<DateTypeOptionBloc>()
-                  .add(DateTypeOptionEvent.didSelectTimeFormat(format));
-            });
-        overlayDelegate.showOverlay(context, list);
+                  .add(DateTypeOptionEvent.didSelectDateFormat(format));
+            },
+          ),
+        );
+      },
+    );
+  }
+
+  Widget _renderTimeFormatButton(BuildContext context, TimeFormat timeFormat) {
+    return Popover(
+      controller: timeFormatPopover,
+      child: TimeFormatButton(
+        timeFormat: timeFormat,
+        onTap: () {
+          timeFormatPopover.show();
+        },
+        onHover: (hover) {
+          if (hover) {
+            timeFormatPopover.show();
+          }
+        },
+      ),
+      targetAnchor: Alignment.topRight,
+      followerAnchor: Alignment.topLeft,
+      offset: const Offset(20, 0),
+      popupBuilder: (BuildContext context) {
+        return OverlayContainer(
+            constraints: BoxConstraints.loose(const Size(460, 440)),
+            child: TimeFormatList(
+                selectedFormat: timeFormat,
+                onSelected: (format) {
+                  context
+                      .read<DateTypeOptionBloc>()
+                      .add(DateTypeOptionEvent.didSelectTimeFormat(format));
+                }));
       },
       },
     );
     );
   }
   }
 }
 }
 
 
 class DateFormatButton extends StatelessWidget {
 class DateFormatButton extends StatelessWidget {
-  final VoidCallback onTap;
-  const DateFormatButton({required this.onTap, Key? key}) : super(key: key);
+  final VoidCallback? onTap;
+  final void Function(bool)? onHover;
+  const DateFormatButton({this.onTap, this.onHover, Key? key})
+      : super(key: key);
 
 
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
@@ -107,6 +154,7 @@ class DateFormatButton extends StatelessWidget {
         margin: GridSize.typeOptionContentInsets,
         margin: GridSize.typeOptionContentInsets,
         hoverColor: theme.hover,
         hoverColor: theme.hover,
         onTap: onTap,
         onTap: onTap,
+        onHover: onHover,
         rightIcon: svgWidget("grid/more", color: theme.iconColor),
         rightIcon: svgWidget("grid/more", color: theme.iconColor),
       ),
       ),
     );
     );
@@ -115,9 +163,10 @@ class DateFormatButton extends StatelessWidget {
 
 
 class TimeFormatButton extends StatelessWidget {
 class TimeFormatButton extends StatelessWidget {
   final TimeFormat timeFormat;
   final TimeFormat timeFormat;
-  final VoidCallback onTap;
+  final VoidCallback? onTap;
+  final void Function(bool)? onHover;
   const TimeFormatButton(
   const TimeFormatButton(
-      {required this.timeFormat, required this.onTap, Key? key})
+      {required this.timeFormat, this.onTap, this.onHover, Key? key})
       : super(key: key);
       : super(key: key);
 
 
   @override
   @override
@@ -131,6 +180,7 @@ class TimeFormatButton extends StatelessWidget {
         margin: GridSize.typeOptionContentInsets,
         margin: GridSize.typeOptionContentInsets,
         hoverColor: theme.hover,
         hoverColor: theme.hover,
         onTap: onTap,
         onTap: onTap,
+        onHover: onHover,
         rightIcon: svgWidget("grid/more", color: theme.iconColor),
         rightIcon: svgWidget("grid/more", color: theme.iconColor),
       ),
       ),
     );
     );

+ 10 - 4
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/multi_select.dart

@@ -35,13 +35,19 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
     Key? key,
     Key? key,
   }) : super(key: key);
   }) : super(key: key);
 
 
+  @override
+  State<StatefulWidget> createState() => _MultiSelectTypeOptionWidgetState();
+}
+
+class _MultiSelectTypeOptionWidgetState
+    extends State<MultiSelectTypeOptionWidget> {
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return SelectOptionTypeOptionWidget(
     return SelectOptionTypeOptionWidget(
-      options: selectOptionAction.typeOption.options,
-      beginEdit: () => overlayDelegate.hideOverlay(context),
-      overlayDelegate: overlayDelegate,
-      typeOptionAction: selectOptionAction,
+      options: widget.selectOptionAction.typeOption.options,
+      beginEdit: () => widget.overlayDelegate.hideOverlay(context),
+      overlayDelegate: widget.overlayDelegate,
+      typeOptionAction: widget.selectOptionAction,
       // key: ValueKey(state.typeOption.hashCode),
       // key: ValueKey(state.typeOption.hashCode),
     );
     );
   }
   }

+ 8 - 3
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart

@@ -42,17 +42,22 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
     Key? key,
     Key? key,
   }) : super(key: key);
   }) : super(key: key);
 
 
+  @override
+  State<StatefulWidget> createState() => _NumberTypeOptionWidgetState();
+}
+
+class _NumberTypeOptionWidgetState extends State<NumberTypeOptionWidget> {
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
     final theme = context.watch<AppTheme>();
     return BlocProvider(
     return BlocProvider(
       create: (context) =>
       create: (context) =>
-          NumberTypeOptionBloc(typeOptionContext: typeOptionContext),
+          NumberTypeOptionBloc(typeOptionContext: widget.typeOptionContext),
       child: SizedBox(
       child: SizedBox(
         height: GridSize.typeOptionItemHeight,
         height: GridSize.typeOptionItemHeight,
         child: BlocConsumer<NumberTypeOptionBloc, NumberTypeOptionState>(
         child: BlocConsumer<NumberTypeOptionBloc, NumberTypeOptionState>(
           listener: (context, state) =>
           listener: (context, state) =>
-              typeOptionContext.typeOption = state.typeOption,
+              widget.typeOptionContext.typeOption = state.typeOption,
           builder: (context, state) {
           builder: (context, state) {
             return FlowyButton(
             return FlowyButton(
               text: Row(
               text: Row(
@@ -76,7 +81,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
                   },
                   },
                   selectedFormat: state.typeOption.format,
                   selectedFormat: state.typeOption.format,
                 );
                 );
-                overlayDelegate.showOverlay(
+                widget.overlayDelegate.showOverlay(
                   context,
                   context,
                   list,
                   list,
                 );
                 );

+ 10 - 4
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/single_select.dart

@@ -34,13 +34,19 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
     Key? key,
     Key? key,
   }) : super(key: key);
   }) : super(key: key);
 
 
+  @override
+  State<StatefulWidget> createState() => _SingleSelectTypeOptionWidgetState();
+}
+
+class _SingleSelectTypeOptionWidgetState
+    extends State<SingleSelectTypeOptionWidget> {
   @override
   @override
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return SelectOptionTypeOptionWidget(
     return SelectOptionTypeOptionWidget(
-      options: selectOptionAction.typeOption.options,
-      beginEdit: () => overlayDelegate.hideOverlay(context),
-      overlayDelegate: overlayDelegate,
-      typeOptionAction: selectOptionAction,
+      options: widget.selectOptionAction.typeOption.options,
+      beginEdit: () => widget.overlayDelegate.hideOverlay(context),
+      overlayDelegate: widget.overlayDelegate,
+      typeOptionAction: widget.selectOptionAction,
       // key: ValueKey(state.typeOption.hashCode),
       // key: ValueKey(state.typeOption.hashCode),
     );
     );
   }
   }

+ 3 - 3
frontend/app_flowy/packages/appflowy_popover/example/lib/example_button.dart

@@ -7,14 +7,14 @@ class PopoverMenu extends StatefulWidget {
 }
 }
 
 
 class _PopoverMenuState extends State<PopoverMenu> {
 class _PopoverMenuState extends State<PopoverMenu> {
-  final PopoverExclusive exclusive = PopoverExclusive();
+  final PopoverMutex exclusive = PopoverMutex();
   late PopoverController firstPopover;
   late PopoverController firstPopover;
   late PopoverController secondPopover;
   late PopoverController secondPopover;
 
 
   @override
   @override
   void initState() {
   void initState() {
-    firstPopover = PopoverController(exclusive: exclusive);
-    secondPopover = PopoverController(exclusive: exclusive);
+    firstPopover = PopoverController(mutex: exclusive);
+    secondPopover = PopoverController(mutex: exclusive);
     super.initState();
     super.initState();
   }
   }
 
 

+ 16 - 8
frontend/app_flowy/packages/appflowy_popover/lib/popover.dart

@@ -2,28 +2,28 @@ import 'package:flutter/gestures.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/services.dart';
 
 
-class PopoverExclusive {
+class PopoverMutex {
   PopoverController? controller;
   PopoverController? controller;
 }
 }
 
 
 class PopoverController {
 class PopoverController {
   PopoverState? state;
   PopoverState? state;
-  PopoverExclusive? exclusive;
+  PopoverMutex? mutex;
 
 
-  PopoverController({this.exclusive});
+  PopoverController({this.mutex});
 
 
   close() {
   close() {
     state?.close();
     state?.close();
-    if (exclusive != null && exclusive!.controller == this) {
-      exclusive!.controller = null;
+    if (mutex != null && mutex!.controller == this) {
+      mutex!.controller = null;
     }
     }
   }
   }
 
 
   show() {
   show() {
-    if (exclusive != null) {
+    if (mutex != null) {
       debugPrint("show popover");
       debugPrint("show popover");
-      exclusive!.controller?.close();
-      exclusive!.controller = this;
+      mutex!.controller?.close();
+      mutex!.controller = this;
     }
     }
     state?.showOverlay();
     state?.showOverlay();
   }
   }
@@ -71,9 +71,15 @@ class PopoverState extends State<Popover> {
     _recognizer.onTap = (() {
     _recognizer.onTap = (() {
       debugPrint("ggg tap");
       debugPrint("ggg tap");
     });
     });
+    WidgetsBinding.instance.pointerRouter
+        .addGlobalRoute(_handleGlobalPointerEvent);
     super.initState();
     super.initState();
   }
   }
 
 
+  _handleGlobalPointerEvent(PointerEvent event) {
+    // debugPrint("mouse down: ${event}");
+  }
+
   showOverlay() {
   showOverlay() {
     debugPrint("show overlay");
     debugPrint("show overlay");
     close();
     close();
@@ -126,6 +132,8 @@ class PopoverState extends State<Popover> {
   @override
   @override
   void deactivate() {
   void deactivate() {
     debugPrint("deactivate");
     debugPrint("deactivate");
+    WidgetsBinding.instance.pointerRouter
+        .removeGlobalRoute(_handleGlobalPointerEvent);
     close();
     close();
     super.deactivate();
     super.deactivate();
   }
   }