Prechádzať zdrojové kódy

feat: using wrap to auto expand Multi-select or single select

appflowy 3 rokov pred
rodič
commit
1ad7e0ece2

+ 2 - 2
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart

@@ -9,8 +9,8 @@ class GridSize {
   static double get leadingHeaderPadding => 50 * scale;
   static double get trailHeaderPadding => 140 * scale;
   static double get headerContainerPadding => 0 * scale;
-  static double get cellHPadding => 10 * scale;
-  static double get cellVPadding => 8 * scale;
+  static double get cellHPadding => 12 * scale;
+  static double get cellVPadding => 12 * scale;
   static double get typeOptionItemHeight => 32 * scale;
   static double get typeOptionSeparatorHeight => 6 * scale;
 

+ 117 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart

@@ -2,6 +2,12 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
 import 'package:flowy_infra_ui/style_widget/hover.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType;
 import 'package:flutter/widgets.dart';
+import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart';
+import 'package:flowy_infra/theme.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
+import 'package:styled_widget/styled_widget.dart';
 import 'checkbox_cell.dart';
 import 'date_cell.dart';
 import 'number_cell.dart';
@@ -57,3 +63,114 @@ class GridCellRequestFocusNotifier extends ChangeNotifier {
 }
 
 abstract class GridCellStyle {}
+
+class CellStateNotifier extends ChangeNotifier {
+  bool _isFocus = false;
+  bool _onEnter = false;
+
+  set isFocus(bool value) {
+    if (_isFocus != value) {
+      _isFocus = value;
+      notifyListeners();
+    }
+  }
+
+  set onEnter(bool value) {
+    if (_onEnter != value) {
+      _onEnter = value;
+      notifyListeners();
+    }
+  }
+
+  bool get isFocus => _isFocus;
+
+  bool get onEnter => _onEnter;
+}
+
+class CellContainer extends StatelessWidget {
+  final GridCellWidget child;
+  final Widget? expander;
+  final double width;
+  final RegionStateNotifier rowStateNotifier;
+  const CellContainer({
+    Key? key,
+    required this.child,
+    required this.width,
+    required this.rowStateNotifier,
+    this.expander,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return ChangeNotifierProxyProvider<RegionStateNotifier, CellStateNotifier>(
+      create: (_) => CellStateNotifier(),
+      update: (_, row, cell) => cell!..onEnter = row.onEnter,
+      child: Selector<CellStateNotifier, bool>(
+        selector: (context, notifier) => notifier.isFocus,
+        builder: (context, isFocus, _) {
+          Widget container = Center(child: child);
+          child.onFocus.addListener(() {
+            Provider.of<CellStateNotifier>(context, listen: false).isFocus = child.onFocus.value;
+          });
+
+          if (expander != null) {
+            container = _CellEnterRegion(child: container, expander: expander!);
+          }
+
+          return GestureDetector(
+            behavior: HitTestBehavior.translucent,
+            onTap: () => child.requestFocus.notify(),
+            child: Container(
+              constraints: BoxConstraints(maxWidth: width),
+              decoration: _makeBoxDecoration(context, isFocus),
+              padding: GridSize.cellContentInsets,
+              child: container,
+            ),
+          );
+        },
+      ),
+    );
+  }
+
+  BoxDecoration _makeBoxDecoration(BuildContext context, bool isFocus) {
+    final theme = context.watch<AppTheme>();
+    if (isFocus) {
+      final borderSide = BorderSide(color: theme.main1, width: 1.0);
+      return BoxDecoration(border: Border.fromBorderSide(borderSide));
+    } else {
+      final borderSide = BorderSide(color: theme.shader5, width: 1.0);
+      return BoxDecoration(border: Border(right: borderSide, bottom: borderSide));
+    }
+  }
+}
+
+class _CellEnterRegion extends StatelessWidget {
+  final Widget child;
+  final Widget expander;
+  const _CellEnterRegion({required this.child, required this.expander, Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Selector<CellStateNotifier, bool>(
+      selector: (context, notifier) => notifier.onEnter,
+      builder: (context, onEnter, _) {
+        List<Widget> children = [child];
+        if (onEnter) {
+          children.add(expander.positioned(right: 0));
+        }
+
+        return MouseRegion(
+          cursor: SystemMouseCursors.click,
+          onEnter: (p) => Provider.of<CellStateNotifier>(context, listen: false).onEnter = true,
+          onExit: (p) => Provider.of<CellStateNotifier>(context, listen: false).onEnter = false,
+          child: Stack(
+            alignment: AlignmentDirectional.center,
+            fit: StackFit.expand,
+            // alignment: AlignmentDirectional.centerEnd,
+            children: children,
+          ),
+        );
+      },
+    );
+  }
+}

+ 0 - 115
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart

@@ -1,115 +0,0 @@
-import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart';
-import 'package:flowy_infra/theme.dart';
-import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
-import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
-import 'cell_builder.dart';
-
-class CellStateNotifier extends ChangeNotifier {
-  bool _isFocus = false;
-  bool _onEnter = false;
-
-  set isFocus(bool value) {
-    if (_isFocus != value) {
-      _isFocus = value;
-      notifyListeners();
-    }
-  }
-
-  set onEnter(bool value) {
-    if (_onEnter != value) {
-      _onEnter = value;
-      notifyListeners();
-    }
-  }
-
-  bool get isFocus => _isFocus;
-
-  bool get onEnter => _onEnter;
-}
-
-class CellContainer extends StatelessWidget {
-  final GridCellWidget child;
-  final Widget? expander;
-  final double width;
-  final RegionStateNotifier rowStateNotifier;
-  const CellContainer({
-    Key? key,
-    required this.child,
-    required this.width,
-    required this.rowStateNotifier,
-    this.expander,
-  }) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    return ChangeNotifierProxyProvider<RegionStateNotifier, CellStateNotifier>(
-      create: (_) => CellStateNotifier(),
-      update: (_, row, cell) => cell!..onEnter = row.onEnter,
-      child: Selector<CellStateNotifier, bool>(
-        selector: (context, notifier) => notifier.isFocus,
-        builder: (context, isFocus, _) {
-          Widget container = Center(child: child);
-          child.onFocus.addListener(() {
-            Provider.of<CellStateNotifier>(context, listen: false).isFocus = child.onFocus.value;
-          });
-
-          if (expander != null) {
-            container = _CellEnterRegion(child: container, expander: expander!);
-          }
-
-          return GestureDetector(
-            behavior: HitTestBehavior.translucent,
-            onTap: () => child.requestFocus.notify(),
-            child: Container(
-              constraints: BoxConstraints(maxWidth: width),
-              decoration: _makeBoxDecoration(context, isFocus),
-              padding: GridSize.cellContentInsets,
-              child: container,
-            ),
-          );
-        },
-      ),
-    );
-  }
-
-  BoxDecoration _makeBoxDecoration(BuildContext context, bool isFocus) {
-    final theme = context.watch<AppTheme>();
-    if (isFocus) {
-      final borderSide = BorderSide(color: theme.main1, width: 1.0);
-      return BoxDecoration(border: Border.fromBorderSide(borderSide));
-    } else {
-      final borderSide = BorderSide(color: theme.shader4, width: 0.4);
-      return BoxDecoration(border: Border(right: borderSide, bottom: borderSide));
-    }
-  }
-}
-
-class _CellEnterRegion extends StatelessWidget {
-  final Widget child;
-  final Widget expander;
-  const _CellEnterRegion({required this.child, required this.expander, Key? key}) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    return Selector<CellStateNotifier, bool>(
-      selector: (context, notifier) => notifier.onEnter,
-      builder: (context, onEnter, _) {
-        List<Widget> children = [Expanded(child: child)];
-        if (onEnter) {
-          children.add(expander);
-        }
-
-        return MouseRegion(
-          cursor: SystemMouseCursors.click,
-          onEnter: (p) => Provider.of<CellStateNotifier>(context, listen: false).onEnter = true,
-          onExit: (p) => Provider.of<CellStateNotifier>(context, listen: false).onEnter = false,
-          child: Row(
-            // alignment: AlignmentDirectional.centerEnd,
-            children: children,
-          ),
-        );
-      },
-    );
-  }
-}

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart

@@ -36,7 +36,7 @@ class _CheckboxCellState extends State<CheckboxCell> {
         builder: (context, state) {
           final icon = state.isSelected ? svgWidget('editor/editor_check') : svgWidget('editor/editor_uncheck');
           return SizedBox(
-            height: 42,
+            height: 20,
             child: Align(
               alignment: Alignment.centerLeft,
               child: FlowyIconButton(

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart

@@ -55,7 +55,7 @@ class _NumberCellState extends State<NumberCell> {
             controller: _controller,
             focusNode: _focusNode,
             onEditingComplete: () => _focusNode.unfocus(),
-            maxLines: 1,
+            maxLines: null,
             style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
             decoration: const InputDecoration(
               contentPadding: EdgeInsets.zero,

+ 0 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart

@@ -1,5 +1,4 @@
 export 'cell_builder.dart';
-export 'cell_container.dart';
 export 'text_cell.dart';
 export 'number_cell.dart';
 export 'date_cell.dart';

+ 19 - 9
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart

@@ -66,15 +66,25 @@ class SelectOptionTag extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return Container(
-      decoration: BoxDecoration(
-        color: option.color.make(context),
-        shape: BoxShape.rectangle,
-        borderRadius: BorderRadius.circular(8.0),
-      ),
-      child: Center(child: FlowyText.medium(option.name, fontSize: 12)),
-      margin: const EdgeInsets.symmetric(horizontal: 3.0),
-      padding: const EdgeInsets.symmetric(horizontal: 6.0),
+    return ChoiceChip(
+      pressElevation: 1,
+      label: FlowyText.medium(option.name, fontSize: 12),
+      selectedColor: option.color.make(context),
+      backgroundColor: option.color.make(context),
+      labelPadding: const EdgeInsets.symmetric(horizontal: 6),
+      selected: true,
+      onSelected: (_) {},
     );
+
+    // return Container(
+    //   decoration: BoxDecoration(
+    //     color: option.color.make(context),
+    //     shape: BoxShape.rectangle,
+    //     borderRadius: BorderRadius.circular(8.0),
+    //   ),
+    //   child: Center(child: FlowyText.medium(option.name, fontSize: 12)),
+    //   margin: const EdgeInsets.symmetric(horizontal: 3.0),
+    //   padding: const EdgeInsets.symmetric(horizontal: 6.0),
+    // );
   }
 }

+ 3 - 6
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart

@@ -44,7 +44,6 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
 
   @override
   void initState() {
-    // Log.trace("init widget $hashCode");
     final cellContext = _buildCellContext();
     _cellBloc = getIt<SelectionCellBloc>(param1: cellContext)..add(const SelectionCellEvent.initial());
     super.initState();
@@ -64,8 +63,7 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
           if (children.isEmpty && widget.cellStyle != null) {
             children.add(FlowyText.medium(widget.cellStyle!.placeholder, fontSize: 14, color: theme.shader3));
           }
-          return SizedBox(
-            height: 69,
+          return SizedBox.expand(
             child: InkWell(
               onTap: () {
                 widget.onFocus.value = true;
@@ -75,7 +73,7 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
                   () => widget.onFocus.value = false,
                 );
               },
-              child: ClipRRect(child: Row(children: children)),
+              child: Center(child: Wrap(children: children)),
             ),
           );
         },
@@ -89,7 +87,6 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
 
   @override
   Future<void> dispose() async {
-    // Log.trace("dispose widget $hashCode");
     _cellBloc.close();
     super.dispose();
   }
@@ -148,7 +145,7 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
                   () => widget.onFocus.value = false,
                 );
               },
-              child: ClipRRect(child: Row(children: children)),
+              child: Wrap(children: children, spacing: 4, runSpacing: 4),
             ),
           );
         },

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/text_field.dart

@@ -94,7 +94,7 @@ class SelectOptionTextField extends StatelessWidget {
       child: SingleChildScrollView(
         controller: sc,
         scrollDirection: Axis.horizontal,
-        child: Row(children: children),
+        child: Wrap(children: children, spacing: 4),
       ),
     );
   }

+ 12 - 15
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart

@@ -68,21 +68,18 @@ class _GridTextCellState extends State<GridTextCell> {
         },
         buildWhen: (previous, current) => previous.content != current.content,
         builder: (context, state) {
-          return SizedBox(
-            height: 42,
-            child: TextField(
-              controller: _controller,
-              focusNode: _focusNode,
-              onChanged: (value) => focusChanged(),
-              onEditingComplete: () => _focusNode.unfocus(),
-              maxLines: 1,
-              style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
-              decoration: InputDecoration(
-                contentPadding: EdgeInsets.zero,
-                border: InputBorder.none,
-                hintText: widget.cellStyle?.placeholder,
-                isDense: true,
-              ),
+          return TextField(
+            controller: _controller,
+            focusNode: _focusNode,
+            onChanged: (value) => focusChanged(),
+            onEditingComplete: () => _focusNode.unfocus(),
+            maxLines: null,
+            style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
+            decoration: InputDecoration(
+              contentPadding: EdgeInsets.zero,
+              border: InputBorder.none,
+              hintText: widget.cellStyle?.placeholder,
+              isDense: true,
             ),
           );
         },

+ 4 - 2
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart

@@ -206,9 +206,11 @@ class _CellExpander extends StatelessWidget {
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
     return FlowyIconButton(
-      width: 20,
+      width: 30,
+      height: 24,
       onPressed: onExpand,
-      iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
+      iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
+      fillColor: theme.surface,
       icon: svgWidget("grid/expander", color: theme.main1),
     );
   }