ソースを参照

refactor: replace FlowyOverlay with AppFlowyPopover in select option

nathan 2 年 前
コミット
6c27b5455e

+ 56 - 35
frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart

@@ -2,6 +2,8 @@ import 'package:app_flowy/plugins/board/application/card/board_select_option_cel
 import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
 import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/extension.dart';
 import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart';
+import 'package:appflowy_popover/popover.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
@@ -26,9 +28,11 @@ class BoardSelectOptionCell extends StatefulWidget with EditableCell {
 
 class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
   late BoardSelectOptionCellBloc _cellBloc;
+  late PopoverController _popover;
 
   @override
   void initState() {
+    _popover = PopoverController();
     final cellController =
         widget.cellControllerBuilder.build() as GridSelectOptionCellController;
     _cellBloc = BoardSelectOptionCellBloc(cellController: cellController)
@@ -41,43 +45,60 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
     return BlocProvider.value(
       value: _cellBloc,
       child: BlocBuilder<BoardSelectOptionCellBloc, BoardSelectOptionCellState>(
-        buildWhen: (previous, current) {
-          return previous.selectedOptions != current.selectedOptions;
-        },
-        builder: (context, state) {
-          if (state.selectedOptions
-                  .where((element) => element.id == widget.groupId)
-                  .isNotEmpty ||
-              state.selectedOptions.isEmpty) {
-            return const SizedBox();
-          } else {
-            final children = state.selectedOptions
-                .map(
-                  (option) => SelectOptionTag.fromOption(
-                    context: context,
-                    option: option,
-                    onSelected: () {
-                      SelectOptionCellEditor.show(
-                        context: context,
-                        cellController: widget.cellControllerBuilder.build()
-                            as GridSelectOptionCellController,
-                      );
-                    },
-                  ),
-                )
-                .toList();
+          buildWhen: (previous, current) {
+        return previous.selectedOptions != current.selectedOptions;
+      }, builder: (context, state) {
+        // Returns SizedBox if the content of the cell is empty
+        if (_isEmpty(state)) return const SizedBox();
 
-            return IntrinsicHeight(
-              child: Padding(
-                padding: const EdgeInsets.symmetric(vertical: 6),
-                child: SizedBox.expand(
-                  child: Wrap(spacing: 4, runSpacing: 2, children: children),
-                ),
-              ),
+        final children = state.selectedOptions.map(
+          (option) {
+            final tag = SelectOptionTag.fromOption(
+              context: context,
+              option: option,
+              onSelected: () => _popover.show(),
             );
-          }
-        },
-      ),
+            return _wrapPopover(tag);
+          },
+        ).toList();
+
+        return IntrinsicHeight(
+          child: Padding(
+            padding: const EdgeInsets.symmetric(vertical: 6),
+            child: SizedBox.expand(
+              child: Wrap(spacing: 4, runSpacing: 2, children: children),
+            ),
+          ),
+        );
+      }),
+    );
+  }
+
+  bool _isEmpty(BoardSelectOptionCellState state) {
+    // The cell should hide if the option id is equal to the groupId.
+    final isInGroup = state.selectedOptions
+        .where((element) => element.id == widget.groupId)
+        .isNotEmpty;
+    return isInGroup || state.selectedOptions.isEmpty;
+  }
+
+  Widget _wrapPopover(Widget child) {
+    final constraints = BoxConstraints.loose(Size(
+      SelectOptionCellEditor.editorPanelWidth,
+      300,
+    ));
+    return AppFlowyStylePopover(
+      controller: _popover,
+      constraints: constraints,
+      direction: PopoverDirection.bottomWithLeftAligned,
+      popupBuilder: (BuildContext context) {
+        return SelectOptionCellEditor(
+          cellController: widget.cellControllerBuilder.build()
+              as GridSelectOptionCellController,
+        );
+      },
+      onClose: () {},
+      child: child,
     );
   }
 

+ 53 - 55
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_cell.dart

@@ -164,67 +164,65 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
-    final Widget child;
-    if (widget.selectOptions.isEmpty && widget.cellStyle != null) {
-      child = Align(
-        alignment: Alignment.centerLeft,
-        child: FlowyText.medium(
-          widget.cellStyle!.placeholder,
-          fontSize: 14,
-          color: theme.shader3,
-        ),
-      );
-    } else {
-      child = Align(
-        alignment: Alignment.centerLeft,
-        child: Wrap(
-          spacing: 4,
-          runSpacing: 2,
-          children: widget.selectOptions
-              .map((option) => SelectOptionTag.fromOption(
-                    context: context,
-                    option: option,
-                  ))
-              .toList(),
-        ),
-      );
-    }
+    Widget child = _buildOptions(theme, context);
 
     return Stack(
       alignment: AlignmentDirectional.center,
       fit: StackFit.expand,
       children: [
-        AppFlowyStylePopover(
-          controller: _popover,
-          constraints: BoxConstraints.loose(
-              Size(SelectOptionCellEditor.editorPanelWidth, 300)),
-          offset: const Offset(0, 20),
-          direction: PopoverDirection.bottomWithLeftAligned,
-          // triggerActions: PopoverTriggerActionFlags.c,
-          popupBuilder: (BuildContext context) {
-            WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
-              widget.onFocus?.call(true);
-            });
-            return SizedBox(
-              width: SelectOptionCellEditor.editorPanelWidth,
-              child: SelectOptionCellEditor(
-                cellController: widget.cellControllerBuilder.build()
-                    as GridSelectOptionCellController,
-                onDismissed: () {
-                  widget.onFocus?.call(false);
-                },
-              ),
-            );
-          },
-          onClose: () {
-            widget.onFocus?.call(false);
-          },
-          child: child,
-        ),
-        InkWell(onTap: () {
-          _popover.show();
-        }),
+        _wrapPopover(child),
+        InkWell(onTap: () => _popover.show()),
       ],
     );
   }
+
+  Widget _wrapPopover(Widget child) {
+    final constraints = BoxConstraints.loose(Size(
+      SelectOptionCellEditor.editorPanelWidth,
+      300,
+    ));
+    return AppFlowyStylePopover(
+      controller: _popover,
+      constraints: constraints,
+      direction: PopoverDirection.bottomWithLeftAligned,
+      popupBuilder: (BuildContext context) {
+        WidgetsBinding.instance.addPostFrameCallback((_) {
+          widget.onFocus?.call(true);
+        });
+        return SelectOptionCellEditor(
+          cellController: widget.cellControllerBuilder.build()
+              as GridSelectOptionCellController,
+        );
+      },
+      onClose: () => widget.onFocus?.call(false),
+      child: child,
+    );
+  }
+
+  Widget _buildOptions(AppTheme theme, BuildContext context) {
+    final Widget child;
+    if (widget.selectOptions.isEmpty && widget.cellStyle != null) {
+      child = FlowyText.medium(
+        widget.cellStyle!.placeholder,
+        fontSize: 14,
+        color: theme.shader3,
+      );
+    } else {
+      final children = widget.selectOptions.map(
+        (option) {
+          return SelectOptionTag.fromOption(
+            context: context,
+            option: option,
+          );
+        },
+      ).toList();
+
+      child = Wrap(
+        spacing: 4,
+        runSpacing: 2,
+        children: children,
+      );
+    }
+    return Align(alignment: Alignment.centerLeft, child: child);
+  }
 }

+ 3 - 45
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart

@@ -25,17 +25,13 @@ import 'text_field.dart';
 
 const double _editorPanelWidth = 300;
 
-class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
+class SelectOptionCellEditor extends StatelessWidget {
   final GridSelectOptionCellController cellController;
-  final VoidCallback? onDismissed;
 
   static double editorPanelWidth = 300;
 
-  const SelectOptionCellEditor({
-    required this.cellController,
-    this.onDismissed,
-    Key? key,
-  }) : super(key: key);
+  const SelectOptionCellEditor({required this.cellController, Key? key})
+      : super(key: key);
 
   @override
   Widget build(BuildContext context) {
@@ -60,44 +56,6 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate {
       ),
     );
   }
-
-  static void show({
-    required BuildContext context,
-    required GridSelectOptionCellController cellController,
-    VoidCallback? onDismissed,
-  }) {
-    SelectOptionCellEditor.remove(context);
-    final editor = SelectOptionCellEditor(
-      cellController: cellController,
-      onDismissed: onDismissed,
-    );
-
-    //
-    FlowyOverlay.of(context).insertWithAnchor(
-      widget: OverlayContainer(
-        constraints: BoxConstraints.loose(const Size(_editorPanelWidth, 300)),
-        child: SizedBox(width: _editorPanelWidth, child: editor),
-      ),
-      identifier: SelectOptionCellEditor.identifier(),
-      anchorContext: context,
-      anchorDirection: AnchorDirection.bottomWithCenterAligned,
-      delegate: editor,
-    );
-  }
-
-  static void remove(BuildContext context) {
-    FlowyOverlay.of(context).remove(identifier());
-  }
-
-  static String identifier() {
-    return (SelectOptionCellEditor).toString();
-  }
-
-  @override
-  bool asBarrier() => true;
-
-  @override
-  void didRemove() => onDismissed?.call();
 }
 
 class _OptionList extends StatelessWidget {