Pārlūkot izejas kodu

feat: implement checklist UI

nathan 2 gadi atpakaļ
vecāks
revīzija
1ba299815e
64 mainītis faili ar 715 papildinājumiem un 110 dzēšanām
  1. 3 0
      frontend/app_flowy/assets/translations/en.json
  2. 1 1
      frontend/app_flowy/lib/plugins/board/presentation/board_page.dart
  3. 1 1
      frontend/app_flowy/lib/plugins/board/presentation/card/card_cell_builder.dart
  4. 3 1
      frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_controller.dart
  5. 93 0
      frontend/app_flowy/lib/plugins/grid/application/cell/checklist_cell_bloc.dart
  6. 194 0
      frontend/app_flowy/lib/plugins/grid/application/cell/checklist_cell_editor_bloc.dart
  7. 2 4
      frontend/app_flowy/lib/plugins/grid/application/cell/select_option_editor_bloc.dart
  8. 10 4
      frontend/app_flowy/lib/plugins/grid/application/cell/select_option_service.dart
  9. 1 1
      frontend/app_flowy/lib/plugins/grid/application/field/field_controller.dart
  10. 1 1
      frontend/app_flowy/lib/plugins/grid/application/filter/filter_create_bloc.dart
  11. 2 4
      frontend/app_flowy/lib/plugins/grid/application/filter/filter_service.dart
  12. 3 2
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/cell_builder.dart
  13. 0 17
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell.dart
  14. 91 0
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell.dart
  15. 81 0
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell_editor.dart
  16. 89 0
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart
  17. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/date_cell/date_cell.dart
  18. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/date_cell/date_editor.dart
  19. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_cell.dart
  20. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart
  21. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checkbox.dart
  22. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart
  23. 1 3
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/text.dart
  24. 2 2
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/create_filter_list.dart
  25. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/menu.dart
  26. 1 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/menu_item.dart
  27. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_cell.dart
  28. 2 2
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_extension.dart
  29. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_list.dart
  30. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_option_editor.dart
  31. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/grid_header.dart
  32. 3 3
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/builder.dart
  33. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart
  34. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart
  35. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart
  36. 1 2
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/row/row_detail.dart
  37. 1 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_group.dart
  38. 0 1
      frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_property.dart
  39. 0 1
      frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart
  40. 0 1
      frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart
  41. 2 0
      frontend/app_flowy/packages/flowy_infra_ui/lib/flowy_infra_ui.dart
  42. 4 4
      frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text_field.dart
  43. 7 0
      frontend/app_flowy/pubspec.lock
  44. 1 0
      frontend/app_flowy/pubspec.yaml
  45. 3 3
      frontend/rust-lib/flowy-grid/src/entities/field_entities.rs
  46. 0 6
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/checklist_filter.rs
  47. 2 2
      frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs
  48. 1 1
      frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs
  49. 3 3
      frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs
  50. 3 3
      frontend/rust-lib/flowy-grid/src/services/field/type_option_builder.rs
  51. 32 4
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_filter.rs
  52. 2 2
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_type_option.rs
  53. 1 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_filter.rs
  54. 5 1
      frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs
  55. 5 2
      frontend/rust-lib/flowy-grid/src/services/filter/cache.rs
  56. 2 2
      frontend/rust-lib/flowy-grid/src/services/filter/controller.rs
  57. 1 1
      frontend/rust-lib/flowy-grid/src/services/group/group_util.rs
  58. 1 1
      frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs
  59. 2 2
      frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs
  60. 1 1
      frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs
  61. 27 0
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs
  62. 1 0
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs
  63. 12 1
      frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs
  64. 11 3
      frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs

+ 3 - 0
frontend/app_flowy/assets/translations/en.json

@@ -265,6 +265,9 @@
       "panelTitle": "Select an option or create one",
       "searchOption": "Search for an option"
     },
+    "checklist": {
+      "panelTitle": "Search an option or create one"
+    },
     "menuName": "Grid"
   },
   "document": {

+ 1 - 1
frontend/app_flowy/lib/plugins/board/presentation/board_page.dart

@@ -358,7 +358,7 @@ Widget? _buildHeaderIcon(GroupData customData) {
       break;
     case FieldType.URL:
       break;
-    case FieldType.CheckList:
+    case FieldType.Checklist:
       break;
   }
 

+ 1 - 1
frontend/app_flowy/lib/plugins/board/presentation/card/card_cell_builder.dart

@@ -59,7 +59,7 @@ class BoardCellBuilder {
           editableNotifier: cellNotifier,
           key: key,
         );
-      case FieldType.CheckList:
+      case FieldType.Checklist:
         return BoardChecklistCell(
           key: key,
         );

+ 3 - 1
frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_controller.dart

@@ -5,6 +5,8 @@ typedef GridCheckboxCellController = IGridCellController<String, String>;
 typedef GridNumberCellController = IGridCellController<String, String>;
 typedef GridSelectOptionCellController
     = IGridCellController<SelectOptionCellDataPB, String>;
+typedef GridChecklistCellController
+    = IGridCellController<SelectOptionCellDataPB, String>;
 typedef GridDateCellController
     = IGridCellController<DateCellDataPB, CalendarData>;
 typedef GridURLCellController = IGridCellController<URLCellDataPB, String>;
@@ -81,7 +83,7 @@ class GridCellControllerBuilder {
         );
       case FieldType.MultiSelect:
       case FieldType.SingleSelect:
-      case FieldType.CheckList:
+      case FieldType.Checklist:
         final cellDataLoader = GridCellDataLoader(
           cellId: _cellId,
           parser: SelectOptionCellDataParser(),

+ 93 - 0
frontend/app_flowy/lib/plugins/grid/application/cell/checklist_cell_bloc.dart

@@ -0,0 +1,93 @@
+import 'package:flowy_sdk/log.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+import 'dart:async';
+import 'cell_service/cell_service.dart';
+import 'select_option_service.dart';
+part 'checklist_cell_bloc.freezed.dart';
+
+class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
+  final GridChecklistCellController cellController;
+  final SelectOptionFFIService _selectOptionService;
+  void Function()? _onCellChangedFn;
+  ChecklistCellBloc({
+    required this.cellController,
+  })  : _selectOptionService =
+            SelectOptionFFIService(cellId: cellController.cellId),
+        super(ChecklistCellState.initial(cellController)) {
+    on<ChecklistCellEvent>(
+      (event, emit) async {
+        await event.when(
+          initial: () async {
+            _startListening();
+            _loadOptions();
+          },
+          didReceiveOptions: (data) {
+            emit(state.copyWith(
+              allOptions: data.options,
+              selectedOptions: data.selectOptions,
+              percent: data.selectOptions.length.toDouble() /
+                  data.options.length.toDouble(),
+            ));
+          },
+        );
+      },
+    );
+  }
+
+  @override
+  Future<void> close() async {
+    if (_onCellChangedFn != null) {
+      cellController.removeListener(_onCellChangedFn!);
+      _onCellChangedFn = null;
+    }
+    await cellController.dispose();
+    return super.close();
+  }
+
+  void _startListening() {
+    _onCellChangedFn = cellController.startListening(
+      onCellFieldChanged: () {
+        _loadOptions();
+      },
+      onCellChanged: (_) {},
+    );
+  }
+
+  void _loadOptions() {
+    _selectOptionService.getOptionContext().then((result) {
+      if (isClosed) return;
+
+      return result.fold(
+        (data) => add(ChecklistCellEvent.didReceiveOptions(data)),
+        (err) => Log.error(err),
+      );
+    });
+  }
+}
+
+@freezed
+class ChecklistCellEvent with _$ChecklistCellEvent {
+  const factory ChecklistCellEvent.initial() = _InitialCell;
+  const factory ChecklistCellEvent.didReceiveOptions(
+      SelectOptionCellDataPB data) = _DidReceiveCellUpdate;
+}
+
+@freezed
+class ChecklistCellState with _$ChecklistCellState {
+  const factory ChecklistCellState({
+    required List<SelectOptionPB> allOptions,
+    required List<SelectOptionPB> selectedOptions,
+    required double percent,
+  }) = _ChecklistCellState;
+
+  factory ChecklistCellState.initial(
+      GridChecklistCellController cellController) {
+    return const ChecklistCellState(
+      allOptions: [],
+      selectedOptions: [],
+      percent: 0,
+    );
+  }
+}

+ 194 - 0
frontend/app_flowy/lib/plugins/grid/application/cell/checklist_cell_editor_bloc.dart

@@ -0,0 +1,194 @@
+import 'dart:async';
+
+import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
+import 'package:dartz/dartz.dart';
+import 'package:flowy_sdk/log.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:freezed_annotation/freezed_annotation.dart';
+
+import 'select_option_service.dart';
+
+part 'checklist_cell_editor_bloc.freezed.dart';
+
+class ChecklistCellEditorBloc
+    extends Bloc<ChecklistCellEditorEvent, ChecklistCellEditorState> {
+  final SelectOptionFFIService _selectOptionService;
+  final GridChecklistCellController cellController;
+  Timer? _delayOperation;
+
+  ChecklistCellEditorBloc({
+    required this.cellController,
+  })  : _selectOptionService =
+            SelectOptionFFIService(cellId: cellController.cellId),
+        super(ChecklistCellEditorState.initial(cellController)) {
+    on<ChecklistCellEditorEvent>(
+      (event, emit) async {
+        await event.when(
+          initial: () async {
+            _startListening();
+            _loadOptions();
+          },
+          didReceiveOptions: (data) {
+            emit(state.copyWith(
+              allOptions: _makeChecklistSelectOptions(data, state.predicate),
+              percent: _percentFromSelectOptionCellData(data),
+            ));
+          },
+          newOption: (optionName) {
+            _createOption(optionName);
+            emit(state.copyWith(
+              predicate: '',
+            ));
+          },
+          deleteOption: (option) {
+            _deleteOption([option]);
+          },
+          updateOption: (option) {
+            _updateOption(option);
+          },
+          selectOption: (optionId) {
+            _selectOptionService.select(optionIds: [optionId]);
+          },
+          unSelectOption: (optionId) {
+            _selectOptionService.unSelect(optionIds: [optionId]);
+          },
+          filterOption: (String predicate) {},
+        );
+      },
+    );
+  }
+
+  @override
+  Future<void> close() async {
+    _delayOperation?.cancel();
+    await cellController.dispose();
+    return super.close();
+  }
+
+  void _createOption(String name) async {
+    final result = await _selectOptionService.create(
+      name: name,
+      isSelected: false,
+    );
+    result.fold((l) => {}, (err) => Log.error(err));
+  }
+
+  void _deleteOption(List<SelectOptionPB> options) async {
+    final result = await _selectOptionService.delete(options: options);
+    result.fold((l) => null, (err) => Log.error(err));
+  }
+
+  void _updateOption(SelectOptionPB option) async {
+    final result = await _selectOptionService.update(
+      option: option,
+    );
+
+    result.fold((l) => null, (err) => Log.error(err));
+  }
+
+  void _loadOptions() {
+    _selectOptionService.getOptionContext().then((result) {
+      if (isClosed) return;
+
+      return result.fold(
+        (data) => add(ChecklistCellEditorEvent.didReceiveOptions(data)),
+        (err) => Log.error(err),
+      );
+    });
+  }
+
+  void _startListening() {
+    cellController.startListening(
+      onCellChanged: ((data) {
+        if (!isClosed && data != null) {
+          add(ChecklistCellEditorEvent.didReceiveOptions(data));
+        }
+      }),
+      onCellFieldChanged: () {
+        _loadOptions();
+      },
+    );
+  }
+}
+
+@freezed
+class ChecklistCellEditorEvent with _$ChecklistCellEditorEvent {
+  const factory ChecklistCellEditorEvent.initial() = _Initial;
+  const factory ChecklistCellEditorEvent.didReceiveOptions(
+      SelectOptionCellDataPB data) = _DidReceiveOptions;
+  const factory ChecklistCellEditorEvent.newOption(String optionName) =
+      _NewOption;
+  const factory ChecklistCellEditorEvent.selectOption(String optionId) =
+      _SelectOption;
+  const factory ChecklistCellEditorEvent.unSelectOption(String optionId) =
+      _UnSelectOption;
+  const factory ChecklistCellEditorEvent.updateOption(SelectOptionPB option) =
+      _UpdateOption;
+  const factory ChecklistCellEditorEvent.deleteOption(SelectOptionPB option) =
+      _DeleteOption;
+  const factory ChecklistCellEditorEvent.filterOption(String predicate) =
+      _FilterOption;
+}
+
+@freezed
+class ChecklistCellEditorState with _$ChecklistCellEditorState {
+  const factory ChecklistCellEditorState({
+    required List<ChecklistSelectOption> allOptions,
+    required Option<String> createOption,
+    required double percent,
+    required String predicate,
+  }) = _ChecklistCellEditorState;
+
+  factory ChecklistCellEditorState.initial(
+      GridSelectOptionCellController context) {
+    final data = context.getCellData(loadIfNotExist: true);
+
+    return ChecklistCellEditorState(
+      allOptions: _makeChecklistSelectOptions(data, ''),
+      createOption: none(),
+      percent: _percentFromSelectOptionCellData(data),
+      predicate: '',
+    );
+  }
+}
+
+double _percentFromSelectOptionCellData(SelectOptionCellDataPB? data) {
+  if (data == null) return 0;
+
+  final a = data.selectOptions.length.toDouble();
+  final b = data.options.length.toDouble();
+
+  if (a > b) return 1.0;
+
+  return a / b;
+}
+
+List<ChecklistSelectOption> _makeChecklistSelectOptions(
+    SelectOptionCellDataPB? data, String predicate) {
+  if (data == null) {
+    return [];
+  }
+
+  final List<ChecklistSelectOption> options = [];
+  final List<SelectOptionPB> allOptions = List.from(data.options);
+  if (predicate.isNotEmpty) {
+    allOptions.retainWhere((element) => element.name.contains(predicate));
+  }
+  final selectedOptionIds = data.selectOptions.map((e) => e.id).toList();
+
+  for (final option in allOptions) {
+    options.add(
+      ChecklistSelectOption(selectedOptionIds.contains(option.id), option),
+    );
+  }
+
+  return options;
+}
+
+class ChecklistSelectOption {
+  final bool isSelected;
+  final SelectOptionPB data;
+
+  ChecklistSelectOption(this.isSelected, this.data);
+}

+ 2 - 4
frontend/app_flowy/lib/plugins/grid/application/cell/select_option_editor_bloc.dart

@@ -1,26 +1,24 @@
 import 'dart:async';
-
 import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
 import 'package:dartz/dartz.dart';
 import 'package:flowy_sdk/log.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
-
 import 'select_option_service.dart';
 
 part 'select_option_editor_bloc.freezed.dart';
 
 class SelectOptionCellEditorBloc
     extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> {
-  final SelectOptionService _selectOptionService;
+  final SelectOptionFFIService _selectOptionService;
   final GridSelectOptionCellController cellController;
   Timer? _delayOperation;
 
   SelectOptionCellEditorBloc({
     required this.cellController,
   })  : _selectOptionService =
-            SelectOptionService(cellId: cellController.cellId),
+            SelectOptionFFIService(cellId: cellController.cellId),
         super(SelectOptionEditorState.initial(cellController)) {
     on<SelectOptionEditorEvent>(
       (event, emit) async {

+ 10 - 4
frontend/app_flowy/lib/plugins/grid/application/cell/select_option_service.dart

@@ -6,15 +6,16 @@ import 'package:app_flowy/plugins/grid/application/field/type_option/type_option
 import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
 import 'cell_service/cell_service.dart';
 
-class SelectOptionService {
+class SelectOptionFFIService {
   final GridCellIdentifier cellId;
-  SelectOptionService({required this.cellId});
+  SelectOptionFFIService({required this.cellId});
 
   String get gridId => cellId.gridId;
   String get fieldId => cellId.fieldInfo.id;
   String get rowId => cellId.rowId;
 
-  Future<Either<Unit, FlowyError>> create({required String name}) {
+  Future<Either<Unit, FlowyError>> create(
+      {required String name, bool isSelected = true}) {
     return TypeOptionFFIService(gridId: gridId, fieldId: fieldId)
         .newOption(name: name)
         .then(
@@ -26,8 +27,13 @@ class SelectOptionService {
               ..fieldId = fieldId
               ..rowId = rowId;
             final payload = SelectOptionChangesetPB.create()
-              ..insertOptions.add(option)
               ..cellIdentifier = cellIdentifier;
+
+            if (isSelected) {
+              payload.insertOptions.add(option);
+            } else {
+              payload.updateOptions.add(option);
+            }
             return GridEventUpdateSelectOption(payload).send();
           },
           (r) => right(r),

+ 1 - 1
frontend/app_flowy/lib/plugins/grid/application/field/field_controller.dart

@@ -503,7 +503,7 @@ class FieldInfo {
 
   bool get hasFilter => _hasFilter;
 
-  bool get canGroup {
+  bool get canBeGroup {
     switch (_field.fieldType) {
       case FieldType.Checkbox:
       case FieldType.MultiSelect:

+ 1 - 1
frontend/app_flowy/lib/plugins/grid/application/filter/filter_create_bloc.dart

@@ -105,7 +105,7 @@ class GridCreateFilterBloc
           condition: SelectOptionCondition.OptionIs,
           fieldType: FieldType.MultiSelect,
         );
-      case FieldType.CheckList:
+      case FieldType.Checklist:
         return _ffiService.insertChecklistFilter(
           fieldId: fieldId,
           condition: ChecklistFilterCondition.IsIncomplete,

+ 2 - 4
frontend/app_flowy/lib/plugins/grid/application/filter/filter_service.dart

@@ -152,14 +152,12 @@ class FilterFFIService {
     String? filterId,
     List<String> optionIds = const [],
   }) {
-    final filter = ChecklistFilterPB()
-      ..condition = condition
-      ..optionIds.addAll(optionIds);
+    final filter = ChecklistFilterPB()..condition = condition;
 
     return insertFilter(
       fieldId: fieldId,
       filterId: filterId,
-      fieldType: FieldType.CheckList,
+      fieldType: FieldType.Checklist,
       data: filter.writeToBuffer(),
     );
   }

+ 3 - 2
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/cell_builder.dart

@@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
 import 'cell_accessory.dart';
 import 'cell_shortcuts.dart';
 import 'checkbox_cell.dart';
-import 'checklist_cell.dart';
+import 'checklist_cell/checklist_cell.dart';
 import 'date_cell/date_cell.dart';
 import 'number_cell.dart';
 import 'select_option_cell/select_option_cell.dart';
@@ -56,8 +56,9 @@ class GridCellBuilder {
           style: style,
           key: key,
         );
-      case FieldType.CheckList:
+      case FieldType.Checklist:
         return GridChecklistCell(
+          cellControllerBuilder: cellControllerBuilder,
           key: key,
         );
       case FieldType.Number:

+ 0 - 17
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell.dart

@@ -1,17 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'cell_builder.dart';
-
-class GridChecklistCell extends GridCellWidget {
-  GridChecklistCell({Key? key}) : super(key: key);
-
-  @override
-  ChecklistCellState createState() => ChecklistCellState();
-}
-
-class ChecklistCellState extends State<GridChecklistCell> {
-  @override
-  Widget build(BuildContext context) {
-    return Container();
-  }
-}

+ 91 - 0
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell.dart

@@ -0,0 +1,91 @@
+import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
+import 'package:app_flowy/plugins/grid/application/cell/checklist_cell_bloc.dart';
+import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
+import 'package:appflowy_popover/appflowy_popover.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import '../cell_builder.dart';
+import 'checklist_cell_editor.dart';
+import 'checklist_prograss_bar.dart';
+
+class GridChecklistCell extends GridCellWidget {
+  final GridCellControllerBuilder cellControllerBuilder;
+  GridChecklistCell({required this.cellControllerBuilder, Key? key})
+      : super(key: key);
+
+  @override
+  GridChecklistCellState createState() => GridChecklistCellState();
+}
+
+class GridChecklistCellState extends State<GridChecklistCell> {
+  late PopoverController _popover;
+  late ChecklistCellBloc _cellBloc;
+
+  @override
+  void initState() {
+    _popover = PopoverController();
+    final cellController =
+        widget.cellControllerBuilder.build() as GridChecklistCellController;
+    _cellBloc = ChecklistCellBloc(cellController: cellController);
+    _cellBloc.add(const ChecklistCellEvent.initial());
+    super.initState();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocProvider.value(
+      value: _cellBloc,
+      child: BlocBuilder<ChecklistCellBloc, ChecklistCellState>(
+        builder: (context, state) {
+          return Stack(
+            alignment: AlignmentDirectional.center,
+            fit: StackFit.expand,
+            children: [
+              Padding(
+                padding: GridSize.cellContentInsets,
+                child: _wrapPopover(const ChecklistProgressBar()),
+              ),
+              InkWell(onTap: () => _popover.show()),
+            ],
+          );
+        },
+      ),
+    );
+  }
+
+  Widget _wrapPopover(Widget child) {
+    return AppFlowyPopover(
+      controller: _popover,
+      constraints: BoxConstraints.loose(const Size(260, 400)),
+      direction: PopoverDirection.bottomWithLeftAligned,
+      triggerActions: PopoverTriggerFlags.none,
+      popupBuilder: (BuildContext context) {
+        WidgetsBinding.instance.addPostFrameCallback((_) {
+          widget.onCellEditing.value = true;
+        });
+        return GridChecklistCellEditor(
+          cellController: widget.cellControllerBuilder.build()
+              as GridChecklistCellController,
+        );
+      },
+      onClose: () => widget.onCellEditing.value = false,
+      child: child,
+    );
+  }
+}
+
+class ChecklistProgressBar extends StatelessWidget {
+  const ChecklistProgressBar({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<ChecklistCellBloc, ChecklistCellState>(
+      builder: (context, state) {
+        return ChecklistPrograssBar(
+          percent: state.percent,
+        );
+      },
+    );
+  }
+}

+ 81 - 0
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell_editor.dart

@@ -0,0 +1,81 @@
+import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
+import 'package:app_flowy/plugins/grid/application/cell/checklist_cell_editor_bloc.dart';
+import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
+import 'package:app_flowy/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart';
+import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
+import 'package:flowy_infra_ui/widget/spacing.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+class GridChecklistCellEditor extends StatefulWidget {
+  final GridChecklistCellController cellController;
+  const GridChecklistCellEditor({required this.cellController, Key? key})
+      : super(key: key);
+
+  @override
+  State<GridChecklistCellEditor> createState() =>
+      _GridChecklistCellEditorState();
+}
+
+class _GridChecklistCellEditorState extends State<GridChecklistCellEditor> {
+  late ChecklistCellEditorBloc bloc;
+
+  @override
+  void initState() {
+    bloc = ChecklistCellEditorBloc(cellController: widget.cellController);
+    bloc.add(const ChecklistCellEditorEvent.initial());
+    super.initState();
+  }
+
+  @override
+  void dispose() {
+    bloc.close();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocProvider.value(
+      value: bloc,
+      child: BlocBuilder<ChecklistCellEditorBloc, ChecklistCellEditorState>(
+        builder: (context, state) {
+          final List<Widget> slivers = [
+            const SliverChecklistPrograssBar(),
+            SliverToBoxAdapter(
+              child: ListView.separated(
+                controller: ScrollController(),
+                shrinkWrap: true,
+                itemCount: state.allOptions.length,
+                itemBuilder: (BuildContext context, int index) {
+                  return _ChecklistOptionCell(option: state.allOptions[index]);
+                },
+                separatorBuilder: (BuildContext context, int index) {
+                  return VSpace(GridSize.typeOptionSeparatorHeight);
+                },
+              ),
+            ),
+          ];
+          return CustomScrollView(
+            shrinkWrap: true,
+            slivers: slivers,
+            controller: ScrollController(),
+            physics: StyledScrollPhysics(),
+          );
+        },
+      ),
+    );
+  }
+}
+
+class _ChecklistOptionCell extends StatelessWidget {
+  final ChecklistSelectOption option;
+  const _ChecklistOptionCell({
+    required this.option,
+    Key? key,
+  }) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(height: 20, width: 100, color: Colors.red);
+  }
+}

+ 89 - 0
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart

@@ -0,0 +1,89 @@
+import 'package:app_flowy/generated/locale_keys.g.dart';
+import 'package:app_flowy/plugins/grid/application/cell/checklist_cell_editor_bloc.dart';
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flowy_infra/color_extension.dart';
+import 'package:flowy_infra_ui/flowy_infra_ui.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:percent_indicator/percent_indicator.dart';
+
+class ChecklistPrograssBar extends StatelessWidget {
+  final double percent;
+  const ChecklistPrograssBar({required this.percent, Key? key})
+      : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return LinearPercentIndicator(
+      lineHeight: 10.0,
+      percent: percent,
+      progressColor: Theme.of(context).colorScheme.primary,
+      backgroundColor: AFThemeExtension.of(context).tint9,
+      barRadius: const Radius.circular(5),
+    );
+  }
+}
+
+class SliverChecklistPrograssBar extends StatelessWidget {
+  const SliverChecklistPrograssBar({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return SliverPersistentHeader(
+      pinned: true,
+      delegate: _SliverChecklistPrograssBarDelegate(),
+    );
+  }
+}
+
+class _SliverChecklistPrograssBarDelegate
+    extends SliverPersistentHeaderDelegate {
+  _SliverChecklistPrograssBarDelegate();
+
+  double fixHeight = 80;
+
+  @override
+  Widget build(
+      BuildContext context, double shrinkOffset, bool overlapsContent) {
+    return BlocBuilder<ChecklistCellEditorBloc, ChecklistCellEditorState>(
+      builder: (context, state) {
+        return Column(
+          children: [
+            if (state.percent != 0)
+              Padding(
+                padding: const EdgeInsets.symmetric(vertical: 8.0),
+                child: ChecklistPrograssBar(percent: state.percent),
+              ),
+            Padding(
+              padding: const EdgeInsets.all(8.0),
+              child: FlowyTextField(
+                hintText: LocaleKeys.grid_checklist_panelTitle.tr(),
+                onChanged: (text) {
+                  context
+                      .read<ChecklistCellEditorBloc>()
+                      .add(ChecklistCellEditorEvent.filterOption(text));
+                },
+                onSubmitted: (text) {
+                  context
+                      .read<ChecklistCellEditorBloc>()
+                      .add(ChecklistCellEditorEvent.newOption(text));
+                },
+              ),
+            )
+          ],
+        );
+      },
+    );
+  }
+
+  @override
+  double get maxExtent => fixHeight;
+
+  @override
+  double get minExtent => fixHeight;
+
+  @override
+  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
+    return false;
+  }
+}

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/date_cell/date_cell.dart

@@ -1,5 +1,4 @@
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:app_flowy/startup/startup.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/date_cell/date_editor.dart

@@ -11,7 +11,6 @@ import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra/size.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/log.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_cell.dart

@@ -3,7 +3,6 @@ import 'package:app_flowy/plugins/grid/application/prelude.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 // ignore: unused_import
 import 'package:flowy_sdk/log.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart

@@ -9,7 +9,6 @@ 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/scrolling/styled_list.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/checkbox.dart

@@ -8,7 +8,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_filter.pbenum.dart';
 import 'package:flutter/material.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/select_option/select_option.dart

@@ -4,7 +4,6 @@ import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.d
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/select_option_filter.pb.dart';

+ 1 - 3
frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/choicechip/text.dart

@@ -3,13 +3,11 @@ import 'package:app_flowy/plugins/grid/application/filter/text_filter_editor_blo
 import 'package:app_flowy/plugins/grid/presentation/widgets/filter/condition_button.dart';
 import 'package:app_flowy/plugins/grid/presentation/widgets/filter/disclosure_button.dart';
 import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.dart';
-import 'package:app_flowy/plugins/grid/presentation/widgets/filter/text_field.dart';
 import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/text_filter.pb.dart';
 import 'package:flutter/material.dart';
@@ -151,7 +149,7 @@ class _TextFilterEditorState extends State<TextFilterEditor> {
 
   Widget _buildFilterTextField(
       BuildContext context, TextFilterEditorState state) {
-    return FilterTextField(
+    return FlowyTextField(
       text: state.filter.content,
       hintText: LocaleKeys.grid_settings_typeAValue.tr(),
       autoFucous: false,

+ 2 - 2
frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/create_filter_list.dart

@@ -2,13 +2,13 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
 import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
 import 'package:app_flowy/plugins/grid/application/filter/filter_create_bloc.dart';
 import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
-import 'package:app_flowy/plugins/grid/presentation/widgets/filter/text_field.dart';
 import 'package:app_flowy/plugins/grid/presentation/widgets/header/field_type_extension.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
+import 'package:flowy_infra_ui/style_widget/text_field.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
@@ -121,7 +121,7 @@ class _FilterTextFieldDelegate extends SliverPersistentHeaderDelegate {
       child: Container(
         color: Theme.of(context).colorScheme.background,
         height: fixHeight,
-        child: FilterTextField(
+        child: FlowyTextField(
           hintText: LocaleKeys.grid_settings_filterBy.tr(),
           onChanged: (text) {
             context

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/menu.dart

@@ -7,7 +7,6 @@ import 'package:flowy_infra/color_extension.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';

+ 1 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/menu_item.dart

@@ -36,7 +36,7 @@ Widget buildFilterChoicechip(FilterInfo filterInfo) {
       return SelectOptionFilterChoicechip(filterInfo: filterInfo);
     case FieldType.URL:
       return URLFilterChoicechip(filterInfo: filterInfo);
-    case FieldType.CheckList:
+    case FieldType.Checklist:
       return ChecklistFilterChoicechip(filterInfo: filterInfo);
     default:
       return const SizedBox();

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_cell.dart

@@ -6,7 +6,6 @@ import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/hover.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';

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

@@ -19,7 +19,7 @@ extension FieldTypeListExtension on FieldType {
         return "grid/field/single_select";
       case FieldType.URL:
         return "grid/field/url";
-      case FieldType.CheckList:
+      case FieldType.Checklist:
         return "grid/field/checklist";
     }
     throw UnimplementedError;
@@ -41,7 +41,7 @@ extension FieldTypeListExtension on FieldType {
         return LocaleKeys.grid_field_singleSelectFieldName.tr();
       case FieldType.URL:
         return LocaleKeys.grid_field_urlFieldName.tr();
-      case FieldType.CheckList:
+      case FieldType.Checklist:
         return LocaleKeys.grid_field_checklistFieldName.tr();
     }
     throw UnimplementedError;

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_list.dart

@@ -3,7 +3,6 @@ import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
 import 'package:flutter/material.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/field_type_option_editor.dart

@@ -5,7 +5,6 @@ import 'package:dartz/dartz.dart' show Either;
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
 import 'package:flutter/material.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/grid_header.dart

@@ -9,7 +9,6 @@ import 'package:flowy_infra/color_extension.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';

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

@@ -5,10 +5,10 @@ import 'package:app_flowy/plugins/grid/application/field/type_option/type_option
 import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_data_controller.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/checklist_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/number_type_option.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/single_select_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
@@ -127,7 +127,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
         ),
       );
 
-    case FieldType.CheckList:
+    case FieldType.Checklist:
       return ChecklistTypeOptionWidgetBuilder(
         makeTypeOptionContextWithDataController<ChecklistTypeOptionPB>(
           gridId: gridId,
@@ -217,7 +217,7 @@ TypeOptionContext<T>
         dataController: dataController,
         dataParser: MultiSelectTypeOptionWidgetDataParser(),
       ) as TypeOptionContext<T>;
-    case FieldType.CheckList:
+    case FieldType.Checklist:
       return ChecklistTypeOptionContext(
         dataController: dataController,
         dataParser: ChecklistTypeOptionWidgetDataParser(),

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart

@@ -7,7 +7,6 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';
 import 'package:flutter/material.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart

@@ -5,7 +5,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/format.pbenum.dart';
 import 'package:flutter/material.dart';

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart

@@ -3,7 +3,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
 import 'package:flutter/material.dart';

+ 1 - 2
frontend/app_flowy/lib/plugins/grid/presentation/widgets/row/row_detail.dart

@@ -9,7 +9,6 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.dart';
 import 'package:flowy_infra_ui/style_widget/icon_button.dart';
 import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:app_flowy/generated/locale_keys.g.dart';
@@ -331,7 +330,7 @@ GridCellStyle? _customCellStyle(FieldType fieldType) {
       return SelectOptionCellStyle(
         placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
       );
-    case FieldType.CheckList:
+    case FieldType.Checklist:
       return SelectOptionCellStyle(
         placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
       );

+ 1 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_group.dart

@@ -37,7 +37,7 @@ class GridGroupList extends StatelessWidget {
               key: ValueKey(fieldInfo.id),
             );
 
-            if (!fieldInfo.canGroup) {
+            if (!fieldInfo.canBeGroup) {
               cell = IgnorePointer(child: Opacity(opacity: 0.3, child: cell));
             }
             return cell;

+ 0 - 1
frontend/app_flowy/lib/plugins/grid/presentation/widgets/toolbar/grid_property.dart

@@ -8,7 +8,6 @@ import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/button.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:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';

+ 0 - 1
frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart

@@ -6,7 +6,6 @@ import 'package:app_flowy/workspace/presentation/settings/widgets/settings_user_
 import 'package:app_flowy/workspace/presentation/settings/widgets/settings_menu.dart';
 import 'package:app_flowy/workspace/application/settings/settings_dialog_bloc.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';

+ 0 - 1
frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart

@@ -1,7 +1,6 @@
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flowy_infra_ui/style_widget/hover.dart';
-import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flutter/material.dart';
 import 'package:styled_widget/styled_widget.dart';

+ 2 - 0
frontend/app_flowy/packages/flowy_infra_ui/lib/flowy_infra_ui.dart

@@ -10,3 +10,5 @@ export 'src/flowy_overlay/list_overlay.dart';
 export 'src/flowy_overlay/option_overlay.dart';
 export 'src/flowy_overlay/flowy_dialog.dart';
 export 'src/flowy_overlay/appflowy_popover.dart';
+export 'style_widget/text.dart';
+export 'style_widget/text_field.dart';

+ 4 - 4
frontend/app_flowy/lib/plugins/grid/presentation/widgets/filter/text_field.dart → frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text_field.dart

@@ -1,13 +1,13 @@
 import 'package:flowy_infra/size.dart';
 import 'package:flutter/material.dart';
 
-class FilterTextField extends StatefulWidget {
+class FlowyTextField extends StatefulWidget {
   final String hintText;
   final String text;
   final void Function(String)? onChanged;
   final void Function(String)? onSubmitted;
   final bool autoFucous;
-  const FilterTextField({
+  const FlowyTextField({
     this.hintText = "",
     this.text = "",
     this.onChanged,
@@ -17,10 +17,10 @@ class FilterTextField extends StatefulWidget {
   }) : super(key: key);
 
   @override
-  State<FilterTextField> createState() => FilterTextFieldState();
+  State<FlowyTextField> createState() => FlowyTextFieldState();
 }
 
-class FilterTextFieldState extends State<FilterTextField> {
+class FlowyTextFieldState extends State<FlowyTextField> {
   late FocusNode focusNode;
   late TextEditingController controller;
 

+ 7 - 0
frontend/app_flowy/pubspec.lock

@@ -862,6 +862,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "2.0.6"
+  percent_indicator:
+    dependency: "direct main"
+    description:
+      name: percent_indicator
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "4.2.2"
   petitparser:
     dependency: transitive
     description:

+ 1 - 0
frontend/app_flowy/pubspec.yaml

@@ -90,6 +90,7 @@ dependencies:
   shared_preferences: ^2.0.15
   google_fonts: ^3.0.1
   file_picker: <=5.0.0
+  percent_indicator: ^4.0.1
 
 dev_dependencies:
   flutter_lints: ^2.0.1

+ 3 - 3
frontend/rust-lib/flowy-grid/src/entities/field_entities.rs

@@ -491,7 +491,7 @@ pub enum FieldType {
     MultiSelect = 4,
     Checkbox = 5,
     URL = 6,
-    CheckList = 7,
+    Checklist = 7,
 }
 
 pub const RICH_TEXT_FIELD: FieldType = FieldType::RichText;
@@ -501,7 +501,7 @@ pub const SINGLE_SELECT_FIELD: FieldType = FieldType::SingleSelect;
 pub const MULTI_SELECT_FIELD: FieldType = FieldType::MultiSelect;
 pub const CHECKBOX_FIELD: FieldType = FieldType::Checkbox;
 pub const URL_FIELD: FieldType = FieldType::URL;
-pub const CHECKLIST_FIELD: FieldType = FieldType::CheckList;
+pub const CHECKLIST_FIELD: FieldType = FieldType::Checklist;
 
 impl std::default::Default for FieldType {
     fn default() -> Self {
@@ -602,7 +602,7 @@ impl std::convert::From<FieldTypeRevision> for FieldType {
             4 => FieldType::MultiSelect,
             5 => FieldType::Checkbox,
             6 => FieldType::URL,
-            7 => FieldType::CheckList,
+            7 => FieldType::Checklist,
             _ => {
                 tracing::error!("Can't convert FieldTypeRevision: {} to FieldType", ty);
                 FieldType::RichText

+ 0 - 6
frontend/rust-lib/flowy-grid/src/entities/filter_entities/checklist_filter.rs

@@ -1,4 +1,3 @@
-use crate::services::field::SelectOptionIds;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use grid_rev_model::FilterRevision;
@@ -7,9 +6,6 @@ use grid_rev_model::FilterRevision;
 pub struct ChecklistFilterPB {
     #[pb(index = 1)]
     pub condition: ChecklistFilterCondition,
-
-    #[pb(index = 2)]
-    pub option_ids: Vec<String>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, ProtoBuf_Enum)]
@@ -45,11 +41,9 @@ impl std::convert::TryFrom<u8> for ChecklistFilterCondition {
 
 impl std::convert::From<&FilterRevision> for ChecklistFilterPB {
     fn from(rev: &FilterRevision) -> Self {
-        let ids = SelectOptionIds::from(rev.content.clone());
         ChecklistFilterPB {
             condition: ChecklistFilterCondition::try_from(rev.condition)
                 .unwrap_or(ChecklistFilterCondition::IsIncomplete),
-            option_ids: ids.into_inner(),
         }
     }
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs

@@ -36,7 +36,7 @@ impl std::convert::From<&FilterRevision> for FilterPB {
             FieldType::DateTime => DateFilterPB::from(rev).try_into().unwrap(),
             FieldType::SingleSelect => SelectOptionFilterPB::from(rev).try_into().unwrap(),
             FieldType::MultiSelect => SelectOptionFilterPB::from(rev).try_into().unwrap(),
-            FieldType::CheckList => ChecklistFilterPB::from(rev).try_into().unwrap(),
+            FieldType::Checklist => ChecklistFilterPB::from(rev).try_into().unwrap(),
             FieldType::Checkbox => CheckboxFilterPB::from(rev).try_into().unwrap(),
             FieldType::URL => TextFilterPB::from(rev).try_into().unwrap(),
         };
@@ -176,7 +176,7 @@ impl TryInto<AlterFilterParams> for AlterFilterPayloadPB {
                 }
                 .to_string();
             }
-            FieldType::SingleSelect | FieldType::MultiSelect | FieldType::CheckList => {
+            FieldType::SingleSelect | FieldType::MultiSelect | FieldType::Checklist => {
                 let filter = SelectOptionFilterPB::try_from(bytes).map_err(|_| ErrorCode::ProtobufSerde)?;
                 condition = filter.condition as u8;
                 content = SelectOptionIds::from(filter.option_ids).to_string();

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs

@@ -105,7 +105,7 @@ impl TypeCellData {
         self.field_type == FieldType::MultiSelect
     }
     pub fn is_checklist(&self) -> bool {
-        self.field_type == FieldType::CheckList
+        self.field_type == FieldType::Checklist
     }
 
     pub fn is_url(&self) -> bool {

+ 3 - 3
frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs

@@ -122,7 +122,7 @@ pub fn apply_cell_data_changeset<C: ToString, T: AsRef<FieldRevision>>(
             SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev)
         }
         FieldType::MultiSelect => MultiSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
-        FieldType::CheckList => ChecklistTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
+        FieldType::Checklist => ChecklistTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
         FieldType::Checkbox => CheckboxTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
         FieldType::URL => URLTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev),
     }?;
@@ -181,7 +181,7 @@ pub fn decode_cell_data_to_string(
             FieldType::MultiSelect => field_rev
                 .get_type_option::<MultiSelectTypeOptionPB>(field_type)?
                 .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
-            FieldType::CheckList => field_rev
+            FieldType::Checklist => field_rev
                 .get_type_option::<ChecklistTypeOptionPB>(field_type)?
                 .displayed_cell_string(cell_data.into(), from_field_type, field_rev),
             FieldType::Checkbox => field_rev
@@ -234,7 +234,7 @@ pub fn try_decode_cell_data(
             FieldType::MultiSelect => field_rev
                 .get_type_option::<MultiSelectTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), from_field_type, field_rev),
-            FieldType::CheckList => field_rev
+            FieldType::Checklist => field_rev
                 .get_type_option::<ChecklistTypeOptionPB>(field_type)?
                 .decode_cell_data(cell_data.into(), from_field_type, field_rev),
             FieldType::Checkbox => field_rev

+ 3 - 3
frontend/rust-lib/flowy-grid/src/services/field/type_option_builder.rs

@@ -38,7 +38,7 @@ pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box<dyn
         FieldType::MultiSelect => MultiSelectTypeOptionPB::default().into(),
         FieldType::Checkbox => CheckboxTypeOptionPB::default().into(),
         FieldType::URL => URLTypeOptionPB::default().into(),
-        FieldType::CheckList => ChecklistTypeOptionPB::default().into(),
+        FieldType::Checklist => ChecklistTypeOptionPB::default().into(),
     };
 
     type_option_builder_from_json_str(&s, field_type)
@@ -53,7 +53,7 @@ pub fn type_option_builder_from_json_str(s: &str, field_type: &FieldType) -> Box
         FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_json_str(s)),
         FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_json_str(s)),
         FieldType::URL => Box::new(URLTypeOptionBuilder::from_json_str(s)),
-        FieldType::CheckList => Box::new(ChecklistTypeOptionBuilder::from_json_str(s)),
+        FieldType::Checklist => Box::new(ChecklistTypeOptionBuilder::from_json_str(s)),
     }
 }
 
@@ -67,6 +67,6 @@ pub fn type_option_builder_from_bytes<T: Into<Bytes>>(bytes: T, field_type: &Fie
         FieldType::MultiSelect => Box::new(MultiSelectTypeOptionBuilder::from_protobuf_bytes(bytes)),
         FieldType::Checkbox => Box::new(CheckboxTypeOptionBuilder::from_protobuf_bytes(bytes)),
         FieldType::URL => Box::new(URLTypeOptionBuilder::from_protobuf_bytes(bytes)),
-        FieldType::CheckList => Box::new(ChecklistTypeOptionBuilder::from_protobuf_bytes(bytes)),
+        FieldType::Checklist => Box::new(ChecklistTypeOptionBuilder::from_protobuf_bytes(bytes)),
     }
 }

+ 32 - 4
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_filter.rs

@@ -1,8 +1,36 @@
-use crate::entities::ChecklistFilterPB;
-use crate::services::field::SelectedSelectOptions;
+use crate::entities::{ChecklistFilterCondition, ChecklistFilterPB};
+use crate::services::field::{SelectOptionPB, SelectedSelectOptions};
 
 impl ChecklistFilterPB {
-    pub fn is_visible(&self, selected_options: &SelectedSelectOptions) -> bool {
-        true
+    pub fn is_visible(&self, all_options: &[SelectOptionPB], selected_options: &SelectedSelectOptions) -> bool {
+        let selected_option_ids = selected_options
+            .options
+            .iter()
+            .map(|option| option.id.as_str())
+            .collect::<Vec<&str>>();
+
+        let mut all_option_ids = all_options
+            .iter()
+            .map(|option| option.id.as_str())
+            .collect::<Vec<&str>>();
+
+        return match self.condition {
+            ChecklistFilterCondition::IsComplete => {
+                if selected_option_ids.is_empty() {
+                    return false;
+                }
+
+                all_option_ids.retain(|option_id| !selected_option_ids.contains(option_id));
+                all_option_ids.is_empty()
+            }
+            ChecklistFilterCondition::IsIncomplete => {
+                if selected_option_ids.is_empty() {
+                    return true;
+                }
+
+                all_option_ids.retain(|option_id| !selected_option_ids.contains(option_id));
+                !all_option_ids.is_empty()
+            }
+        };
     }
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/checklist_type_option.rs

@@ -22,7 +22,7 @@ pub struct ChecklistTypeOptionPB {
     #[pb(index = 2)]
     pub disable_color: bool,
 }
-impl_type_option!(ChecklistTypeOptionPB, FieldType::CheckList);
+impl_type_option!(ChecklistTypeOptionPB, FieldType::Checklist);
 
 impl SelectTypeOptionSharedAction for ChecklistTypeOptionPB {
     fn number_of_max_options(&self) -> Option<usize> {
@@ -101,7 +101,7 @@ impl ChecklistTypeOptionBuilder {
 
 impl TypeOptionBuilder for ChecklistTypeOptionBuilder {
     fn field_type(&self) -> FieldType {
-        FieldType::CheckList
+        FieldType::Checklist
     }
 
     fn serializer(&self) -> &dyn TypeOptionDataSerializer {

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_filter.rs

@@ -67,7 +67,7 @@ impl CellFilterOperation<ChecklistFilterPB> for ChecklistTypeOptionPB {
             return Ok(true);
         }
         let selected_options = SelectedSelectOptions::from(self.get_selected_options(any_cell_data.into()));
-        Ok(filter.is_visible(&selected_options))
+        Ok(filter.is_visible(&self.options, &selected_options))
     }
 }
 

+ 5 - 1
frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_type_option.rs

@@ -4,7 +4,7 @@ use crate::services::cell::{
     CellBytes, CellBytesParser, CellData, CellDataIsEmpty, CellDisplayable, FromCellChangeset, FromCellString,
 };
 use crate::services::field::selection_type_option::type_option_transform::SelectOptionTypeOptionTransformer;
-use crate::services::field::{MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
+use crate::services::field::{ChecklistTypeOptionPB, MultiSelectTypeOptionPB, SingleSelectTypeOptionPB};
 use bytes::Bytes;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::{internal_error, ErrorCode, FlowyResult};
@@ -212,6 +212,10 @@ pub fn select_type_option_from_field_rev(
             let type_option = MultiSelectTypeOptionPB::from(field_rev);
             Ok(Box::new(type_option))
         }
+        FieldType::Checklist => {
+            let type_option = ChecklistTypeOptionPB::from(field_rev);
+            Ok(Box::new(type_option))
+        }
         ty => {
             tracing::error!("Unsupported field type: {:?} for this handler", ty);
             Err(ErrorCode::FieldInvalidOperation.into())

+ 5 - 2
frontend/rust-lib/flowy-grid/src/services/filter/cache.rs

@@ -29,7 +29,7 @@ impl FilterMap {
             FieldType::MultiSelect => self.select_option_filter.get(filter_type).is_some(),
             FieldType::Checkbox => self.checkbox_filter.get(filter_type).is_some(),
             FieldType::URL => self.url_filter.get(filter_type).is_some(),
-            FieldType::CheckList => self.checklist_filter.get(filter_type).is_some(),
+            FieldType::Checklist => self.checklist_filter.get(filter_type).is_some(),
         }
     }
 
@@ -61,6 +61,9 @@ impl FilterMap {
         if !self.checkbox_filter.is_empty() {
             return false;
         }
+        if !self.checklist_filter.is_empty() {
+            return false;
+        }
         true
     }
 
@@ -87,7 +90,7 @@ impl FilterMap {
             FieldType::URL => {
                 let _ = self.url_filter.remove(filter_id);
             }
-            FieldType::CheckList => {
+            FieldType::Checklist => {
                 let _ = self.checklist_filter.remove(filter_id);
             }
         };

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/filter/controller.rs

@@ -291,7 +291,7 @@ impl FilterController {
                             .url_filter
                             .insert(filter_type, TextFilterPB::from(filter_rev.as_ref()));
                     }
-                    FieldType::CheckList => {
+                    FieldType::Checklist => {
                         let _ = self
                             .filter_map
                             .checklist_filter
@@ -419,7 +419,7 @@ fn filter_cell(
                     .ok(),
             )
         }),
-        FieldType::CheckList => filter_map.checklist_filter.get(filter_id).and_then(|filter| {
+        FieldType::Checklist => filter_map.checklist_filter.get(filter_id).and_then(|filter| {
             Some(
                 field_rev
                     .get_type_option::<ChecklistTypeOptionPB>(field_rev.ty)?

+ 1 - 1
frontend/rust-lib/flowy-grid/src/services/group/group_util.rs

@@ -123,7 +123,7 @@ pub fn default_group_configuration(field_rev: &FieldRevision) -> GroupConfigurat
             SelectOptionGroupConfigurationRevision::default(),
         )
         .unwrap(),
-        FieldType::CheckList => GroupConfigurationRevision::new(
+        FieldType::Checklist => GroupConfigurationRevision::new(
             field_id,
             field_type_rev,
             SelectOptionGroupConfigurationRevision::default(),

+ 1 - 1
frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs

@@ -226,7 +226,7 @@ impl GridRowTest {
                 assert_eq!(s, expected);
             }
 
-            FieldType::CheckList => {
+            FieldType::Checklist => {
                 let cell_data = self
                     .editor
                     .get_cell_bytes(&cell_id)

+ 2 - 2
frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs

@@ -94,12 +94,12 @@ impl<'a> GridRowTestBuilder<'a> {
     where
         F: Fn(Vec<SelectOptionPB>) -> Vec<SelectOptionPB>,
     {
-        let checklist_field = self.field_rev_with_type(&FieldType::CheckList);
+        let checklist_field = self.field_rev_with_type(&FieldType::Checklist);
         let type_option = ChecklistTypeOptionPB::from(&checklist_field);
         let options = f(type_option.options);
         let ops_ids = options.iter().map(|option| option.id.clone()).collect::<Vec<_>>();
         self.inner_builder
-            .insert_select_option_cell(&multi_select_field.id, ops_ids);
+            .insert_select_option_cell(&checklist_field.id, ops_ids);
 
         checklist_field.id.clone()
     }

+ 1 - 1
frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs

@@ -31,7 +31,7 @@ async fn grid_cell_update() {
                     let type_option = MultiSelectTypeOptionPB::from(field_rev);
                     SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id).to_str()
                 }
-                FieldType::CheckList => {
+                FieldType::Checklist => {
                     let type_option = ChecklistTypeOptionPB::from(field_rev);
                     SelectOptionCellChangeset::from_insert_option_id(&type_option.options.first().unwrap().id).to_str()
                 }

+ 27 - 0
frontend/rust-lib/flowy-grid/tests/grid/filter_test/checklist_filter_test.rs

@@ -0,0 +1,27 @@
+use crate::grid::filter_test::script::FilterScript::*;
+use crate::grid::filter_test::script::GridFilterTest;
+use flowy_grid::entities::{ChecklistFilterCondition, SelectOptionCondition};
+
+#[tokio::test]
+async fn grid_filter_checklist_is_incomplete_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateChecklistFilter {
+            condition: ChecklistFilterCondition::IsIncomplete,
+        },
+        AssertNumberOfVisibleRows { expected: 4 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_checklist_is_complete_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateChecklistFilter {
+            condition: ChecklistFilterCondition::IsComplete,
+        },
+        AssertNumberOfVisibleRows { expected: 1 },
+    ];
+    test.run_scripts(scripts).await;
+}

+ 1 - 0
frontend/rust-lib/flowy-grid/tests/grid/filter_test/mod.rs

@@ -1,4 +1,5 @@
 mod checkbox_filter_test;
+mod checklist_filter_test;
 mod date_filter_test;
 mod number_filter_test;
 mod script;

+ 12 - 1
frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs

@@ -6,7 +6,7 @@
 use std::time::Duration;
 use bytes::Bytes;
 use futures::TryFutureExt;
-use flowy_grid::entities::{AlterFilterParams, AlterFilterPayloadPB, DeleteFilterParams, GridLayout, GridSettingChangesetParams, GridSettingPB, RowPB, TextFilterCondition, FieldType, NumberFilterCondition, CheckboxFilterCondition, DateFilterCondition, DateFilterContent, SelectOptionCondition, TextFilterPB, NumberFilterPB, CheckboxFilterPB, DateFilterPB, SelectOptionFilterPB, CellChangesetPB, FilterPB};
+use flowy_grid::entities::{AlterFilterParams, AlterFilterPayloadPB, DeleteFilterParams, GridLayout, GridSettingChangesetParams, GridSettingPB, RowPB, TextFilterCondition, FieldType, NumberFilterCondition, CheckboxFilterCondition, DateFilterCondition, DateFilterContent, SelectOptionCondition, TextFilterPB, NumberFilterPB, CheckboxFilterPB, DateFilterPB, SelectOptionFilterPB, CellChangesetPB, FilterPB, ChecklistFilterCondition, ChecklistFilterPB};
 use flowy_grid::services::field::{SelectOptionCellChangeset, SelectOptionIds};
 use flowy_grid::services::setting::GridSettingChangesetBuilder;
 use grid_rev_model::{FieldRevision, FieldTypeRevision};
@@ -57,6 +57,9 @@ pub enum FilterScript {
         condition: SelectOptionCondition,
         option_ids: Vec<String>,
     },
+    CreateChecklistFilter {
+        condition: ChecklistFilterCondition,
+    },
     AssertFilterCount {
         count: i32,
     },
@@ -184,6 +187,14 @@ impl GridFilterTest {
                     AlterFilterPayloadPB::new(field_rev, filter);
                 self.insert_filter(payload).await;
             }
+            FilterScript::CreateChecklistFilter { condition} => {
+                let field_rev = self.get_first_field_rev(FieldType::Checklist);
+                // let type_option = self.get_checklist_type_option(&field_rev.id);
+                let filter = ChecklistFilterPB { condition };
+                let payload =
+                    AlterFilterPayloadPB::new(field_rev, filter);
+                self.insert_filter(payload).await;
+            }
             FilterScript::AssertFilterCount { count } => {
                 let filters = self.editor.get_all_filters().await.unwrap();
                 assert_eq!(count as usize, filters.len());

+ 11 - 3
frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs

@@ -131,6 +131,14 @@ impl GridEditorTest {
         type_option
     }
 
+    pub fn get_checklist_type_option(&self, field_id: &str) -> ChecklistTypeOptionPB {
+        let field_type = FieldType::Checklist;
+        let field_rev = self.get_field_rev(field_id, field_type.clone());
+        let type_option = field_rev
+            .get_type_option::<ChecklistTypeOptionPB>(field_type.into())
+            .unwrap();
+        type_option
+    }
     pub fn get_checkbox_type_option(&self, field_id: &str) -> CheckboxTypeOptionPB {
         let field_type = FieldType::Checkbox;
         let field_rev = self.get_field_rev(field_id, field_type.clone());
@@ -220,7 +228,7 @@ fn make_test_grid() -> BuildGridContext {
                 let url_field = FieldBuilder::new(url).name("link").visibility(true).build();
                 grid_builder.add_field(url_field);
             }
-            FieldType::CheckList => {
+            FieldType::Checklist => {
                 let checklist = ChecklistTypeOptionBuilder::default()
                     .add_option(SelectOptionPB::new(FIRST_THING))
                     .add_option(SelectOptionPB::new(SECOND_THING))
@@ -245,7 +253,7 @@ fn make_test_grid() -> BuildGridContext {
                         FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
                         FieldType::MultiSelect => row_builder
                             .insert_multi_select_cell(|mut options| vec![options.remove(0), options.remove(0)]),
-                        FieldType::CheckList => row_builder.insert_checklist_cell(|options| options),
+                        FieldType::Checklist => row_builder.insert_checklist_cell(|options| options),
                         FieldType::Checkbox => row_builder.insert_checkbox_cell("true"),
                         _ => "".to_owned(),
                     };
@@ -382,7 +390,7 @@ fn make_test_board() -> BuildGridContext {
                 let url_field = FieldBuilder::new(url).name("link").visibility(true).build();
                 grid_builder.add_field(url_field);
             }
-            FieldType::CheckList => {}
+            FieldType::Checklist => {}
         }
     }