| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 | 
							- import 'dart:async';
 
- import 'dart:collection';
 
- import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
 
- import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
 
- import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
 
- import 'package:app_flowy/plugins/grid/application/row/row_service.dart';
 
- import 'package:appflowy_board/appflowy_board.dart';
 
- import 'package:dartz/dartz.dart';
 
- import 'package:equatable/equatable.dart';
 
- import 'package:flowy_sdk/log.dart';
 
- import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
 
- 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 'board_data_controller.dart';
 
- import 'group_controller.dart';
 
- part 'board_bloc.freezed.dart';
 
- class BoardBloc extends Bloc<BoardEvent, BoardState> {
 
-   final BoardDataController _gridDataController;
 
-   late final AppFlowyBoardController boardController;
 
-   final MoveRowFFIService _rowService;
 
-   final LinkedHashMap<String, GroupController> groupControllers =
 
-       LinkedHashMap();
 
-   GridFieldController get fieldController =>
 
-       _gridDataController.fieldController;
 
-   String get gridId => _gridDataController.gridId;
 
-   BoardBloc({required ViewPB view})
 
-       : _rowService = MoveRowFFIService(gridId: view.id),
 
-         _gridDataController = BoardDataController(view: view),
 
-         super(BoardState.initial(view.id)) {
 
-     boardController = AppFlowyBoardController(
 
-       onMoveGroup: (
 
-         fromGroupId,
 
-         fromIndex,
 
-         toGroupId,
 
-         toIndex,
 
-       ) {
 
-         _moveGroup(fromGroupId, toGroupId);
 
-       },
 
-       onMoveGroupItem: (
 
-         groupId,
 
-         fromIndex,
 
-         toIndex,
 
-       ) {
 
-         final fromRow = groupControllers[groupId]?.rowAtIndex(fromIndex);
 
-         final toRow = groupControllers[groupId]?.rowAtIndex(toIndex);
 
-         _moveRow(fromRow, groupId, toRow);
 
-       },
 
-       onMoveGroupItemToGroup: (
 
-         fromGroupId,
 
-         fromIndex,
 
-         toGroupId,
 
-         toIndex,
 
-       ) {
 
-         final fromRow = groupControllers[fromGroupId]?.rowAtIndex(fromIndex);
 
-         final toRow = groupControllers[toGroupId]?.rowAtIndex(toIndex);
 
-         _moveRow(fromRow, toGroupId, toRow);
 
-       },
 
-     );
 
-     on<BoardEvent>(
 
-       (event, emit) async {
 
-         await event.when(
 
-           initial: () async {
 
-             _startListening();
 
-             await _openGrid(emit);
 
-           },
 
-           createBottomRow: (groupId) async {
 
-             final startRowId = groupControllers[groupId]?.lastRow()?.id;
 
-             final result = await _gridDataController.createBoardCard(
 
-               groupId,
 
-               startRowId: startRowId,
 
-             );
 
-             result.fold(
 
-               (_) {},
 
-               (err) => Log.error(err),
 
-             );
 
-           },
 
-           createHeaderRow: (String groupId) async {
 
-             final result = await _gridDataController.createBoardCard(groupId);
 
-             result.fold(
 
-               (_) {},
 
-               (err) => Log.error(err),
 
-             );
 
-           },
 
-           didCreateRow: (group, row, int? index) {
 
-             emit(state.copyWith(
 
-               editingRow: Some(BoardEditingRow(
 
-                 group: group,
 
-                 row: row,
 
-                 index: index,
 
-               )),
 
-             ));
 
-             _groupItemStartEditing(group, row, true);
 
-           },
 
-           startEditingRow: (group, row) {
 
-             emit(state.copyWith(
 
-               editingRow: Some(BoardEditingRow(
 
-                 group: group,
 
-                 row: row,
 
-                 index: null,
 
-               )),
 
-             ));
 
-             _groupItemStartEditing(group, row, true);
 
-           },
 
-           endEditingRow: (rowId) {
 
-             state.editingRow.fold(() => null, (editingRow) {
 
-               assert(editingRow.row.id == rowId);
 
-               _groupItemStartEditing(editingRow.group, editingRow.row, false);
 
-               emit(state.copyWith(editingRow: none()));
 
-             });
 
-           },
 
-           didReceiveGridUpdate: (GridPB grid) {
 
-             emit(state.copyWith(grid: Some(grid)));
 
-           },
 
-           didReceiveError: (FlowyError error) {
 
-             emit(state.copyWith(noneOrError: some(error)));
 
-           },
 
-           didReceiveGroups: (List<GroupPB> groups) {
 
-             emit(
 
-               state.copyWith(
 
-                 groupIds: groups.map((group) => group.groupId).toList(),
 
-               ),
 
-             );
 
-           },
 
-         );
 
-       },
 
-     );
 
-   }
 
-   void _groupItemStartEditing(GroupPB group, RowPB row, bool isEdit) {
 
-     final fieldContext = fieldController.getField(group.fieldId);
 
-     if (fieldContext == null) {
 
-       Log.warn("FieldContext should not be null");
 
-       return;
 
-     }
 
-     boardController.enableGroupDragging(!isEdit);
 
-     // boardController.updateGroupItem(
 
-     //   group.groupId,
 
-     //   GroupItem(
 
-     //     row: row,
 
-     //     fieldContext: fieldContext,
 
-     //     isDraggable: !isEdit,
 
-     //   ),
 
-     // );
 
-   }
 
-   void _moveRow(RowPB? fromRow, String columnId, RowPB? toRow) {
 
-     if (fromRow != null) {
 
-       _rowService
 
-           .moveGroupRow(
 
-         fromRowId: fromRow.id,
 
-         toGroupId: columnId,
 
-         toRowId: toRow?.id,
 
-       )
 
-           .then((result) {
 
-         result.fold((l) => null, (r) => add(BoardEvent.didReceiveError(r)));
 
-       });
 
-     }
 
-   }
 
-   void _moveGroup(String fromGroupId, String toGroupId) {
 
-     _rowService
 
-         .moveGroup(
 
-       fromGroupId: fromGroupId,
 
-       toGroupId: toGroupId,
 
-     )
 
-         .then((result) {
 
-       result.fold((l) => null, (r) => add(BoardEvent.didReceiveError(r)));
 
-     });
 
-   }
 
-   @override
 
-   Future<void> close() async {
 
-     await _gridDataController.dispose();
 
-     for (final controller in groupControllers.values) {
 
-       controller.dispose();
 
-     }
 
-     return super.close();
 
-   }
 
-   void initializeGroups(List<GroupPB> groupsData) {
 
-     for (var controller in groupControllers.values) {
 
-       controller.dispose();
 
-     }
 
-     groupControllers.clear();
 
-     boardController.clear();
 
-     //
 
-     List<AppFlowyGroupData> groups = groupsData
 
-         .where((group) => fieldController.getField(group.fieldId) != null)
 
-         .map((group) {
 
-       return AppFlowyGroupData(
 
-         id: group.groupId,
 
-         name: group.desc,
 
-         items: _buildGroupItems(group),
 
-         customData: GroupData(
 
-           group: group,
 
-           fieldContext: fieldController.getField(group.fieldId)!,
 
-         ),
 
-       );
 
-     }).toList();
 
-     boardController.addGroups(groups);
 
-     for (final group in groupsData) {
 
-       final delegate = GroupControllerDelegateImpl(
 
-         controller: boardController,
 
-         fieldController: fieldController,
 
-         onNewColumnItem: (groupId, row, index) {
 
-           add(BoardEvent.didCreateRow(group, row, index));
 
-         },
 
-       );
 
-       final controller = GroupController(
 
-         gridId: state.gridId,
 
-         group: group,
 
-         delegate: delegate,
 
-       );
 
-       controller.startListening();
 
-       groupControllers[controller.group.groupId] = (controller);
 
-     }
 
-   }
 
-   GridRowCache? getRowCache(String blockId) {
 
-     final GridBlockCache? blockCache = _gridDataController.blocks[blockId];
 
-     return blockCache?.rowCache;
 
-   }
 
-   void _startListening() {
 
-     _gridDataController.addListener(
 
-       onGridChanged: (grid) {
 
-         if (!isClosed) {
 
-           add(BoardEvent.didReceiveGridUpdate(grid));
 
-         }
 
-       },
 
-       didLoadGroups: (groups) {
 
-         if (isClosed) return;
 
-         initializeGroups(groups);
 
-         add(BoardEvent.didReceiveGroups(groups));
 
-       },
 
-       onDeletedGroup: (groupIds) {
 
-         if (isClosed) return;
 
-         //
 
-       },
 
-       onInsertedGroup: (insertedGroups) {
 
-         if (isClosed) return;
 
-         //
 
-       },
 
-       onUpdatedGroup: (updatedGroups) {
 
-         if (isClosed) return;
 
-         for (final group in updatedGroups) {
 
-           final columnController =
 
-               boardController.getGroupController(group.groupId);
 
-           columnController?.updateGroupName(group.desc);
 
-         }
 
-       },
 
-       onError: (err) {
 
-         Log.error(err);
 
-       },
 
-       onResetGroups: (groups) {
 
-         if (isClosed) return;
 
-         initializeGroups(groups);
 
-         add(BoardEvent.didReceiveGroups(groups));
 
-       },
 
-     );
 
-   }
 
-   List<AppFlowyGroupItem> _buildGroupItems(GroupPB group) {
 
-     final items = group.rows.map((row) {
 
-       final fieldContext = fieldController.getField(group.fieldId);
 
-       return GroupItem(
 
-         row: row,
 
-         fieldContext: fieldContext!,
 
-       );
 
-     }).toList();
 
-     return <AppFlowyGroupItem>[...items];
 
-   }
 
-   Future<void> _openGrid(Emitter<BoardState> emit) async {
 
-     final result = await _gridDataController.openGrid();
 
-     result.fold(
 
-       (grid) => emit(
 
-         state.copyWith(loadingState: GridLoadingState.finish(left(unit))),
 
-       ),
 
-       (err) => emit(
 
-         state.copyWith(loadingState: GridLoadingState.finish(right(err))),
 
-       ),
 
-     );
 
-   }
 
- }
 
- @freezed
 
- class BoardEvent with _$BoardEvent {
 
-   const factory BoardEvent.initial() = _InitialBoard;
 
-   const factory BoardEvent.createBottomRow(String groupId) = _CreateBottomRow;
 
-   const factory BoardEvent.createHeaderRow(String groupId) = _CreateHeaderRow;
 
-   const factory BoardEvent.didCreateRow(
 
-     GroupPB group,
 
-     RowPB row,
 
-     int? index,
 
-   ) = _DidCreateRow;
 
-   const factory BoardEvent.startEditingRow(
 
-     GroupPB group,
 
-     RowPB row,
 
-   ) = _StartEditRow;
 
-   const factory BoardEvent.endEditingRow(String rowId) = _EndEditRow;
 
-   const factory BoardEvent.didReceiveError(FlowyError error) = _DidReceiveError;
 
-   const factory BoardEvent.didReceiveGridUpdate(
 
-     GridPB grid,
 
-   ) = _DidReceiveGridUpdate;
 
-   const factory BoardEvent.didReceiveGroups(List<GroupPB> groups) =
 
-       _DidReceiveGroups;
 
- }
 
- @freezed
 
- class BoardState with _$BoardState {
 
-   const factory BoardState({
 
-     required String gridId,
 
-     required Option<GridPB> grid,
 
-     required List<String> groupIds,
 
-     required Option<BoardEditingRow> editingRow,
 
-     required GridLoadingState loadingState,
 
-     required Option<FlowyError> noneOrError,
 
-   }) = _BoardState;
 
-   factory BoardState.initial(String gridId) => BoardState(
 
-         grid: none(),
 
-         gridId: gridId,
 
-         groupIds: [],
 
-         editingRow: none(),
 
-         noneOrError: none(),
 
-         loadingState: const _Loading(),
 
-       );
 
- }
 
- @freezed
 
- class GridLoadingState with _$GridLoadingState {
 
-   const factory GridLoadingState.loading() = _Loading;
 
-   const factory GridLoadingState.finish(
 
-       Either<Unit, FlowyError> successOrFail) = _Finish;
 
- }
 
- class GridFieldEquatable extends Equatable {
 
-   final UnmodifiableListView<FieldPB> _fields;
 
-   const GridFieldEquatable(
 
-     UnmodifiableListView<FieldPB> fields,
 
-   ) : _fields = fields;
 
-   @override
 
-   List<Object?> get props {
 
-     if (_fields.isEmpty) {
 
-       return [];
 
-     }
 
-     return [
 
-       _fields.length,
 
-       _fields
 
-           .map((field) => field.width)
 
-           .reduce((value, element) => value + element),
 
-     ];
 
-   }
 
-   UnmodifiableListView<FieldPB> get value => UnmodifiableListView(_fields);
 
- }
 
- class GroupItem extends AppFlowyGroupItem {
 
-   final RowPB row;
 
-   final GridFieldContext fieldContext;
 
-   GroupItem({
 
-     required this.row,
 
-     required this.fieldContext,
 
-     bool draggable = true,
 
-   }) {
 
-     super.draggable = draggable;
 
-   }
 
-   @override
 
-   String get id => row.id;
 
- }
 
- class GroupControllerDelegateImpl extends GroupControllerDelegate {
 
-   final GridFieldController fieldController;
 
-   final AppFlowyBoardController controller;
 
-   final void Function(String, RowPB, int?) onNewColumnItem;
 
-   GroupControllerDelegateImpl({
 
-     required this.controller,
 
-     required this.fieldController,
 
-     required this.onNewColumnItem,
 
-   });
 
-   @override
 
-   void insertRow(GroupPB group, RowPB row, int? index) {
 
-     final fieldContext = fieldController.getField(group.fieldId);
 
-     if (fieldContext == null) {
 
-       Log.warn("FieldContext should not be null");
 
-       return;
 
-     }
 
-     if (index != null) {
 
-       final item = GroupItem(
 
-         row: row,
 
-         fieldContext: fieldContext,
 
-       );
 
-       controller.insertGroupItem(group.groupId, index, item);
 
-     } else {
 
-       final item = GroupItem(
 
-         row: row,
 
-         fieldContext: fieldContext,
 
-       );
 
-       controller.addGroupItem(group.groupId, item);
 
-     }
 
-   }
 
-   @override
 
-   void removeRow(GroupPB group, String rowId) {
 
-     controller.removeGroupItem(group.groupId, rowId);
 
-   }
 
-   @override
 
-   void updateRow(GroupPB group, RowPB row) {
 
-     final fieldContext = fieldController.getField(group.fieldId);
 
-     if (fieldContext == null) {
 
-       Log.warn("FieldContext should not be null");
 
-       return;
 
-     }
 
-     controller.updateGroupItem(
 
-       group.groupId,
 
-       GroupItem(
 
-         row: row,
 
-         fieldContext: fieldContext,
 
-       ),
 
-     );
 
-   }
 
-   @override
 
-   void addNewRow(GroupPB group, RowPB row, int? index) {
 
-     final fieldContext = fieldController.getField(group.fieldId);
 
-     if (fieldContext == null) {
 
-       Log.warn("FieldContext should not be null");
 
-       return;
 
-     }
 
-     final item = GroupItem(
 
-       row: row,
 
-       fieldContext: fieldContext,
 
-       draggable: false,
 
-     );
 
-     if (index != null) {
 
-       controller.insertGroupItem(group.groupId, index, item);
 
-     } else {
 
-       controller.addGroupItem(group.groupId, item);
 
-     }
 
-     onNewColumnItem(group.groupId, row, index);
 
-   }
 
- }
 
- class BoardEditingRow {
 
-   GroupPB group;
 
-   RowPB row;
 
-   int? index;
 
-   BoardEditingRow({
 
-     required this.group,
 
-     required this.row,
 
-     required this.index,
 
-   });
 
- }
 
- class GroupData {
 
-   final GroupPB group;
 
-   final GridFieldContext fieldContext;
 
-   GroupData({
 
-     required this.group,
 
-     required this.fieldContext,
 
-   });
 
-   CheckboxGroup? asCheckboxGroup() {
 
-     if (fieldType != FieldType.Checkbox) return null;
 
-     return CheckboxGroup(group);
 
-   }
 
-   FieldType get fieldType => fieldContext.fieldType;
 
- }
 
- class CheckboxGroup {
 
-   final GroupPB group;
 
-   CheckboxGroup(this.group);
 
- // Hardcode value: "Yes" that equal to the value defined in Rust
 
- // pub const CHECK: &str = "Yes";
 
-   bool get isCheck => group.groupId == "Yes";
 
- }
 
 
  |