Sfoglia il codice sorgente

chore: renmae property & add documentation

appflowy 2 anni fa
parent
commit
29f2d863ff
24 ha cambiato i file con 190 aggiunte e 189 eliminazioni
  1. 4 3
      frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart
  2. 13 13
      frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_cache.dart
  3. 3 7
      frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart
  4. 10 15
      frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart
  5. 14 14
      frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart
  6. 42 42
      frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart
  7. 1 1
      frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart
  8. 5 5
      frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart
  9. 2 2
      frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart
  10. 7 7
      frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart
  11. 2 2
      frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart
  12. 2 3
      frontend/app_flowy/lib/workspace/application/grid/grid_service.dart
  13. 1 1
      frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart
  14. 5 5
      frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart
  15. 4 4
      frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart
  16. 49 39
      frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart
  17. 2 2
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart
  18. 3 3
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart
  19. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart
  20. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart
  21. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart
  22. 5 5
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart
  23. 12 12
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart
  24. 1 1
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart

+ 4 - 3
frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart → frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart

@@ -6,21 +6,22 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
 
 import 'block_listener.dart';
 
+/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information
 class GridBlockCache {
   final String gridId;
   final GridBlock block;
-  late GridRowsCache _rowCache;
+  late GridRowCache _rowCache;
   late GridBlockListener _listener;
 
   List<GridRow> get rows => _rowCache.rows;
-  GridRowsCache get rowCache => _rowCache;
+  GridRowCache get rowCache => _rowCache;
 
   GridBlockCache({
     required this.gridId,
     required this.block,
     required GridFieldCache fieldCache,
   }) {
-    _rowCache = GridRowsCache(
+    _rowCache = GridRowCache(
       gridId: gridId,
       block: block,
       notifier: GridRowCacheFieldNotifierImpl(fieldCache),

+ 13 - 13
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart → frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_cache.dart

@@ -2,11 +2,9 @@ part of 'cell_service.dart';
 
 typedef GridCellMap = LinkedHashMap<String, GridCellIdentifier>;
 
-class _GridCellCacheValue {
-  GridCellCacheKey key;
+class GridCell {
   dynamic object;
-  _GridCellCacheValue({
-    required this.key,
+  GridCell({
     required this.object,
   });
 }
@@ -22,14 +20,16 @@ class GridCellCacheKey {
   });
 }
 
-/// GridCellsCache is used to cache cell data of each Grid.
+/// GridCellCache is used to cache cell data of each block.
 /// We use GridCellCacheKey to index the cell in the cache.
-class GridCellsCache {
+/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid
+/// for more information
+class GridCellCache {
   final String gridId;
 
-  /// fieldId: {cacheKey: cacheData}
+  /// fieldId: {cacheKey: GridCell}
   final Map<String, Map<String, dynamic>> _cellDataByFieldId = {};
-  GridCellsCache({
+  GridCellCache({
     required this.gridId,
   });
 
@@ -37,14 +37,14 @@ class GridCellsCache {
     _cellDataByFieldId.remove(fieldId);
   }
 
-  void insert<T extends _GridCellCacheValue>(T value) {
-    var map = _cellDataByFieldId[value.key.fieldId];
+  void insert<T extends GridCell>(GridCellCacheKey key, T value) {
+    var map = _cellDataByFieldId[key.fieldId];
     if (map == null) {
-      _cellDataByFieldId[value.key.fieldId] = {};
-      map = _cellDataByFieldId[value.key.fieldId];
+      _cellDataByFieldId[key.fieldId] = {};
+      map = _cellDataByFieldId[key.fieldId];
     }
 
-    map![value.key.rowId] = value.object;
+    map![key.rowId] = value.object;
   }
 
   T? get<T>(GridCellCacheKey key) {

+ 3 - 7
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart

@@ -11,22 +11,18 @@ abstract class ICellDataParser<T> {
 
 class GridCellDataLoader<T> {
   final CellService service = CellService();
-  final GridCellIdentifier gridCell;
+  final GridCellIdentifier cellId;
   final ICellDataParser<T> parser;
   final bool reloadOnFieldChanged;
 
   GridCellDataLoader({
-    required this.gridCell,
+    required this.cellId,
     required this.parser,
     this.reloadOnFieldChanged = false,
   });
 
   Future<T?> loadData() {
-    final fut = service.getCell(
-      gridId: gridCell.gridId,
-      fieldId: gridCell.field.id,
-      rowId: gridCell.rowId,
-    );
+    final fut = service.getCell(cellId: cellId);
     return fut.then(
       (result) => result.fold((Cell cell) {
         try {

+ 10 - 15
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart

@@ -7,21 +7,16 @@ abstract class IGridCellDataPersistence<D> {
 }
 
 class CellDataPersistence implements IGridCellDataPersistence<String> {
-  final GridCellIdentifier gridCell;
+  final GridCellIdentifier cellId;
 
   CellDataPersistence({
-    required this.gridCell,
+    required this.cellId,
   });
   final CellService _cellService = CellService();
 
   @override
   Future<Option<FlowyError>> save(String data) async {
-    final fut = _cellService.updateCell(
-      gridId: gridCell.gridId,
-      fieldId: gridCell.field.id,
-      rowId: gridCell.rowId,
-      data: data,
-    );
+    final fut = _cellService.updateCell(cellId: cellId, data: data);
 
     return fut.then((result) {
       return result.fold(
@@ -38,14 +33,14 @@ class CalendarData with _$CalendarData {
 }
 
 class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData> {
-  final GridCellIdentifier gridCell;
+  final GridCellIdentifier cellId;
   DateCellDataPersistence({
-    required this.gridCell,
+    required this.cellId,
   });
 
   @override
   Future<Option<FlowyError>> save(CalendarData data) {
-    var payload = DateChangesetPayload.create()..cellIdentifier = _cellIdentifier(gridCell);
+    var payload = DateChangesetPayload.create()..cellIdentifier = _makeCellIdPayload(cellId);
 
     final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString();
     payload.date = date;
@@ -63,9 +58,9 @@ class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData>
   }
 }
 
-CellIdentifierPayload _cellIdentifier(GridCellIdentifier gridCell) {
+CellIdentifierPayload _makeCellIdPayload(GridCellIdentifier cellId) {
   return CellIdentifierPayload.create()
-    ..gridId = gridCell.gridId
-    ..fieldId = gridCell.field.id
-    ..rowId = gridCell.rowId;
+    ..gridId = cellId.gridId
+    ..fieldId = cellId.fieldId
+    ..rowId = cellId.rowId;
 }

+ 14 - 14
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart

@@ -23,7 +23,7 @@ import 'cell_field_notifier.dart';
 part 'cell_service.freezed.dart';
 part 'cell_data_loader.dart';
 part 'context_builder.dart';
-part 'cache.dart';
+part 'cell_cache.dart';
 part 'cell_data_persistence.dart';
 
 // key: rowId
@@ -32,28 +32,24 @@ class CellService {
   CellService();
 
   Future<Either<void, FlowyError>> updateCell({
-    required String gridId,
-    required String fieldId,
-    required String rowId,
+    required GridCellIdentifier cellId,
     required String data,
   }) {
     final payload = CellChangeset.create()
-      ..gridId = gridId
-      ..fieldId = fieldId
-      ..rowId = rowId
+      ..gridId = cellId.gridId
+      ..fieldId = cellId.fieldId
+      ..rowId = cellId.rowId
       ..content = data;
     return GridEventUpdateCell(payload).send();
   }
 
   Future<Either<Cell, FlowyError>> getCell({
-    required String gridId,
-    required String fieldId,
-    required String rowId,
+    required GridCellIdentifier cellId,
   }) {
     final payload = CellIdentifierPayload.create()
-      ..gridId = gridId
-      ..fieldId = fieldId
-      ..rowId = rowId;
+      ..gridId = cellId.gridId
+      ..fieldId = cellId.fieldId
+      ..rowId = cellId.rowId;
     return GridEventGetCell(payload).send();
   }
 }
@@ -71,7 +67,11 @@ class GridCellIdentifier with _$GridCellIdentifier {
   // ignore: unused_element
   const GridCellIdentifier._();
 
+  String get fieldId => field.id;
+
+  FieldType get fieldType => field.fieldType;
+
   ValueKey key() {
-    return ValueKey(rowId + field.id + "${field.fieldType}");
+    return ValueKey(rowId + fieldId + "${field.fieldType}");
   }
 }

+ 42 - 42
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart

@@ -6,97 +6,99 @@ typedef GridDateCellController = IGridCellController<DateCellData, CalendarData>
 typedef GridURLCellController = IGridCellController<URLCellData, String>;
 
 class GridCellControllerBuilder {
-  final GridCellIdentifier _gridCell;
-  final GridCellsCache _cellCache;
+  final GridCellIdentifier _cellId;
+  final GridCellCache _cellCache;
   final GridFieldCache _fieldCache;
 
-  GridCellControllerBuilder(
-      {required GridCellIdentifier gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache})
-      : _cellCache = cellCache,
+  GridCellControllerBuilder({
+    required GridCellIdentifier cellId,
+    required GridCellCache cellCache,
+    required GridFieldCache fieldCache,
+  })  : _cellCache = cellCache,
         _fieldCache = fieldCache,
-        _gridCell = gridCell;
+        _cellId = cellId;
 
   IGridCellController build() {
     final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache));
 
-    switch (_gridCell.field.fieldType) {
+    switch (_cellId.fieldType) {
       case FieldType.Checkbox:
         final cellDataLoader = GridCellDataLoader(
-          gridCell: _gridCell,
+          cellId: _cellId,
           parser: StringCellDataParser(),
         );
         return GridCellController(
-          gridCell: _gridCell,
+          cellId: _cellId,
           cellCache: _cellCache,
           cellDataLoader: cellDataLoader,
           fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
+          cellDataPersistence: CellDataPersistence(cellId: _cellId),
         );
       case FieldType.DateTime:
         final cellDataLoader = GridCellDataLoader(
-          gridCell: _gridCell,
+          cellId: _cellId,
           parser: DateCellDataParser(),
           reloadOnFieldChanged: true,
         );
 
         return GridDateCellController(
-          gridCell: _gridCell,
+          cellId: _cellId,
           cellCache: _cellCache,
           cellDataLoader: cellDataLoader,
           fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
+          cellDataPersistence: DateCellDataPersistence(cellId: _cellId),
         );
       case FieldType.Number:
         final cellDataLoader = GridCellDataLoader(
-          gridCell: _gridCell,
+          cellId: _cellId,
           parser: StringCellDataParser(),
         );
         return GridCellController(
-          gridCell: _gridCell,
+          cellId: _cellId,
           cellCache: _cellCache,
           cellDataLoader: cellDataLoader,
           fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
+          cellDataPersistence: CellDataPersistence(cellId: _cellId),
         );
       case FieldType.RichText:
         final cellDataLoader = GridCellDataLoader(
-          gridCell: _gridCell,
+          cellId: _cellId,
           parser: StringCellDataParser(),
         );
         return GridCellController(
-          gridCell: _gridCell,
+          cellId: _cellId,
           cellCache: _cellCache,
           cellDataLoader: cellDataLoader,
           fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
+          cellDataPersistence: CellDataPersistence(cellId: _cellId),
         );
       case FieldType.MultiSelect:
       case FieldType.SingleSelect:
         final cellDataLoader = GridCellDataLoader(
-          gridCell: _gridCell,
+          cellId: _cellId,
           parser: SelectOptionCellDataParser(),
           reloadOnFieldChanged: true,
         );
 
         return GridSelectOptionCellController(
-          gridCell: _gridCell,
+          cellId: _cellId,
           cellCache: _cellCache,
           cellDataLoader: cellDataLoader,
           fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
+          cellDataPersistence: CellDataPersistence(cellId: _cellId),
         );
 
       case FieldType.URL:
         final cellDataLoader = GridCellDataLoader(
-          gridCell: _gridCell,
+          cellId: _cellId,
           parser: URLCellDataParser(),
         );
         return GridURLCellController(
-          gridCell: _gridCell,
+          cellId: _cellId,
           cellCache: _cellCache,
           cellDataLoader: cellDataLoader,
           fieldNotifier: cellFieldNotifier,
-          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
+          cellDataPersistence: CellDataPersistence(cellId: _cellId),
         );
     }
     throw UnimplementedError;
@@ -112,8 +114,8 @@ class GridCellControllerBuilder {
 ///
 // ignore: must_be_immutable
 class IGridCellController<T, D> extends Equatable {
-  final GridCellIdentifier gridCell;
-  final GridCellsCache _cellsCache;
+  final GridCellIdentifier cellId;
+  final GridCellCache _cellsCache;
   final GridCellCacheKey _cacheKey;
   final FieldService _fieldService;
   final GridCellFieldNotifier _fieldNotifier;
@@ -130,8 +132,8 @@ class IGridCellController<T, D> extends Equatable {
   bool _isDispose = false;
 
   IGridCellController({
-    required this.gridCell,
-    required GridCellsCache cellCache,
+    required this.cellId,
+    required GridCellCache cellCache,
     required GridCellFieldNotifier fieldNotifier,
     required GridCellDataLoader<T> cellDataLoader,
     required IGridCellDataPersistence<D> cellDataPersistence,
@@ -139,29 +141,27 @@ class IGridCellController<T, D> extends Equatable {
         _cellDataLoader = cellDataLoader,
         _cellDataPersistence = cellDataPersistence,
         _fieldNotifier = fieldNotifier,
-        _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id),
-        _cacheKey = GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id);
+        _fieldService = FieldService(gridId: cellId.gridId, fieldId: cellId.field.id),
+        _cacheKey = GridCellCacheKey(rowId: cellId.rowId, fieldId: cellId.field.id);
 
   IGridCellController<T, D> clone() {
     return IGridCellController(
-        gridCell: gridCell,
+        cellId: cellId,
         cellDataLoader: _cellDataLoader,
         cellCache: _cellsCache,
         fieldNotifier: _fieldNotifier,
         cellDataPersistence: _cellDataPersistence);
   }
 
-  String get gridId => gridCell.gridId;
+  String get gridId => cellId.gridId;
 
-  String get rowId => gridCell.rowId;
+  String get rowId => cellId.rowId;
 
-  String get cellId => gridCell.rowId + gridCell.field.id;
+  String get fieldId => cellId.field.id;
 
-  String get fieldId => gridCell.field.id;
+  Field get field => cellId.field;
 
-  Field get field => gridCell.field;
-
-  FieldType get fieldType => gridCell.field.fieldType;
+  FieldType get fieldType => cellId.field.fieldType;
 
   VoidCallback? startListening({required void Function(T?) onCellChanged, VoidCallback? onCellFieldChanged}) {
     if (isListening) {
@@ -177,7 +177,7 @@ class IGridCellController<T, D> extends Equatable {
     ///   user input: 12
     ///   cell display: $12
     _cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey));
-    _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id);
+    _cellListener = CellListener(rowId: cellId.rowId, fieldId: cellId.field.id);
 
     /// 1.Listen on user edit event and load the new cell data if needed.
     _cellListener.start(onCellChanged: (result) {
@@ -264,7 +264,7 @@ class IGridCellController<T, D> extends Equatable {
     _loadDataOperation = Timer(const Duration(milliseconds: 10), () {
       _cellDataLoader.loadData().then((data) {
         _cellDataNotifier?.value = data;
-        _cellsCache.insert(_GridCellCacheValue(key: _cacheKey, object: data));
+        _cellsCache.insert(_cacheKey, GridCell(object: data));
       });
     });
   }
@@ -287,7 +287,7 @@ class IGridCellController<T, D> extends Equatable {
   }
 
   @override
-  List<Object> get props => [_cellsCache.get(_cacheKey) ?? "", cellId];
+  List<Object> get props => [_cellsCache.get(_cacheKey) ?? "", cellId.rowId + cellId.field.id];
 }
 
 class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier {

+ 1 - 1
frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart

@@ -17,7 +17,7 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
 
   SelectOptionCellEditorBloc({
     required this.cellController,
-  })  : _selectOptionService = SelectOptionService(gridCell: cellController.gridCell),
+  })  : _selectOptionService = SelectOptionService(cellId: cellController.cellId),
         super(SelectOptionEditorState.initial(cellController)) {
     on<SelectOptionEditorEvent>(
       (event, emit) async {

+ 5 - 5
frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart

@@ -7,12 +7,12 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
 import 'cell_service/cell_service.dart';
 
 class SelectOptionService {
-  final GridCellIdentifier gridCell;
-  SelectOptionService({required this.gridCell});
+  final GridCellIdentifier cellId;
+  SelectOptionService({required this.cellId});
 
-  String get gridId => gridCell.gridId;
-  String get fieldId => gridCell.field.id;
-  String get rowId => gridCell.rowId;
+  String get gridId => cellId.gridId;
+  String get fieldId => cellId.field.id;
+  String get rowId => cellId.rowId;
 
   Future<Either<Unit, FlowyError>> create({required String name}) {
     return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then(

+ 2 - 2
frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart

@@ -9,7 +9,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
   FieldEditorBloc({
     required String gridId,
     required String fieldName,
-    required IFieldContextLoader fieldContextLoader,
+    required IFieldTypeOptionLoader fieldContextLoader,
   }) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) {
     on<FieldEditorEvent>(
       (event, emit) async {
@@ -53,7 +53,7 @@ class FieldEditorState with _$FieldEditorState {
     required Option<GridFieldContext> fieldContext,
   }) = _FieldEditorState;
 
-  factory FieldEditorState.initial(String gridId, String fieldName, IFieldContextLoader loader) => FieldEditorState(
+  factory FieldEditorState.initial(String gridId, String fieldName, IFieldTypeOptionLoader loader) => FieldEditorState(
         gridId: gridId,
         fieldContext: none(),
         errorText: '',

+ 7 - 7
frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart

@@ -141,7 +141,7 @@ class GridFieldCellContext with _$GridFieldCellContext {
   }) = _GridFieldCellContext;
 }
 
-abstract class IFieldContextLoader {
+abstract class IFieldTypeOptionLoader {
   String get gridId;
   Future<Either<FieldTypeOptionData, FlowyError>> load();
 
@@ -155,10 +155,10 @@ abstract class IFieldContextLoader {
   }
 }
 
-class NewFieldContextLoader extends IFieldContextLoader {
+class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {
   @override
   final String gridId;
-  NewFieldContextLoader({
+  NewFieldTypeOptionLoader({
     required this.gridId,
   });
 
@@ -172,12 +172,12 @@ class NewFieldContextLoader extends IFieldContextLoader {
   }
 }
 
-class FieldContextLoader extends IFieldContextLoader {
+class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
   @override
   final String gridId;
   final Field field;
 
-  FieldContextLoader({
+  FieldTypeOptionLoader({
     required this.gridId,
     required this.field,
   });
@@ -195,14 +195,14 @@ class FieldContextLoader extends IFieldContextLoader {
 
 class GridFieldContext {
   final String gridId;
-  final IFieldContextLoader _loader;
+  final IFieldTypeOptionLoader _loader;
 
   late FieldTypeOptionData _data;
   ValueNotifier<Field>? _fieldNotifier;
 
   GridFieldContext({
     required this.gridId,
-    required IFieldContextLoader loader,
+    required IFieldTypeOptionLoader loader,
   }) : _loader = loader;
 
   Future<Either<Unit, FlowyError>> loadData() async {

+ 2 - 2
frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart

@@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
-import 'block/block_service.dart';
+import 'block/block_cache.dart';
 import 'grid_service.dart';
 import 'row/row_service.dart';
 import 'dart:collection';
@@ -68,7 +68,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
     return super.close();
   }
 
-  GridRowsCache? getRowCache(String blockId, String rowId) {
+  GridRowCache? getRowCache(String blockId, String rowId) {
     final GridBlockCache? blockCache = _blocks[blockId];
     return blockCache?.rowCache;
   }

+ 2 - 3
frontend/app_flowy/lib/workspace/application/grid/grid_service.dart

@@ -61,13 +61,12 @@ typedef FieldsCallback = void Function(List<Field>);
 
 class GridFieldCache {
   final String gridId;
-  late final GridFieldsListener _fieldListener;
+  final GridFieldsListener _fieldListener;
   FieldsNotifier? _fieldNotifier = FieldsNotifier();
   final Map<FieldsCallback, VoidCallback> _fieldsCallbackMap = {};
   final Map<FieldChangesetCallback, FieldChangesetCallback> _changesetCallbackMap = {};
 
-  GridFieldCache({required this.gridId}) {
-    _fieldListener = GridFieldsListener(gridId: gridId);
+  GridFieldCache({required this.gridId}) : _fieldListener = GridFieldsListener(gridId: gridId) {
     _fieldListener.start(onFieldsChanged: (result) {
       result.fold(
         (changeset) {

+ 1 - 1
frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart

@@ -15,7 +15,7 @@ class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState>
       : _rowService = RowService(
           gridId: rowData.gridId,
           blockId: rowData.blockId,
-          rowId: rowData.rowId,
+          rowId: rowData.id,
         ),
         super(RowActionSheetState.initial(rowData)) {
     on<RowActionSheetEvent>(

+ 5 - 5
frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart

@@ -11,19 +11,19 @@ part 'row_bloc.freezed.dart';
 
 class RowBloc extends Bloc<RowEvent, RowState> {
   final RowService _rowService;
-  final GridRowsCache _rowCache;
+  final GridRowCache _rowCache;
   void Function()? _rowListenFn;
 
   RowBloc({
     required GridRow rowData,
-    required GridRowsCache rowCache,
+    required GridRowCache rowCache,
   })  : _rowService = RowService(
           gridId: rowData.gridId,
           blockId: rowData.blockId,
-          rowId: rowData.rowId,
+          rowId: rowData.id,
         ),
         _rowCache = rowCache,
-        super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) {
+        super(RowState.initial(rowData, rowCache.loadGridCells(rowData.id))) {
     on<RowEvent>(
       (event, emit) async {
         await event.map(
@@ -58,7 +58,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
 
   Future<void> _startListening() async {
     _rowListenFn = _rowCache.addListener(
-      rowId: state.rowData.rowId,
+      rowId: state.rowData.id,
       onCellUpdated: (cellDatas, reason) => add(RowEvent.didReceiveCellDatas(cellDatas, reason)),
       listenWhen: () => !isClosed,
     );

+ 4 - 4
frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart

@@ -8,12 +8,12 @@ part 'row_detail_bloc.freezed.dart';
 
 class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
   final GridRow rowData;
-  final GridRowsCache _rowCache;
+  final GridRowCache _rowCache;
   void Function()? _rowListenFn;
 
   RowDetailBloc({
     required this.rowData,
-    required GridRowsCache rowCache,
+    required GridRowCache rowCache,
   })  : _rowCache = rowCache,
         super(RowDetailState.initial()) {
     on<RowDetailEvent>(
@@ -41,14 +41,14 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
 
   Future<void> _startListening() async {
     _rowListenFn = _rowCache.addListener(
-      rowId: rowData.rowId,
+      rowId: rowData.id,
       onCellUpdated: (cellDatas, reason) => add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())),
       listenWhen: () => !isClosed,
     );
   }
 
   Future<void> _loadCellData() async {
-    final cellDataMap = _rowCache.loadGridCells(rowData.rowId);
+    final cellDataMap = _rowCache.loadGridCells(rowData.id);
     if (!isClosed) {
       add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList()));
     }

+ 49 - 39
frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart

@@ -21,35 +21,46 @@ abstract class GridRowCacheFieldNotifier {
   void dispose();
 }
 
-class GridRowsCache {
+/// Cache the rows in memory
+/// Insert / delete / update row
+///
+/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information.
+
+class GridRowCache {
   final String gridId;
   final GridBlock block;
-  final _Notifier _notifier;
+
+  /// _rows containers the current block's rows
+  /// Use List to reverse the order of the GridRow.
   List<GridRow> _rows = [];
+
+  /// Use Map for faster access the raw row data.
   final HashMap<String, Row> _rowByRowId;
+
+  final GridCellCache _cellCache;
   final GridRowCacheFieldNotifier _fieldNotifier;
-  final GridCellsCache _cellCache;
+  final _GridRowChangesetNotifier _rowChangeReasonNotifier;
 
-  List<GridRow> get rows => _rows;
-  GridCellsCache get cellCache => _cellCache;
+  UnmodifiableListView<GridRow> get rows => UnmodifiableListView(_rows);
+  GridCellCache get cellCache => _cellCache;
 
-  GridRowsCache({
+  GridRowCache({
     required this.gridId,
     required this.block,
     required GridRowCacheFieldNotifier notifier,
-  })  : _cellCache = GridCellsCache(gridId: gridId),
+  })  : _cellCache = GridCellCache(gridId: gridId),
         _rowByRowId = HashMap(),
-        _notifier = _Notifier(),
+        _rowChangeReasonNotifier = _GridRowChangesetNotifier(),
         _fieldNotifier = notifier {
     //
-    notifier.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange()));
+    notifier.onFieldsChanged(() => _rowChangeReasonNotifier.receive(const GridRowChangeReason.fieldDidChange()));
     notifier.onFieldChanged((field) => _cellCache.remove(field.id));
     _rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList();
   }
 
   Future<void> dispose() async {
     _fieldNotifier.dispose();
-    _notifier.dispose();
+    _rowChangeReasonNotifier.dispose();
     await _cellCache.dispose();
   }
 
@@ -73,14 +84,15 @@ class GridRowsCache {
     final Map<String, String> deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId};
 
     _rows.asMap().forEach((index, row) {
-      if (deletedRowByRowId[row.rowId] == null) {
+      if (deletedRowByRowId[row.id] == null) {
         newRows.add(row);
       } else {
+        _rowByRowId.remove(row.id);
         deletedIndex.add(DeletedIndex(index: index, row: row));
       }
     });
     _rows = newRows;
-    _notifier.receive(GridRowChangeReason.delete(deletedIndex));
+    _rowChangeReasonNotifier.receive(GridRowChangeReason.delete(deletedIndex));
   }
 
   void _insertRows(List<InsertedRow> insertRows) {
@@ -89,17 +101,16 @@ class GridRowsCache {
     }
 
     InsertedIndexs insertIndexs = [];
-    final List<GridRow> newRows = _rows;
     for (final insertRow in insertRows) {
       final insertIndex = InsertedIndex(
         index: insertRow.index,
         rowId: insertRow.rowId,
       );
       insertIndexs.add(insertIndex);
-      newRows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble())));
+      _rows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble())));
     }
 
-    _notifier.receive(GridRowChangeReason.insert(insertIndexs));
+    _rowChangeReasonNotifier.receive(GridRowChangeReason.insert(insertIndexs));
   }
 
   void _updateRows(List<UpdatedRow> updatedRows) {
@@ -108,20 +119,19 @@ class GridRowsCache {
     }
 
     final UpdatedIndexs updatedIndexs = UpdatedIndexs();
-    final List<GridRow> newRows = _rows;
     for (final updatedRow in updatedRows) {
       final rowId = updatedRow.rowId;
-      final index = newRows.indexWhere((row) => row.rowId == rowId);
+      final index = _rows.indexWhere((row) => row.id == rowId);
       if (index != -1) {
         _rowByRowId[rowId] = updatedRow.row;
 
-        newRows.removeAt(index);
-        newRows.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble()));
+        _rows.removeAt(index);
+        _rows.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble()));
         updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId);
       }
     }
 
-    _notifier.receive(GridRowChangeReason.update(updatedIndexs));
+    _rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs));
   }
 
   void _hideRows(List<String> hideRows) {}
@@ -131,8 +141,8 @@ class GridRowsCache {
   void onRowsChanged(
     void Function(GridRowChangeReason) onRowChanged,
   ) {
-    _notifier.addListener(() {
-      onRowChanged(_notifier._reason);
+    _rowChangeReasonNotifier.addListener(() {
+      onRowChanged(_rowChangeReasonNotifier.reason);
     });
   }
 
@@ -151,12 +161,12 @@ class GridRowsCache {
           final row = _rowByRowId[rowId];
           if (row != null) {
             final GridCellMap cellDataMap = _makeGridCells(rowId, row);
-            onCellUpdated(cellDataMap, _notifier._reason);
+            onCellUpdated(cellDataMap, _rowChangeReasonNotifier.reason);
           }
         }
       }
 
-      _notifier._reason.whenOrNull(
+      _rowChangeReasonNotifier.reason.whenOrNull(
         update: (indexs) {
           if (indexs[rowId] != null) notifyUpdate();
         },
@@ -164,12 +174,12 @@ class GridRowsCache {
       );
     }
 
-    _notifier.addListener(listenrHandler);
+    _rowChangeReasonNotifier.addListener(listenrHandler);
     return listenrHandler;
   }
 
   void removeRowListener(VoidCallback callback) {
-    _notifier.removeListener(callback);
+    _rowChangeReasonNotifier.removeListener(callback);
   }
 
   GridCellMap loadGridCells(String rowId) {
@@ -215,19 +225,19 @@ class GridRowsCache {
     updatedRow.freeze();
 
     _rowByRowId[updatedRow.id] = updatedRow;
-    final index = _rows.indexWhere((gridRow) => gridRow.rowId == updatedRow.id);
+    final index = _rows.indexWhere((gridRow) => gridRow.id == updatedRow.id);
     if (index != -1) {
       // update the corresponding row in _rows if they are not the same
-      if (_rows[index].data != updatedRow) {
-        final row = _rows.removeAt(index).copyWith(data: updatedRow);
+      if (_rows[index].rawRow != updatedRow) {
+        final row = _rows.removeAt(index).copyWith(rawRow: updatedRow);
         _rows.insert(index, row);
 
         // Calculate the update index
         final UpdatedIndexs updatedIndexs = UpdatedIndexs();
-        updatedIndexs[row.rowId] = UpdatedIndex(index: index, rowId: row.rowId);
+        updatedIndexs[row.id] = UpdatedIndex(index: index, rowId: row.id);
 
         //
-        _notifier.receive(GridRowChangeReason.update(updatedIndexs));
+        _rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs));
       }
     }
   }
@@ -237,19 +247,19 @@ class GridRowsCache {
       gridId: gridId,
       blockId: block.id,
       fields: _fieldNotifier.fields,
-      rowId: rowId,
+      id: rowId,
       height: rowHeight,
     );
   }
 }
 
-class _Notifier extends ChangeNotifier {
-  GridRowChangeReason _reason = const InitialListState();
+class _GridRowChangesetNotifier extends ChangeNotifier {
+  GridRowChangeReason reason = const InitialListState();
 
-  _Notifier();
+  _GridRowChangesetNotifier();
 
-  void receive(GridRowChangeReason reason) {
-    _reason = reason;
+  void receive(GridRowChangeReason newReason) {
+    reason = newReason;
     reason.map(
       insert: (_) => notifyListeners(),
       delete: (_) => notifyListeners(),
@@ -319,10 +329,10 @@ class GridRow with _$GridRow {
   const factory GridRow({
     required String gridId,
     required String blockId,
-    required String rowId,
+    required String id,
     required UnmodifiableListView<Field> fields,
     required double height,
-    Row? data,
+    Row? rawRow,
   }) = _GridRow;
 }
 

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

@@ -227,7 +227,7 @@ class _GridRowsState extends State<_GridRows> {
     GridRow rowData,
     Animation<double> animation,
   ) {
-    final rowCache = context.read<GridBloc>().getRowCache(rowData.blockId, rowData.rowId);
+    final rowCache = context.read<GridBloc>().getRowCache(rowData.blockId, rowData.id);
     final fieldCache = context.read<GridBloc>().fieldCache;
     if (rowCache != null) {
       return SizeTransition(
@@ -236,7 +236,7 @@ class _GridRowsState extends State<_GridRows> {
           rowData: rowData,
           rowCache: rowCache,
           fieldCache: fieldCache,
-          key: ValueKey(rowData.rowId),
+          key: ValueKey(rowData.id),
         ),
       );
     } else {

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

@@ -14,7 +14,7 @@ import 'text_cell.dart';
 import 'url_cell/url_cell.dart';
 
 class GridCellBuilder {
-  final GridCellsCache cellCache;
+  final GridCellCache cellCache;
   final GridFieldCache fieldCache;
   GridCellBuilder({
     required this.cellCache,
@@ -23,12 +23,12 @@ class GridCellBuilder {
 
   GridCellWidget build(GridCellIdentifier cell, {GridCellStyle? style}) {
     final cellControllerBuilder = GridCellControllerBuilder(
-      gridCell: cell,
+      cellId: cell,
       cellCache: cellCache,
       fieldCache: fieldCache,
     );
     final key = cell.key();
-    switch (cell.field.fieldType) {
+    switch (cell.fieldType) {
       case FieldType.Checkbox:
         return CheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key);
       case FieldType.DateTime:

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

@@ -65,7 +65,7 @@ class GridFieldCell extends StatelessWidget {
     FieldEditor(
       gridId: state.gridId,
       fieldName: field.name,
-      contextLoader: FieldContextLoader(
+      contextLoader: FieldTypeOptionLoader(
         gridId: state.gridId,
         field: field,
       ),

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart

@@ -14,7 +14,7 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
   final String gridId;
   final String fieldName;
 
-  final IFieldContextLoader contextLoader;
+  final IFieldTypeOptionLoader contextLoader;
   const FieldEditor({
     required this.gridId,
     required this.fieldName,

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

@@ -151,7 +151,7 @@ class CreateFieldButton extends StatelessWidget {
       onTap: () => FieldEditor(
         gridId: gridId,
         fieldName: "",
-        contextLoader: NewFieldContextLoader(gridId: gridId),
+        contextLoader: NewFieldTypeOptionLoader(gridId: gridId),
       ).show(context),
       leftIcon: svgWidget("home/add"),
     );

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

@@ -16,7 +16,7 @@ import 'row_detail.dart';
 
 class GridRowWidget extends StatefulWidget {
   final GridRow rowData;
-  final GridRowsCache rowCache;
+  final GridRowCache rowCache;
   final GridCellBuilder cellBuilder;
 
   GridRowWidget({
@@ -183,12 +183,12 @@ class _RowCells extends StatelessWidget {
 
   List<Widget> _makeCells(BuildContext context, GridCellMap gridCellMap) {
     return gridCellMap.values.map(
-      (gridCell) {
-        final GridCellWidget child = builder.build(gridCell);
+      (cellId) {
+        final GridCellWidget child = builder.build(cellId);
         accessoryBuilder(GridCellAccessoryBuildContext buildContext) {
           final builder = child.accessoryBuilder;
           List<GridCellAccessory> accessories = [];
-          if (gridCell.field.isPrimary) {
+          if (cellId.field.isPrimary) {
             accessories.add(PrimaryCellAccessory(
               onTapCallback: onExpand,
               isCellEditing: buildContext.isCellEditing,
@@ -202,7 +202,7 @@ class _RowCells extends StatelessWidget {
         }
 
         return CellContainer(
-          width: gridCell.field.width.toDouble(),
+          width: cellId.field.width.toDouble(),
           child: child,
           rowStateNotifier: Provider.of<RegionStateNotifier>(context, listen: false),
           accessoryBuilder: accessoryBuilder,

+ 12 - 12
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart

@@ -22,7 +22,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 
 class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate {
   final GridRow rowData;
-  final GridRowsCache rowCache;
+  final GridRowCache rowCache;
   final GridCellBuilder cellBuilder;
 
   const RowDetailPage({
@@ -122,7 +122,7 @@ class _PropertyList extends StatelessWidget {
             itemCount: state.gridCells.length,
             itemBuilder: (BuildContext context, int index) {
               return _RowDetailCell(
-                gridCell: state.gridCells[index],
+                cellId: state.gridCells[index],
                 cellBuilder: cellBuilder,
               );
             },
@@ -137,10 +137,10 @@ class _PropertyList extends StatelessWidget {
 }
 
 class _RowDetailCell extends StatelessWidget {
-  final GridCellIdentifier gridCell;
+  final GridCellIdentifier cellId;
   final GridCellBuilder cellBuilder;
   const _RowDetailCell({
-    required this.gridCell,
+    required this.cellId,
     required this.cellBuilder,
     Key? key,
   }) : super(key: key);
@@ -148,8 +148,8 @@ class _RowDetailCell extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
-    final style = _customCellStyle(theme, gridCell.field.fieldType);
-    final cell = cellBuilder.build(gridCell, style: style);
+    final style = _customCellStyle(theme, cellId.fieldType);
+    final cell = cellBuilder.build(cellId, style: style);
 
     final gesture = GestureDetector(
       behavior: HitTestBehavior.translucent,
@@ -169,7 +169,7 @@ class _RowDetailCell extends StatelessWidget {
           children: [
             SizedBox(
               width: 150,
-              child: FieldCellButton(field: gridCell.field, onTap: () => _showFieldEditor(context)),
+              child: FieldCellButton(field: cellId.field, onTap: () => _showFieldEditor(context)),
             ),
             const HSpace(10),
             Expanded(child: gesture),
@@ -181,11 +181,11 @@ class _RowDetailCell extends StatelessWidget {
 
   void _showFieldEditor(BuildContext context) {
     FieldEditor(
-      gridId: gridCell.gridId,
-      fieldName: gridCell.field.name,
-      contextLoader: FieldContextLoader(
-        gridId: gridCell.gridId,
-        field: gridCell.field,
+      gridId: cellId.gridId,
+      fieldName: cellId.field.name,
+      contextLoader: FieldTypeOptionLoader(
+        gridId: cellId.gridId,
+        field: cellId.field,
       ),
     ).show(context);
   }

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

@@ -116,7 +116,7 @@ class _GridPropertyCell extends StatelessWidget {
         FieldEditor(
           gridId: gridId,
           fieldName: field.name,
-          contextLoader: FieldContextLoader(gridId: gridId, field: field),
+          contextLoader: FieldTypeOptionLoader(gridId: gridId, field: field),
         ).show(context, anchorDirection: AnchorDirection.bottomRight);
       },
     );