Browse Source

Refactor/database classes (#1913)

Nathan.fooo 2 years ago
parent
commit
59a1910b3c
63 changed files with 293 additions and 476 deletions
  1. 0 1
      frontend/.vscode/settings.json
  2. 57 218
      frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_controller.dart
  3. 108 0
      frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_controller_builder.dart
  4. 0 63
      frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_field_notifier.dart
  5. 0 6
      frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_service.dart
  6. 2 2
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_editor_bloc.dart
  7. 4 4
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_type_option_edit_bloc.dart
  8. 2 2
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/type_option_context.dart
  9. 11 11
      frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/type_option_data_controller.dart
  10. 4 18
      frontend/appflowy_flutter/lib/plugins/database_view/application/row/row_data_controller.dart
  11. 6 6
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/board_data_controller.dart
  12. 1 2
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_checkbox_cell_bloc.dart
  13. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_date_cell_bloc.dart
  14. 2 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_number_cell_bloc.dart
  15. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_select_option_cell_bloc.dart
  16. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_text_cell_bloc.dart
  17. 1 2
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_url_cell_bloc.dart
  18. 1 12
      frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/card_data_controller.dart
  19. 1 3
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/board_page.dart
  20. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_checkbox_cell.dart
  21. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_checklist_cell.dart
  22. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_date_cell.dart
  23. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_number_cell.dart
  24. 1 2
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_select_option_cell.dart
  25. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_text_cell.dart
  26. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_url_cell.dart
  27. 2 2
      frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/card_cell_builder.dart
  28. 1 0
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/checkbox_cell_bloc.dart
  29. 5 5
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/checklist_cell_bloc.dart
  30. 4 5
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/checklist_cell_editor_bloc.dart
  31. 1 0
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/date_cal_bloc.dart
  32. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/date_cell_bloc.dart
  33. 8 17
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/number_cell_bloc.dart
  34. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/select_option_cell_bloc.dart
  35. 4 4
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/select_option_editor_bloc.dart
  36. 3 3
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/select_option_service.dart
  37. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/text_cell_bloc.dart
  38. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/url_cell_bloc.dart
  39. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/url_cell_editor_bloc.dart
  40. 0 3
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/checklist_filter_bloc.dart
  41. 7 17
      frontend/appflowy_flutter/lib/plugins/database_view/grid/application/grid_bloc.dart
  42. 8 10
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/grid_page.dart
  43. 4 8
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/cell_builder.dart
  44. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/checkbox_cell.dart
  45. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/checklist_cell/checklist_cell.dart
  46. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/checklist_cell/checklist_cell_editor.dart
  47. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/date_cell/date_cell.dart
  48. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/date_cell/date_editor.dart
  49. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/number_cell.dart
  50. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/select_option_cell/select_option_cell.dart
  51. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart
  52. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/text_cell.dart
  53. 1 2
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/url_cell/cell_editor.dart
  54. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/url_cell/url_cell.dart
  55. 2 2
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/field_type_option_editor.dart
  56. 5 5
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/builder.dart
  57. 1 1
      frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/setting_button.dart
  58. 1 0
      frontend/appflowy_flutter/lib/startup/deps_resolver.dart
  59. 1 1
      frontend/appflowy_flutter/test/bloc_test/board_test/group_by_multi_select_field_test.dart
  60. 2 4
      frontend/appflowy_flutter/test/bloc_test/board_test/util.dart
  61. 4 4
      frontend/appflowy_flutter/test/bloc_test/grid_test/filter/create_filter_test.dart
  62. 2 2
      frontend/appflowy_flutter/test/bloc_test/grid_test/grid_bloc_test.dart
  63. 2 4
      frontend/appflowy_flutter/test/bloc_test/grid_test/util.dart

+ 0 - 1
frontend/.vscode/settings.json

@@ -24,7 +24,6 @@
     "svgviewer.showzoominout": true,
     "editor.wordWrapColumn": 80,
     "editor.minimap.maxColumn": 140,
-    "prettier.printWidth": 140,
     "editor.wordWrap": "wordWrapColumn",
     "dart.lineLength": 80,
     "typescript.validate.enable": true,

+ 57 - 218
frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_controller.dart

@@ -1,118 +1,16 @@
-part of 'cell_service.dart';
-
-typedef TextCellController = CellController<String, String>;
-typedef CheckboxCellController = CellController<String, String>;
-typedef NumberCellController = CellController<String, String>;
-typedef SelectOptionCellController
-    = CellController<SelectOptionCellDataPB, String>;
-typedef ChecklistCellController
-    = CellController<SelectOptionCellDataPB, String>;
-typedef DateCellController = CellController<DateCellDataPB, CalendarData>;
-typedef URLCellController = CellController<URLCellDataPB, String>;
-
-abstract class CellControllerBuilderDelegate {
-  CellFieldNotifier buildFieldNotifier();
-}
-
-class CellControllerBuilder {
-  final CellIdentifier _cellId;
-  final CellCache _cellCache;
-  final CellControllerBuilderDelegate delegate;
-
-  CellControllerBuilder({
-    required this.delegate,
-    required CellIdentifier cellId,
-    required CellCache cellCache,
-  })  : _cellCache = cellCache,
-        _cellId = cellId;
-
-  CellController build() {
-    final cellFieldNotifier = delegate.buildFieldNotifier();
-    switch (_cellId.fieldType) {
-      case FieldType.Checkbox:
-        final cellDataLoader = CellDataLoader(
-          cellId: _cellId,
-          parser: StringCellDataParser(),
-        );
-        return TextCellController(
-          cellId: _cellId,
-          cellCache: _cellCache,
-          cellDataLoader: cellDataLoader,
-          fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
-        );
-      case FieldType.DateTime:
-        final cellDataLoader = CellDataLoader(
-          cellId: _cellId,
-          parser: DateCellDataParser(),
-          reloadOnFieldChanged: true,
-        );
-
-        return DateCellController(
-          cellId: _cellId,
-          cellCache: _cellCache,
-          cellDataLoader: cellDataLoader,
-          fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: DateCellDataPersistence(cellId: _cellId),
-        );
-      case FieldType.Number:
-        final cellDataLoader = CellDataLoader(
-          cellId: _cellId,
-          parser: StringCellDataParser(),
-          reloadOnFieldChanged: true,
-        );
-        return NumberCellController(
-          cellId: _cellId,
-          cellCache: _cellCache,
-          cellDataLoader: cellDataLoader,
-          fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
-        );
-      case FieldType.RichText:
-        final cellDataLoader = CellDataLoader(
-          cellId: _cellId,
-          parser: StringCellDataParser(),
-        );
-        return TextCellController(
-          cellId: _cellId,
-          cellCache: _cellCache,
-          cellDataLoader: cellDataLoader,
-          fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
-        );
-      case FieldType.MultiSelect:
-      case FieldType.SingleSelect:
-      case FieldType.Checklist:
-        final cellDataLoader = CellDataLoader(
-          cellId: _cellId,
-          parser: SelectOptionCellDataParser(),
-          reloadOnFieldChanged: true,
-        );
-
-        return SelectOptionCellController(
-          cellId: _cellId,
-          cellCache: _cellCache,
-          cellDataLoader: cellDataLoader,
-          fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
-        );
-
-      case FieldType.URL:
-        final cellDataLoader = CellDataLoader(
-          cellId: _cellId,
-          parser: URLCellDataParser(),
-        );
-        return URLCellController(
-          cellId: _cellId,
-          cellCache: _cellCache,
-          cellDataLoader: cellDataLoader,
-          fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
-        );
-    }
-    throw UnimplementedError;
-  }
-}
+import 'dart:async';
+import 'package:appflowy/plugins/database_view/application/field/field_listener.dart';
+import 'package:appflowy_backend/log.dart';
+import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pbenum.dart';
+import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
+import 'package:dartz/dartz.dart';
+import 'package:equatable/equatable.dart';
+import 'package:flutter/foundation.dart';
+import '../field/field_controller.dart';
+import '../field/field_service.dart';
+import '../field/type_option/type_option_context.dart';
+import 'cell_listener.dart';
+import 'cell_service.dart';
 
 /// IGridCellController is used to manipulate the cell and receive notifications.
 /// * Read/Write cell data
@@ -124,32 +22,39 @@ class CellControllerBuilder {
 // ignore: must_be_immutable
 class CellController<T, D> extends Equatable {
   final CellIdentifier cellId;
-  final CellCache _cellsCache;
+  final CellCache _cellCache;
   final CellCacheKey _cacheKey;
   final FieldBackendService _fieldBackendSvc;
-  final CellFieldNotifier _fieldNotifier;
+  final SingleFieldListener _fieldListener;
   final CellDataLoader<T> _cellDataLoader;
   final CellDataPersistence<D> _cellDataPersistence;
 
   CellListener? _cellListener;
   CellDataNotifier<T?>? _cellDataNotifier;
 
-  bool isListening = false;
-  VoidCallback? _onFieldChangedFn;
+  VoidCallback? _onCellFieldChanged;
   Timer? _loadDataOperation;
   Timer? _saveDataOperation;
-  bool _isDispose = false;
+
+  String get viewId => cellId.viewId;
+
+  String get rowId => cellId.rowId;
+
+  String get fieldId => cellId.fieldInfo.id;
+
+  FieldInfo get fieldInfo => cellId.fieldInfo;
+
+  FieldType get fieldType => cellId.fieldInfo.fieldType;
 
   CellController({
     required this.cellId,
     required CellCache cellCache,
-    required CellFieldNotifier fieldNotifier,
     required CellDataLoader<T> cellDataLoader,
     required CellDataPersistence<D> cellDataPersistence,
-  })  : _cellsCache = cellCache,
+  })  : _cellCache = cellCache,
         _cellDataLoader = cellDataLoader,
         _cellDataPersistence = cellDataPersistence,
-        _fieldNotifier = fieldNotifier,
+        _fieldListener = SingleFieldListener(fieldId: cellId.fieldId),
         _fieldBackendSvc = FieldBackendService(
           viewId: cellId.viewId,
           fieldId: cellId.fieldInfo.id,
@@ -157,46 +62,12 @@ class CellController<T, D> extends Equatable {
         _cacheKey = CellCacheKey(
           rowId: cellId.rowId,
           fieldId: cellId.fieldInfo.id,
-        );
-
-  String get viewId => cellId.viewId;
-
-  String get rowId => cellId.rowId;
-
-  String get fieldId => cellId.fieldInfo.id;
-
-  FieldInfo get fieldInfo => cellId.fieldInfo;
-
-  FieldType get fieldType => cellId.fieldInfo.fieldType;
-
-  /// Listen on the cell content or field changes
-  ///
-  /// An optional [listenWhenOnCellChanged] can be implemented for more
-  ///  granular control over when [listener] is called.
-  /// [listenWhenOnCellChanged] will be invoked on each [onCellChanged]
-  /// get called.
-  /// [listenWhenOnCellChanged] takes the previous `value` and current
-  /// `value` and must return a [bool] which determines whether or not
-  ///  the [onCellChanged] function will be invoked.
-  /// [onCellChanged] is optional and if omitted, it will default to `true`.
-  ///
-  VoidCallback? startListening({
-    required void Function(T?) onCellChanged,
-    bool Function(T? oldValue, T? newValue)? listenWhenOnCellChanged,
-    VoidCallback? onCellFieldChanged,
-  }) {
-    if (isListening) {
-      Log.error("Already started. It seems like you should call clone first");
-      return null;
-    }
-    isListening = true;
-
-    _cellDataNotifier = CellDataNotifier(
-      value: _cellsCache.get(_cacheKey),
-      listenWhen: listenWhenOnCellChanged,
+        ) {
+    _cellDataNotifier = CellDataNotifier(value: _cellCache.get(_cacheKey));
+    _cellListener = CellListener(
+      rowId: cellId.rowId,
+      fieldId: cellId.fieldInfo.id,
     );
-    _cellListener =
-        CellListener(rowId: cellId.rowId, fieldId: cellId.fieldInfo.id);
 
     /// 1.Listen on user edit event and load the new cell data if needed.
     /// For example:
@@ -205,7 +76,7 @@ class CellController<T, D> extends Equatable {
     _cellListener?.start(onCellChanged: (result) {
       result.fold(
         (_) {
-          _cellsCache.remove(_cacheKey);
+          _cellCache.remove(_cacheKey);
           _loadData();
         },
         (err) => Log.error(err),
@@ -213,20 +84,25 @@ class CellController<T, D> extends Equatable {
     });
 
     /// 2.Listen on the field event and load the cell data if needed.
-    _onFieldChangedFn = () {
-      if (onCellFieldChanged != null) {
-        onCellFieldChanged();
-      }
-
-      /// reloadOnFieldChanged should be true if you need to load the data when the corresponding field is changed
-      /// For example:
-      ///   ¥12 -> $12
-      if (_cellDataLoader.reloadOnFieldChanged) {
-        _loadData();
-      }
-    };
+    _fieldListener.start(onFieldChanged: (result) {
+      result.fold((fieldPB) {
+        /// reloadOnFieldChanged should be true if you need to load the data when the corresponding field is changed
+        /// For example:
+        ///   ¥12 -> $12
+        if (_cellDataLoader.reloadOnFieldChanged) {
+          _loadData();
+        }
+        _onCellFieldChanged?.call();
+      }, (err) => Log.error(err));
+    });
+  }
 
-    _fieldNotifier.register(_cacheKey, _onFieldChangedFn!);
+  /// Listen on the cell content or field changes
+  VoidCallback? startListening({
+    required void Function(T?) onCellChanged,
+    VoidCallback? onCellFieldChanged,
+  }) {
+    _onCellFieldChanged = onCellFieldChanged;
 
     /// Notify the listener, the cell data was changed.
     onCellChangedFn() => onCellChanged(_cellDataNotifier?.value);
@@ -244,7 +120,7 @@ class CellController<T, D> extends Equatable {
   /// The cell data will be read from the Cache first, and load from disk if it does not exist.
   /// You can set [loadIfNotExist] to false (default is true) to disable loading the cell data.
   T? getCellData({bool loadIfNotExist = true}) {
-    final data = _cellsCache.get(_cacheKey);
+    final data = _cellCache.get(_cacheKey);
     if (data == null && loadIfNotExist) {
       _loadData();
     }
@@ -294,9 +170,9 @@ class CellController<T, D> extends Equatable {
     _loadDataOperation = Timer(const Duration(milliseconds: 10), () {
       _cellDataLoader.loadData().then((data) {
         if (data != null) {
-          _cellsCache.insert(_cacheKey, GridBaseCell(object: data));
+          _cellCache.insert(_cacheKey, GridBaseCell(object: data));
         } else {
-          _cellsCache.remove(_cacheKey);
+          _cellCache.remove(_cacheKey);
         }
 
         _cellDataNotifier?.value = data;
@@ -305,54 +181,17 @@ class CellController<T, D> extends Equatable {
   }
 
   Future<void> dispose() async {
-    if (_isDispose) {
-      Log.error("$this should only dispose once");
-      return;
-    }
-    _isDispose = true;
     await _cellListener?.stop();
     _loadDataOperation?.cancel();
     _saveDataOperation?.cancel();
     _cellDataNotifier?.dispose();
+    await _fieldListener.stop();
     _cellDataNotifier = null;
-
-    if (_onFieldChangedFn != null) {
-      _fieldNotifier.unregister(_cacheKey, _onFieldChangedFn!);
-      await _fieldNotifier.dispose();
-      _onFieldChangedFn = null;
-    }
   }
 
   @override
   List<Object> get props =>
-      [_cellsCache.get(_cacheKey) ?? "", cellId.rowId + cellId.fieldInfo.id];
-}
-
-class GridCellFieldNotifierImpl extends ICellFieldNotifier {
-  final FieldController _fieldController;
-  OnReceiveUpdateFields? _onChangesetFn;
-
-  GridCellFieldNotifierImpl(FieldController cache) : _fieldController = cache;
-
-  @override
-  void onCellDispose() {
-    if (_onChangesetFn != null) {
-      _fieldController.removeListener(onChangesetListener: _onChangesetFn!);
-      _onChangesetFn = null;
-    }
-  }
-
-  @override
-  void onCellFieldChanged(void Function(FieldInfo) callback) {
-    _onChangesetFn = (List<FieldInfo> filedInfos) {
-      for (final field in filedInfos) {
-        callback(field);
-      }
-    };
-    _fieldController.addListener(
-      onReceiveFields: _onChangesetFn,
-    );
-  }
+      [_cellCache.get(_cacheKey) ?? "", cellId.rowId + cellId.fieldInfo.id];
 }
 
 class CellDataNotifier<T> extends ChangeNotifier {

+ 108 - 0
frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_controller_builder.dart

@@ -0,0 +1,108 @@
+import 'package:appflowy_backend/protobuf/flowy-database/date_type_option_entities.pb.dart';
+import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pbenum.dart';
+import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
+import 'package:appflowy_backend/protobuf/flowy-database/url_type_option_entities.pb.dart';
+
+import 'cell_controller.dart';
+import 'cell_service.dart';
+
+typedef TextCellController = CellController<String, String>;
+typedef CheckboxCellController = CellController<String, String>;
+typedef NumberCellController = CellController<String, String>;
+typedef SelectOptionCellController
+    = CellController<SelectOptionCellDataPB, String>;
+typedef ChecklistCellController
+    = CellController<SelectOptionCellDataPB, String>;
+typedef DateCellController = CellController<DateCellDataPB, CalendarData>;
+typedef URLCellController = CellController<URLCellDataPB, String>;
+
+class CellControllerBuilder {
+  final CellIdentifier _cellId;
+  final CellCache _cellCache;
+
+  CellControllerBuilder({
+    required CellIdentifier cellId,
+    required CellCache cellCache,
+  })  : _cellCache = cellCache,
+        _cellId = cellId;
+
+  CellController build() {
+    switch (_cellId.fieldType) {
+      case FieldType.Checkbox:
+        final cellDataLoader = CellDataLoader(
+          cellId: _cellId,
+          parser: StringCellDataParser(),
+        );
+        return TextCellController(
+          cellId: _cellId,
+          cellCache: _cellCache,
+          cellDataLoader: cellDataLoader,
+          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
+        );
+      case FieldType.DateTime:
+        final cellDataLoader = CellDataLoader(
+          cellId: _cellId,
+          parser: DateCellDataParser(),
+          reloadOnFieldChanged: true,
+        );
+
+        return DateCellController(
+          cellId: _cellId,
+          cellCache: _cellCache,
+          cellDataLoader: cellDataLoader,
+          cellDataPersistence: DateCellDataPersistence(cellId: _cellId),
+        );
+      case FieldType.Number:
+        final cellDataLoader = CellDataLoader(
+          cellId: _cellId,
+          parser: StringCellDataParser(),
+          reloadOnFieldChanged: true,
+        );
+        return NumberCellController(
+          cellId: _cellId,
+          cellCache: _cellCache,
+          cellDataLoader: cellDataLoader,
+          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
+        );
+      case FieldType.RichText:
+        final cellDataLoader = CellDataLoader(
+          cellId: _cellId,
+          parser: StringCellDataParser(),
+        );
+        return TextCellController(
+          cellId: _cellId,
+          cellCache: _cellCache,
+          cellDataLoader: cellDataLoader,
+          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
+        );
+      case FieldType.MultiSelect:
+      case FieldType.SingleSelect:
+      case FieldType.Checklist:
+        final cellDataLoader = CellDataLoader(
+          cellId: _cellId,
+          parser: SelectOptionCellDataParser(),
+          reloadOnFieldChanged: true,
+        );
+
+        return SelectOptionCellController(
+          cellId: _cellId,
+          cellCache: _cellCache,
+          cellDataLoader: cellDataLoader,
+          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
+        );
+
+      case FieldType.URL:
+        final cellDataLoader = CellDataLoader(
+          cellId: _cellId,
+          parser: URLCellDataParser(),
+        );
+        return URLCellController(
+          cellId: _cellId,
+          cellCache: _cellCache,
+          cellDataLoader: cellDataLoader,
+          cellDataPersistence: TextCellDataPersistence(cellId: _cellId),
+        );
+    }
+    throw UnimplementedError;
+  }
+}

+ 0 - 63
frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_field_notifier.dart

@@ -1,63 +0,0 @@
-import 'package:flutter/foundation.dart';
-import '../field/field_controller.dart';
-import 'cell_service.dart';
-
-abstract class ICellFieldNotifier {
-  void onCellFieldChanged(void Function(FieldInfo) callback);
-  void onCellDispose();
-}
-
-/// DatabasePB's cell helper wrapper that enables each cell will get notified when the corresponding field was changed.
-/// You Register an onFieldChanged callback to listen to the cell changes, and unregister if you don't want to listen.
-class CellFieldNotifier {
-  final ICellFieldNotifier notifier;
-
-  /// fieldId: {objectId: callback}
-  final Map<String, Map<String, List<VoidCallback>>> _fieldListenerByFieldId =
-      {};
-
-  CellFieldNotifier({required this.notifier}) {
-    notifier.onCellFieldChanged(
-      (field) {
-        final map = _fieldListenerByFieldId[field.id];
-        if (map != null) {
-          for (final callbacks in map.values) {
-            for (final callback in callbacks) {
-              callback();
-            }
-          }
-        }
-      },
-    );
-  }
-
-  ///
-  void register(CellCacheKey cacheKey, VoidCallback onFieldChanged) {
-    var map = _fieldListenerByFieldId[cacheKey.fieldId];
-    if (map == null) {
-      _fieldListenerByFieldId[cacheKey.fieldId] = {};
-      map = _fieldListenerByFieldId[cacheKey.fieldId];
-      map![cacheKey.rowId] = [onFieldChanged];
-    } else {
-      var objects = map[cacheKey.rowId];
-      if (objects == null) {
-        map[cacheKey.rowId] = [onFieldChanged];
-      } else {
-        objects.add(onFieldChanged);
-      }
-    }
-  }
-
-  void unregister(CellCacheKey cacheKey, VoidCallback fn) {
-    var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId];
-    final index = callbacks?.indexWhere((callback) => callback == fn);
-    if (index != null && index != -1) {
-      callbacks?.removeAt(index);
-    }
-  }
-
-  Future<void> dispose() async {
-    notifier.onCellDispose();
-    _fieldListenerByFieldId.clear();
-  }
-}

+ 0 - 6
frontend/appflowy_flutter/lib/plugins/database_view/application/cell/cell_service.dart

@@ -1,7 +1,6 @@
 import 'dart:async';
 import 'dart:collection';
 import 'package:dartz/dartz.dart';
-import 'package:equatable/equatable.dart';
 import 'package:appflowy_backend/dispatch/dispatch.dart';
 import 'package:appflowy_backend/log.dart';
 import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
@@ -15,13 +14,8 @@ import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:convert' show utf8;
 
 import '../field/field_controller.dart';
-import '../field/field_service.dart';
-import '../field/type_option/type_option_context.dart';
-import 'cell_field_notifier.dart';
-import 'cell_listener.dart';
 part 'cell_service.freezed.dart';
 part 'cell_data_loader.dart';
-part 'cell_controller.dart';
 part 'cell_cache.dart';
 part 'cell_data_persistence.dart';
 

+ 2 - 2
frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_editor_bloc.dart

@@ -10,7 +10,7 @@ import 'type_option/type_option_data_controller.dart';
 part 'field_editor_bloc.freezed.dart';
 
 class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
-  final TypeOptionDataController dataController;
+  final TypeOptionController dataController;
 
   FieldEditorBloc({
     required String viewId,
@@ -18,7 +18,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
     required bool isGroupField,
     required IFieldTypeOptionLoader loader,
   })  : dataController =
-            TypeOptionDataController(viewId: viewId, loader: loader),
+            TypeOptionController(viewId: viewId, loader: loader),
         super(FieldEditorState.initial(viewId, fieldName, isGroupField)) {
     on<FieldEditorEvent>(
       (event, emit) async {

+ 4 - 4
frontend/appflowy_flutter/lib/plugins/database_view/application/field/field_type_option_edit_bloc.dart

@@ -8,10 +8,10 @@ part 'field_type_option_edit_bloc.freezed.dart';
 
 class FieldTypeOptionEditBloc
     extends Bloc<FieldTypeOptionEditEvent, FieldTypeOptionEditState> {
-  final TypeOptionDataController _dataController;
+  final TypeOptionController _dataController;
   void Function()? _fieldListenFn;
 
-  FieldTypeOptionEditBloc(TypeOptionDataController dataController)
+  FieldTypeOptionEditBloc(TypeOptionController dataController)
       : _dataController = dataController,
         super(FieldTypeOptionEditState.initial(dataController)) {
     on<FieldTypeOptionEditEvent>(
@@ -58,9 +58,9 @@ class FieldTypeOptionEditState with _$FieldTypeOptionEditState {
   }) = _FieldTypeOptionEditState;
 
   factory FieldTypeOptionEditState.initial(
-    TypeOptionDataController typeOptionDataController,
+    TypeOptionController typeOptionController,
   ) =>
       FieldTypeOptionEditState(
-        field: typeOptionDataController.field,
+        field: typeOptionController.field,
       );
 }

+ 2 - 2
frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/type_option_context.dart

@@ -109,11 +109,11 @@ class ChecklistTypeOptionWidgetDataParser
 class TypeOptionContext<T extends GeneratedMessage> {
   T? _typeOptionObject;
   final TypeOptionParser<T> dataParser;
-  final TypeOptionDataController _dataController;
+  final TypeOptionController _dataController;
 
   TypeOptionContext({
     required this.dataParser,
-    required TypeOptionDataController dataController,
+    required TypeOptionController dataController,
   }) : _dataController = dataController;
 
   String get viewId => _dataController.viewId;

+ 11 - 11
frontend/appflowy_flutter/lib/plugins/database_view/application/field/type_option/type_option_data_controller.dart

@@ -9,25 +9,25 @@ import 'package:appflowy_backend/log.dart';
 import '../field_service.dart';
 import 'type_option_context.dart';
 
-class TypeOptionDataController {
+class TypeOptionController {
   final String viewId;
+  late TypeOptionPB _typeOption;
   final IFieldTypeOptionLoader loader;
-  late TypeOptionPB _typeOptiondata;
   final PublishNotifier<FieldPB> _fieldNotifier = PublishNotifier();
 
-  /// Returns a [TypeOptionDataController] used to modify the specified
+  /// Returns a [TypeOptionController] used to modify the specified
   /// [FieldPB]'s data
   ///
   /// Should call [loadTypeOptionData] if the passed-in [FieldInfo]
   /// is null
   ///
-  TypeOptionDataController({
+  TypeOptionController({
     required this.viewId,
     required this.loader,
     FieldInfo? fieldInfo,
   }) {
     if (fieldInfo != null) {
-      _typeOptiondata = TypeOptionPB.create()
+      _typeOption = TypeOptionPB.create()
         ..viewId = viewId
         ..field_2 = fieldInfo.field;
     }
@@ -38,7 +38,7 @@ class TypeOptionDataController {
     return result.fold(
       (data) {
         data.freeze();
-        _typeOptiondata = data;
+        _typeOption = data;
         _fieldNotifier.value = data.field_2;
         return left(data);
       },
@@ -50,28 +50,28 @@ class TypeOptionDataController {
   }
 
   FieldPB get field {
-    return _typeOptiondata.field_2;
+    return _typeOption.field_2;
   }
 
   T getTypeOption<T>(TypeOptionParser<T> parser) {
-    return parser.fromBuffer(_typeOptiondata.typeOptionData);
+    return parser.fromBuffer(_typeOption.typeOptionData);
   }
 
   set fieldName(String name) {
-    _typeOptiondata = _typeOptiondata.rebuild((rebuildData) {
+    _typeOption = _typeOption.rebuild((rebuildData) {
       rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
         rebuildField.name = name;
       });
     });
 
-    _fieldNotifier.value = _typeOptiondata.field_2;
+    _fieldNotifier.value = _typeOption.field_2;
 
     FieldBackendService(viewId: viewId, fieldId: field.id)
         .updateField(name: name);
   }
 
   set typeOptionData(List<int> typeOptionData) {
-    _typeOptiondata = _typeOptiondata.rebuild((rebuildData) {
+    _typeOption = _typeOption.rebuild((rebuildData) {
       if (typeOptionData.isNotEmpty) {
         rebuildData.typeOptionData = typeOptionData;
       }

+ 4 - 18
frontend/appflowy_flutter/lib/plugins/database_view/application/row/row_data_controller.dart

@@ -1,24 +1,20 @@
 import 'package:flutter/material.dart';
-import '../../grid/presentation/widgets/cell/cell_builder.dart';
-import '../cell/cell_field_notifier.dart';
 import '../cell/cell_service.dart';
-import '../field/field_controller.dart';
 import 'row_cache.dart';
 
 typedef OnRowChanged = void Function(CellByFieldId, RowsChangedReason);
 
-class RowDataController extends GridCellBuilderDelegate {
+class RowDataController {
   final RowInfo rowInfo;
   final List<VoidCallback> _onRowChangedListeners = [];
-  final FieldController _fieldController;
   final RowCache _rowCache;
 
+  get cellCache => _rowCache.cellCache;
+
   RowDataController({
     required this.rowInfo,
-    required FieldController fieldController,
     required RowCache rowCache,
-  })  : _fieldController = fieldController,
-        _rowCache = rowCache;
+  }) : _rowCache = rowCache;
 
   CellByFieldId loadData() {
     return _rowCache.loadGridCells(rowInfo.rowPB.id);
@@ -36,14 +32,4 @@ class RowDataController extends GridCellBuilderDelegate {
       _rowCache.removeRowListener(fn);
     }
   }
-
-  // GridCellBuilderDelegate implementation
-  @override
-  CellFieldNotifier buildFieldNotifier() {
-    return CellFieldNotifier(
-        notifier: GridCellFieldNotifierImpl(_fieldController));
-  }
-
-  @override
-  CellCache get cellCache => _rowCache.cellCache;
 }

+ 6 - 6
frontend/appflowy_flutter/lib/plugins/database_view/board/application/board_data_controller.dart

@@ -21,7 +21,7 @@ typedef OnResetGroups = void Function(List<GroupPB>);
 
 class BoardDataController {
   final String viewId;
-  final DatabaseBackendService _databaseFFIService;
+  final DatabaseBackendService _databaseSvc;
   final FieldController fieldController;
   final BoardListener _listener;
   late DatabaseViewCache _viewCache;
@@ -38,7 +38,7 @@ class BoardDataController {
   BoardDataController({required ViewPB view})
       : viewId = view.id,
         _listener = BoardListener(view.id),
-        _databaseFFIService = DatabaseBackendService(viewId: view.id),
+        _databaseSvc = DatabaseBackendService(viewId: view.id),
         fieldController = FieldController(viewId: view.id) {
     //
     _viewCache = DatabaseViewCache(
@@ -100,7 +100,7 @@ class BoardDataController {
   }
 
   Future<Either<Unit, FlowyError>> openGrid() async {
-    final result = await _databaseFFIService.openGrid();
+    final result = await _databaseSvc.openGrid();
     return result.fold(
       (grid) async {
         _onDatabaseChanged?.call(grid);
@@ -121,17 +121,17 @@ class BoardDataController {
 
   Future<Either<RowPB, FlowyError>> createBoardCard(String groupId,
       {String? startRowId}) {
-    return _databaseFFIService.createBoardCard(groupId, startRowId);
+    return _databaseSvc.createBoardCard(groupId, startRowId);
   }
 
   Future<void> dispose() async {
     await _viewCache.dispose();
-    await _databaseFFIService.closeView();
+    await _databaseSvc.closeView();
     await fieldController.dispose();
   }
 
   Future<void> _loadGroups() async {
-    final result = await _databaseFFIService.loadGroups();
+    final result = await _databaseSvc.loadGroups();
     return Future(
       () => result.fold(
         (groups) {

+ 1 - 2
frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_checkbox_cell_bloc.dart

@@ -1,8 +1,7 @@
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';
-
-import '../../../application/cell/cell_service.dart';
+import '../../../application/cell/cell_controller_builder.dart';
 
 part 'board_checkbox_cell_bloc.freezed.dart';
 

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_date_cell_bloc.dart

@@ -3,7 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';
 
-import '../../../application/cell/cell_service.dart';
+import '../../../application/cell/cell_controller_builder.dart';
 import '../../../application/field/field_controller.dart';
 part 'board_date_cell_bloc.freezed.dart';
 

+ 2 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_number_cell_bloc.dart

@@ -1,7 +1,8 @@
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';
-import '../../../application/cell/cell_service.dart';
+
+import '../../../application/cell/cell_controller_builder.dart';
 
 part 'board_number_cell_bloc.freezed.dart';
 

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_select_option_cell_bloc.dart

@@ -1,5 +1,5 @@
 import 'dart:async';
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_text_cell_bloc.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';

+ 1 - 2
frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/board_url_cell_bloc.dart

@@ -1,10 +1,9 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/url_type_option_entities.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';
 
-import '../../../application/cell/cell_service.dart';
-
 part 'board_url_cell_bloc.freezed.dart';
 
 class BoardURLCellBloc extends Bloc<BoardURLCellEvent, BoardURLCellState> {

+ 1 - 12
frontend/appflowy_flutter/lib/plugins/database_view/board/application/card/card_data_controller.dart

@@ -1,9 +1,7 @@
 import 'package:appflowy_backend/protobuf/flowy-database/row_entities.pb.dart';
 import 'package:flutter/foundation.dart';
 
-import '../../../application/cell/cell_field_notifier.dart';
 import '../../../application/cell/cell_service.dart';
-import '../../../application/field/field_controller.dart';
 import '../../../application/row/row_cache.dart';
 import '../../presentation/card/card_cell_builder.dart';
 
@@ -11,16 +9,13 @@ typedef OnCardChanged = void Function(CellByFieldId, RowsChangedReason);
 
 class CardDataController extends BoardCellBuilderDelegate {
   final RowPB rowPB;
-  final FieldController _fieldController;
   final RowCache _rowCache;
   final List<VoidCallback> _onCardChangedListeners = [];
 
   CardDataController({
     required this.rowPB,
-    required FieldController fieldController,
     required RowCache rowCache,
-  })  : _fieldController = fieldController,
-        _rowCache = rowCache;
+  }) : _rowCache = rowCache;
 
   CellByFieldId loadData() {
     return _rowCache.loadGridCells(rowPB.id);
@@ -39,12 +34,6 @@ class CardDataController extends BoardCellBuilderDelegate {
     }
   }
 
-  @override
-  CellFieldNotifier buildFieldNotifier() {
-    return CellFieldNotifier(
-        notifier: GridCellFieldNotifierImpl(_fieldController));
-  }
-
   @override
   CellCache get cellCache => _rowCache.cellCache;
 }

+ 1 - 3
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/board_page.dart

@@ -229,7 +229,6 @@ class _BoardContentState extends State<BoardContent> {
     final fieldController = context.read<BoardBloc>().fieldController;
     final viewId = context.read<BoardBloc>().viewId;
     final cardController = CardDataController(
-      fieldController: fieldController,
       rowCache: rowCache,
       rowPB: rowPB,
     );
@@ -306,7 +305,6 @@ class _BoardContentState extends State<BoardContent> {
 
     final dataController = RowDataController(
       rowInfo: rowInfo,
-      fieldController: fieldController,
       rowCache: rowCache,
     );
 
@@ -314,7 +312,7 @@ class _BoardContentState extends State<BoardContent> {
       context: context,
       builder: (BuildContext context) {
         return RowDetailPage(
-          cellBuilder: GridCellBuilder(delegate: dataController),
+          cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
           dataController: dataController,
         );
       },

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_checkbox_cell.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/board/application/card/board_checkbox_cell_bloc.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/style_widget/icon_button.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_checklist_cell.dart

@@ -1,7 +1,7 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import '../../../application/cell/cell_service.dart';
 import '../../../grid/application/cell/checklist_cell_bloc.dart';
 import '../../../grid/presentation/widgets/cell/checklist_cell/checklist_progress_bar.dart';
 

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_date_cell.dart

@@ -1,9 +1,9 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/board/application/card/board_date_cell_bloc.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import '../../../application/cell/cell_service.dart';
 import 'define.dart';
 
 class BoardDateCell extends StatefulWidget {

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_number_cell.dart

@@ -1,7 +1,7 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
-import '../../../application/cell/cell_service.dart';
 import '../../application/card/board_number_cell_bloc.dart';
 import 'define.dart';
 

+ 1 - 2
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_select_option_cell.dart

@@ -1,9 +1,8 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.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 '../../../application/cell/cell_service.dart';
 import '../../../grid/presentation/widgets/cell/select_option_cell/extension.dart';
 import '../../../grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart';
 import '../../application/card/board_select_option_cell_bloc.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_text_cell.dart

@@ -1,10 +1,10 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/widgets/cell/cell_builder.dart';
 import 'package:flowy_infra/size.dart';
 import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:textstyle_extensions/textstyle_extensions.dart';
-import '../../../application/cell/cell_service.dart';
 import '../../application/card/board_text_cell_bloc.dart';
 import 'board_cell.dart';
 import 'define.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/board_url_cell.dart

@@ -1,9 +1,9 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:flowy_infra/size.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:textstyle_extensions/textstyle_extensions.dart';
 
-import '../../../application/cell/cell_service.dart';
 import '../../application/card/board_url_cell_bloc.dart';
 import 'define.dart';
 

+ 2 - 2
frontend/appflowy_flutter/lib/plugins/database_view/board/presentation/card/card_cell_builder.dart

@@ -1,3 +1,4 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
 import 'package:flutter/material.dart';
 
@@ -11,7 +12,7 @@ import 'board_select_option_cell.dart';
 import 'board_text_cell.dart';
 import 'board_url_cell.dart';
 
-abstract class BoardCellBuilderDelegate extends CellControllerBuilderDelegate {
+abstract class BoardCellBuilderDelegate {
   CellCache get cellCache;
 }
 
@@ -26,7 +27,6 @@ class BoardCellBuilder {
     EditableCellNotifier cellNotifier,
   ) {
     final cellControllerBuilder = CellControllerBuilder(
-      delegate: delegate,
       cellId: cellId,
       cellCache: delegate.cellCache,
     );

+ 1 - 0
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/checkbox_cell_bloc.dart

@@ -1,3 +1,4 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';

+ 5 - 5
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/checklist_cell_bloc.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/log.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
@@ -10,12 +10,12 @@ part 'checklist_cell_bloc.freezed.dart';
 
 class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
   final ChecklistCellController cellController;
-  final SelectOptionFFIService _selectOptionService;
+  final SelectOptionBackendService _selectOptionSvc;
   void Function()? _onCellChangedFn;
   ChecklistCellBloc({
     required this.cellController,
-  })  : _selectOptionService =
-            SelectOptionFFIService(cellId: cellController.cellId),
+  })  : _selectOptionSvc =
+            SelectOptionBackendService(cellId: cellController.cellId),
         super(ChecklistCellState.initial(cellController)) {
     on<ChecklistCellEvent>(
       (event, emit) async {
@@ -60,7 +60,7 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
   }
 
   void _loadOptions() {
-    _selectOptionService.getOptionContext().then((result) {
+    _selectOptionSvc.getCellData().then((result) {
       if (isClosed) return;
 
       return result.fold(

+ 4 - 5
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/checklist_cell_editor_bloc.dart

@@ -1,25 +1,24 @@
 import 'dart:async';
 
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:dartz/dartz.dart';
 import 'package:appflowy_backend/log.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/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 SelectOptionBackendService _selectOptionService;
   final ChecklistCellController cellController;
 
   ChecklistCellEditorBloc({
     required this.cellController,
   })  : _selectOptionService =
-            SelectOptionFFIService(cellId: cellController.cellId),
+            SelectOptionBackendService(cellId: cellController.cellId),
         super(ChecklistCellEditorState.initial(cellController)) {
     on<ChecklistCellEditorEvent>(
       (event, emit) async {
@@ -87,7 +86,7 @@ class ChecklistCellEditorBloc
   }
 
   void _loadOptions() {
-    _selectOptionService.getOptionContext().then((result) {
+    _selectOptionService.getCellData().then((result) {
       if (isClosed) return;
 
       return result.fold(

+ 1 - 0
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/date_cal_bloc.dart

@@ -1,4 +1,5 @@
 import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
 import 'package:easy_localization/easy_localization.dart'

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/date_cell_bloc.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/date_type_option_entities.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';

+ 8 - 17
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/number_cell_bloc.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/log.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
@@ -49,22 +49,13 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
   }
 
   void _startListening() {
-    _onCellChangedFn =
-        cellController.startListening(onCellChanged: ((cellContent) {
-      if (!isClosed) {
-        add(NumberCellEvent.didReceiveCellUpdate(cellContent));
-      }
-    }), listenWhenOnCellChanged: (oldValue, newValue) {
-      // If the new value is not the same as the content, which means the
-      // backend formatted the content that user enter. For example:
-      //
-      // state.cellContent: "abc"
-      // oldValue: ""
-      // newValue: ""
-      // The oldValue is the same as newValue. So the [onCellChanged] won't
-      // get called. So just return true to refresh the cell content
-      return true;
-    });
+    _onCellChangedFn = cellController.startListening(
+      onCellChanged: ((cellContent) {
+        if (!isClosed) {
+          add(NumberCellEvent.didReceiveCellUpdate(cellContent));
+        }
+      }),
+    );
   }
 }
 

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/select_option_cell_bloc.dart

@@ -1,5 +1,5 @@
 import 'dart:async';
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';

+ 4 - 4
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/select_option_editor_bloc.dart

@@ -1,5 +1,5 @@
 import 'dart:async';
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:dartz/dartz.dart';
 import 'package:appflowy_backend/log.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
@@ -11,13 +11,13 @@ part 'select_option_editor_bloc.freezed.dart';
 
 class SelectOptionCellEditorBloc
     extends Bloc<SelectOptionEditorEvent, SelectOptionEditorState> {
-  final SelectOptionFFIService _selectOptionService;
+  final SelectOptionBackendService _selectOptionService;
   final SelectOptionCellController cellController;
 
   SelectOptionCellEditorBloc({
     required this.cellController,
   })  : _selectOptionService =
-            SelectOptionFFIService(cellId: cellController.cellId),
+            SelectOptionBackendService(cellId: cellController.cellId),
         super(SelectOptionEditorState.initial(cellController)) {
     on<SelectOptionEditorEvent>(
       (event, emit) async {
@@ -159,7 +159,7 @@ class SelectOptionCellEditorBloc
   }
 
   Future<void> _loadOptions() async {
-    final result = await _selectOptionService.getOptionContext();
+    final result = await _selectOptionService.getCellData();
     if (isClosed) {
       Log.warn("Unexpected closing the bloc");
       return;

+ 3 - 3
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/select_option_service.dart

@@ -6,9 +6,9 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/cell_entities.pb.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/select_type_option.pb.dart';
 
-class SelectOptionFFIService {
+class SelectOptionBackendService {
   final CellIdentifier cellId;
-  SelectOptionFFIService({required this.cellId});
+  SelectOptionBackendService({required this.cellId});
 
   String get viewId => cellId.viewId;
   String get fieldId => cellId.fieldInfo.id;
@@ -60,7 +60,7 @@ class SelectOptionFFIService {
     return DatabaseEventUpdateSelectOption(payload).send();
   }
 
-  Future<Either<SelectOptionCellDataPB, FlowyError>> getOptionContext() {
+  Future<Either<SelectOptionCellDataPB, FlowyError>> getCellData() {
     final payload = CellIdPB.create()
       ..viewId = viewId
       ..fieldId = fieldId

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/text_cell_bloc.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/url_cell_bloc.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/url_type_option_entities.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/cell/url_cell_editor_bloc.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/url_type_option_entities.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';

+ 0 - 3
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/filter/checklist_filter_bloc.dart

@@ -13,14 +13,11 @@ class ChecklistFilterEditorBloc
     extends Bloc<ChecklistFilterEditorEvent, ChecklistFilterEditorState> {
   final FilterInfo filterInfo;
   final FilterBackendService _filterBackendSvc;
-  // final SelectOptionFFIService _selectOptionService;
   final FilterListener _listener;
 
   ChecklistFilterEditorBloc({
     required this.filterInfo,
   })  : _filterBackendSvc = FilterBackendService(viewId: filterInfo.viewId),
-        // _selectOptionService =
-        //           SelectOptionFFIService(cellId: cellController.cellId)
         _listener = FilterListener(
           viewId: filterInfo.viewId,
           filterId: filterInfo.filter.id,

+ 7 - 17
frontend/appflowy_flutter/lib/plugins/database_view/grid/application/grid_bloc.dart

@@ -15,10 +15,9 @@ import 'dart:collection';
 part 'grid_bloc.freezed.dart';
 
 class GridBloc extends Bloc<GridEvent, GridState> {
-  final DatabaseController gridController;
-  void Function()? _createRowOperation;
+  final DatabaseController databaseController;
 
-  GridBloc({required ViewPB view, required this.gridController})
+  GridBloc({required ViewPB view, required this.databaseController})
       : super(GridState.initial(view.id)) {
     on<GridEvent>(
       (event, emit) async {
@@ -28,12 +27,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
             await _openGrid(emit);
           },
           createRow: () {
-            state.loadingState.when(
-              loading: () {
-                _createRowOperation = () => gridController.createRow();
-              },
-              finish: (_) => gridController.createRow(),
-            );
+            databaseController.createRow();
           },
           deleteRow: (rowInfo) async {
             final rowService = RowBackendService(
@@ -63,16 +57,16 @@ class GridBloc extends Bloc<GridEvent, GridState> {
 
   @override
   Future<void> close() async {
-    await gridController.dispose();
+    await databaseController.dispose();
     return super.close();
   }
 
   RowCache? getRowCache(String blockId, String rowId) {
-    return gridController.rowCache;
+    return databaseController.rowCache;
   }
 
   void _startListening() {
-    gridController.addListener(
+    databaseController.addListener(
       onGridChanged: (grid) {
         if (!isClosed) {
           add(GridEvent.didReceiveGridUpdate(grid));
@@ -92,13 +86,9 @@ class GridBloc extends Bloc<GridEvent, GridState> {
   }
 
   Future<void> _openGrid(Emitter<GridState> emit) async {
-    final result = await gridController.openGrid();
+    final result = await databaseController.openGrid();
     result.fold(
       (grid) {
-        if (_createRowOperation != null) {
-          _createRowOperation?.call();
-          _createRowOperation = null;
-        }
         emit(
           state.copyWith(loadingState: GridLoadingState.finish(left(unit))),
         );

+ 8 - 10
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/grid_page.dart

@@ -35,11 +35,11 @@ class GridPage extends StatefulWidget {
     required this.view,
     this.onDeleted,
     Key? key,
-  })  : gridController = DatabaseController(view: view),
+  })  : databaseController = DatabaseController(view: view),
         super(key: key);
 
   final ViewPB view;
-  final DatabaseController gridController;
+  final DatabaseController databaseController;
   final VoidCallback? onDeleted;
 
   @override
@@ -54,19 +54,19 @@ class _GridPageState extends State<GridPage> {
         BlocProvider<GridBloc>(
           create: (context) => GridBloc(
             view: widget.view,
-            gridController: widget.gridController,
+            databaseController: widget.databaseController,
           )..add(const GridEvent.initial()),
         ),
         BlocProvider<GridFilterMenuBloc>(
           create: (context) => GridFilterMenuBloc(
             viewId: widget.view.id,
-            fieldController: widget.gridController.fieldController,
+            fieldController: widget.databaseController.fieldController,
           )..add(const GridFilterMenuEvent.initial()),
         ),
         BlocProvider<SortMenuBloc>(
           create: (context) => SortMenuBloc(
             viewId: widget.view.id,
-            fieldController: widget.gridController.fieldController,
+            fieldController: widget.databaseController.fieldController,
           )..add(const SortMenuEvent.initial()),
         ),
         BlocProvider<DatabaseSettingBloc>(
@@ -190,7 +190,7 @@ class _FlowyGridState extends State<FlowyGrid> {
 
   Widget _gridHeader(BuildContext context, String viewId) {
     final fieldController =
-        context.read<GridBloc>().gridController.fieldController;
+        context.read<GridBloc>().databaseController.fieldController;
     return GridHeaderSliverAdaptor(
       viewId: viewId,
       fieldController: fieldController,
@@ -274,10 +274,9 @@ class _GridRowsState extends State<_GridRows> {
     if (rowCache == null) return const SizedBox();
 
     final fieldController =
-        context.read<GridBloc>().gridController.fieldController;
+        context.read<GridBloc>().databaseController.fieldController;
     final dataController = RowDataController(
       rowInfo: rowInfo,
-      fieldController: fieldController,
       rowCache: rowCache,
     );
 
@@ -286,7 +285,7 @@ class _GridRowsState extends State<_GridRows> {
       child: GridRowWidget(
         rowInfo: rowInfo,
         dataController: dataController,
-        cellBuilder: GridCellBuilder(delegate: dataController),
+        cellBuilder: GridCellBuilder(cellCache: dataController.cellCache),
         openDetailPage: (context, cellBuilder) {
           _openRowDetailPage(
             context,
@@ -310,7 +309,6 @@ class _GridRowsState extends State<_GridRows> {
   ) {
     final dataController = RowDataController(
       rowInfo: rowInfo,
-      fieldController: fieldController,
       rowCache: rowCache,
     );
 

+ 4 - 8
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/cell_builder.dart

@@ -1,3 +1,4 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pb.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
@@ -13,21 +14,16 @@ import 'select_option_cell/select_option_cell.dart';
 import 'text_cell.dart';
 import 'url_cell/url_cell.dart';
 
-abstract class GridCellBuilderDelegate extends CellControllerBuilderDelegate {
-  CellCache get cellCache;
-}
-
 class GridCellBuilder {
-  final GridCellBuilderDelegate delegate;
+  final CellCache cellCache;
   GridCellBuilder({
-    required this.delegate,
+    required this.cellCache,
   });
 
   GridCellWidget build(CellIdentifier cellId, {GridCellStyle? style}) {
     final cellControllerBuilder = CellControllerBuilder(
       cellId: cellId,
-      cellCache: delegate.cellCache,
-      delegate: delegate,
+      cellCache: cellCache,
     );
 
     final key = cellId.key();

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/checkbox_cell.dart

@@ -1,9 +1,9 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/startup/startup.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/style_widget/icon_button.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
-import '../../../../application/cell/cell_service.dart';
 import '../../../application/cell/checkbox_cell_bloc.dart';
 import '../../layout/sizes.dart';
 import 'cell_builder.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/checklist_cell/checklist_cell.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/grid/application/cell/checklist_cell_bloc.dart';
 import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/checklist_cell/checklist_cell_editor.dart

@@ -1,3 +1,4 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra/image.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -8,7 +9,6 @@ import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import '../../../../../application/cell/cell_service.dart';
 import '../../../../application/cell/checklist_cell_editor_bloc.dart';
 import '../../../layout/sizes.dart';
 import '../../header/type_option/select_option_editor.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/date_cell/date_cell.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/grid/application/cell/date_cell_bloc.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';
 import 'package:flutter/widgets.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/date_cell/date_editor.dart

@@ -1,4 +1,5 @@
 import 'package:appflowy/generated/locale_keys.g.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/field/type_option/type_option_context.dart';
 import 'package:appflowy/plugins/database_view/grid/application/cell/date_cal_bloc.dart';
 import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
@@ -20,7 +21,6 @@ import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:table_calendar/table_calendar.dart';
 import 'package:textstyle_extensions/textstyle_extensions.dart';
-import '../../../../../application/cell/cell_service.dart';
 import '../../../layout/sizes.dart';
 import '../../common/type_option_separator.dart';
 import '../../header/type_option/date.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/number_cell.dart

@@ -1,9 +1,9 @@
 import 'dart:async';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/startup/startup.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import '../../../../application/cell/cell_service.dart';
 import '../../../application/cell/number_cell_bloc.dart';
 import '../../layout/sizes.dart';
 import 'cell_builder.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/select_option_cell/select_option_cell.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/startup/startup.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra_ui/flowy_infra_ui.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart

@@ -1,4 +1,5 @@
 import 'dart:collection';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/grid/application/cell/select_option_editor_bloc.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:flowy_infra/theme_extension.dart';
@@ -15,7 +16,6 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:appflowy/generated/locale_keys.g.dart';
 import 'package:textfield_tags/textfield_tags.dart';
 
-import '../../../../../application/cell/cell_service.dart';
 import '../../../layout/sizes.dart';
 import '../../common/type_option_separator.dart';
 import '../../header/type_option/select_option_editor.dart';

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/text_cell.dart

@@ -1,5 +1,5 @@
 import 'dart:async';
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/grid/application/cell/text_cell_bloc.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';

+ 1 - 2
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/url_cell/cell_editor.dart

@@ -1,9 +1,8 @@
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:flutter/material.dart';
 import 'dart:async';
-
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import '../../../../../application/cell/cell_service.dart';
 import '../../../../application/cell/url_cell_editor_bloc.dart';
 
 class URLCellEditor extends StatefulWidget {

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/cell/url_cell/url_cell.dart

@@ -1,6 +1,6 @@
 import 'dart:async';
 import 'package:appflowy/generated/locale_keys.g.dart';
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/workspace/presentation/home/toast.dart';
 import 'package:appflowy_popover/appflowy_popover.dart';
 import 'package:easy_localization/easy_localization.dart';

+ 2 - 2
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/field_type_option_editor.dart

@@ -23,11 +23,11 @@ typedef SwitchToFieldCallback = Future<Either<TypeOptionPB, FlowyError>>
 );
 
 class FieldTypeOptionEditor extends StatelessWidget {
-  final TypeOptionDataController _dataController;
+  final TypeOptionController _dataController;
   final PopoverMutex popoverMutex;
 
   const FieldTypeOptionEditor({
-    required TypeOptionDataController dataController,
+    required TypeOptionController dataController,
     required this.popoverMutex,
     Key? key,
   })  : _dataController = dataController,

+ 5 - 5
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/header/type_option/builder.dart

@@ -48,7 +48,7 @@ abstract class TypeOptionWidgetBuilder {
 
 Widget? makeTypeOptionWidget({
   required BuildContext context,
-  required TypeOptionDataController dataController,
+  required TypeOptionController dataController,
   required PopoverMutex popoverMutex,
 }) {
   final builder = makeTypeOptionWidgetBuilder(
@@ -59,7 +59,7 @@ Widget? makeTypeOptionWidget({
 }
 
 TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder({
-  required TypeOptionDataController dataController,
+  required TypeOptionController dataController,
   required PopoverMutex popoverMutex,
 }) {
   final viewId = dataController.viewId;
@@ -144,7 +144,7 @@ TypeOptionContext<T> makeTypeOptionContext<T extends GeneratedMessage>({
   required FieldInfo fieldInfo,
 }) {
   final loader = FieldTypeOptionLoader(viewId: viewId, field: fieldInfo.field);
-  final dataController = TypeOptionDataController(
+  final dataController = TypeOptionController(
     viewId: viewId,
     loader: loader,
     fieldInfo: fieldInfo,
@@ -178,7 +178,7 @@ TypeOptionContext<T> makeSelectTypeOptionContext<T extends GeneratedMessage>({
     viewId: viewId,
     field: fieldPB,
   );
-  final dataController = TypeOptionDataController(
+  final dataController = TypeOptionController(
     viewId: viewId,
     loader: loader,
   );
@@ -194,7 +194,7 @@ TypeOptionContext<T>
     makeTypeOptionContextWithDataController<T extends GeneratedMessage>({
   required String viewId,
   required FieldType fieldType,
-  required TypeOptionDataController dataController,
+  required TypeOptionController dataController,
 }) {
   switch (fieldType) {
     case FieldType.Checkbox:

+ 1 - 1
frontend/appflowy_flutter/lib/plugins/database_view/grid/presentation/widgets/toolbar/setting_button.dart

@@ -35,7 +35,7 @@ class _SettingButtonState extends State<SettingButton> {
     return BlocSelector<GridBloc, GridState, GridSettingContext>(
       selector: (state) {
         final fieldController =
-            context.read<GridBloc>().gridController.fieldController;
+            context.read<GridBloc>().databaseController.fieldController;
         return GridSettingContext(
           viewId: state.viewId,
           fieldController: fieldController,

+ 1 - 0
frontend/appflowy_flutter/lib/startup/deps_resolver.dart

@@ -1,4 +1,5 @@
 import 'package:appflowy/core/network_monitor.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_action_sheet_bloc.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';

+ 1 - 1
frontend/appflowy_flutter/test/bloc_test/board_test/group_by_multi_select_field_test.dart

@@ -1,4 +1,4 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/setting/group_bloc.dart';
 import 'package:appflowy/plugins/database_view/board/application/board_bloc.dart';
 import 'package:appflowy/plugins/database_view/grid/application/cell/select_option_editor_bloc.dart';

+ 2 - 4
frontend/appflowy_flutter/test/bloc_test/board_test/util.dart

@@ -1,4 +1,5 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_editor_bloc.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
@@ -105,11 +106,9 @@ class BoardTestContext {
   ) async {
     final RowInfo rowInfo = rowInfos.last;
     final rowCache = _boardDataController.rowCache;
-    final fieldController = _boardDataController.fieldController;
 
     final rowDataController = RowDataController(
       rowInfo: rowInfo,
-      fieldController: fieldController,
       rowCache: rowCache,
     );
 
@@ -122,7 +121,6 @@ class BoardTestContext {
     return CellControllerBuilder(
       cellId: rowBloc.state.cellByFieldId[fieldId]!,
       cellCache: rowCache.cellCache,
-      delegate: rowDataController,
     );
   }
 

+ 4 - 4
frontend/appflowy_flutter/test/bloc_test/grid_test/filter/create_filter_test.dart

@@ -53,7 +53,7 @@ void main() {
     final gridController = DatabaseController(view: context.gridView);
     final gridBloc = GridBloc(
       view: context.gridView,
-      gridController: gridController,
+      databaseController: gridController,
     )..add(const GridEvent.initial());
     await gridResponseFuture();
 
@@ -74,7 +74,7 @@ void main() {
     final gridController = DatabaseController(view: context.gridView);
     final gridBloc = GridBloc(
       view: context.gridView,
-      gridController: gridController,
+      databaseController: gridController,
     )..add(const GridEvent.initial());
     await gridResponseFuture();
 
@@ -115,7 +115,7 @@ void main() {
     final gridController = DatabaseController(view: context.gridView);
     final gridBloc = GridBloc(
       view: context.gridView,
-      gridController: gridController,
+      databaseController: gridController,
     )..add(const GridEvent.initial());
 
     await gridResponseFuture();
@@ -134,7 +134,7 @@ void main() {
     final gridController = DatabaseController(view: context.gridView);
     final gridBloc = GridBloc(
       view: context.gridView,
-      gridController: gridController,
+      databaseController: gridController,
     )..add(const GridEvent.initial());
 
     await gridResponseFuture();

+ 2 - 2
frontend/appflowy_flutter/test/bloc_test/grid_test/grid_bloc_test.dart

@@ -20,7 +20,7 @@ void main() {
       "create a row",
       build: () => GridBloc(
           view: context.gridView,
-          gridController: DatabaseController(view: context.gridView))
+          databaseController: DatabaseController(view: context.gridView))
         ..add(const GridEvent.initial()),
       act: (bloc) => bloc.add(const GridEvent.createRow()),
       wait: const Duration(milliseconds: 300),
@@ -33,7 +33,7 @@ void main() {
       "delete the last row",
       build: () => GridBloc(
           view: context.gridView,
-          gridController: DatabaseController(view: context.gridView))
+          databaseController: DatabaseController(view: context.gridView))
         ..add(const GridEvent.initial()),
       act: (bloc) async {
         await gridResponseFuture();

+ 2 - 4
frontend/appflowy_flutter/test/bloc_test/grid_test/util.dart

@@ -1,4 +1,5 @@
-import 'package:appflowy/plugins/database_view/application/cell/cell_service.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller.dart';
+import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_controller.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_editor_bloc.dart';
 import 'package:appflowy/plugins/database_view/application/field/field_service.dart';
@@ -66,11 +67,9 @@ class GridTestContext {
   ) async {
     final RowInfo rowInfo = rowInfos[rowIndex];
     final rowCache = gridController.rowCache;
-    final fieldController = gridController.fieldController;
 
     final rowDataController = RowDataController(
       rowInfo: rowInfo,
-      fieldController: fieldController,
       rowCache: rowCache,
     );
 
@@ -83,7 +82,6 @@ class GridTestContext {
     return CellControllerBuilder(
       cellId: rowBloc.state.cellByFieldId[fieldId]!,
       cellCache: rowCache.cellCache,
-      delegate: rowDataController,
     );
   }