board_bloc.dart 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import 'dart:async';
  2. import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
  3. import 'package:app_flowy/plugins/grid/application/grid_data_controller.dart';
  4. import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
  5. import 'package:appflowy_board/appflowy_board.dart';
  6. import 'package:dartz/dartz.dart';
  7. import 'package:equatable/equatable.dart';
  8. import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
  9. import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
  10. import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
  11. import 'package:flutter_bloc/flutter_bloc.dart';
  12. import 'package:freezed_annotation/freezed_annotation.dart';
  13. import 'dart:collection';
  14. part 'board_bloc.freezed.dart';
  15. class BoardBloc extends Bloc<BoardEvent, BoardState> {
  16. final GridDataController _gridDataController;
  17. late final BoardDataController boardDataController;
  18. BoardBloc({required ViewPB view})
  19. : _gridDataController = GridDataController(view: view),
  20. super(BoardState.initial(view.id)) {
  21. boardDataController = BoardDataController(
  22. onMoveColumn: (
  23. fromIndex,
  24. toIndex,
  25. ) {},
  26. onMoveColumnItem: (
  27. columnId,
  28. fromIndex,
  29. toIndex,
  30. ) {},
  31. onMoveColumnItemToColumn: (
  32. fromColumnId,
  33. fromIndex,
  34. toColumnId,
  35. toIndex,
  36. ) {},
  37. );
  38. // boardDataController.addColumns(_buildColumns());
  39. on<BoardEvent>(
  40. (event, emit) async {
  41. await event.when(
  42. initial: () async {
  43. _startListening();
  44. await _loadGrid(emit);
  45. },
  46. createRow: () {
  47. _gridDataController.createRow();
  48. },
  49. didReceiveGridUpdate: (GridPB grid) {
  50. emit(state.copyWith(grid: Some(grid)));
  51. },
  52. didReceiveFieldUpdate: (UnmodifiableListView<GridFieldPB> fields) {
  53. emit(state.copyWith(fields: GridFieldEquatable(fields)));
  54. },
  55. didReceiveRowUpdate: (
  56. List<GridRowInfo> newRowInfos,
  57. GridRowChangeReason reason,
  58. ) {
  59. emit(state.copyWith(rowInfos: newRowInfos, reason: reason));
  60. },
  61. );
  62. },
  63. );
  64. }
  65. @override
  66. Future<void> close() async {
  67. await _gridDataController.dispose();
  68. return super.close();
  69. }
  70. GridRowCache? getRowCache(String blockId, String rowId) {
  71. final GridBlockCache? blockCache = _gridDataController.blocks[blockId];
  72. return blockCache?.rowCache;
  73. }
  74. void _startListening() {
  75. _gridDataController.addListener(
  76. onGridChanged: (grid) {
  77. if (!isClosed) {
  78. add(BoardEvent.didReceiveGridUpdate(grid));
  79. }
  80. },
  81. onRowsChanged: (rowInfos, reason) {
  82. if (!isClosed) {
  83. add(BoardEvent.didReceiveRowUpdate(rowInfos, reason));
  84. }
  85. },
  86. onFieldsChanged: (fields) {
  87. if (!isClosed) {
  88. _buildColumns(fields);
  89. add(BoardEvent.didReceiveFieldUpdate(fields));
  90. }
  91. },
  92. );
  93. }
  94. void _buildColumns(UnmodifiableListView<GridFieldPB> fields) {
  95. List<BoardColumnData> columns = [];
  96. for (final field in fields) {
  97. if (field.fieldType == FieldType.SingleSelect) {
  98. // return BoardColumnData(customData: field, id: field.id, desc: "1");
  99. }
  100. }
  101. boardDataController.addColumns(columns);
  102. // final column1 = BoardColumnData(id: "To Do", items: [
  103. // TextItem("Card 1"),
  104. // TextItem("Card 2"),
  105. // RichTextItem(title: "Card 3", subtitle: 'Aug 1, 2020 4:05 PM'),
  106. // TextItem("Card 4"),
  107. // ]);
  108. // final column2 = BoardColumnData(id: "In Progress", items: [
  109. // RichTextItem(title: "Card 5", subtitle: 'Aug 1, 2020 4:05 PM'),
  110. // TextItem("Card 6"),
  111. // ]);
  112. // final column3 = BoardColumnData(id: "Done", items: []);
  113. // boardDataController.addColumn(column1);
  114. // boardDataController.addColumn(column2);
  115. // boardDataController.addColumn(column3);
  116. }
  117. Future<void> _loadGrid(Emitter<BoardState> emit) async {
  118. final result = await _gridDataController.loadData();
  119. result.fold(
  120. (grid) => emit(
  121. state.copyWith(loadingState: GridLoadingState.finish(left(unit))),
  122. ),
  123. (err) => emit(
  124. state.copyWith(loadingState: GridLoadingState.finish(right(err))),
  125. ),
  126. );
  127. }
  128. }
  129. @freezed
  130. class BoardEvent with _$BoardEvent {
  131. const factory BoardEvent.initial() = InitialGrid;
  132. const factory BoardEvent.createRow() = _CreateRow;
  133. const factory BoardEvent.didReceiveRowUpdate(
  134. List<GridRowInfo> rows,
  135. GridRowChangeReason listState,
  136. ) = _DidReceiveRowUpdate;
  137. const factory BoardEvent.didReceiveFieldUpdate(
  138. UnmodifiableListView<GridFieldPB> fields,
  139. ) = _DidReceiveFieldUpdate;
  140. const factory BoardEvent.didReceiveGridUpdate(
  141. GridPB grid,
  142. ) = _DidReceiveGridUpdate;
  143. }
  144. @freezed
  145. class BoardState with _$BoardState {
  146. const factory BoardState({
  147. required String gridId,
  148. required Option<GridPB> grid,
  149. required GridFieldEquatable fields,
  150. required List<GridRowInfo> rowInfos,
  151. required GridLoadingState loadingState,
  152. required GridRowChangeReason reason,
  153. }) = _BoardState;
  154. factory BoardState.initial(String gridId) => BoardState(
  155. fields: GridFieldEquatable(UnmodifiableListView([])),
  156. rowInfos: [],
  157. grid: none(),
  158. gridId: gridId,
  159. loadingState: const _Loading(),
  160. reason: const InitialListState(),
  161. );
  162. }
  163. @freezed
  164. class GridLoadingState with _$GridLoadingState {
  165. const factory GridLoadingState.loading() = _Loading;
  166. const factory GridLoadingState.finish(
  167. Either<Unit, FlowyError> successOrFail) = _Finish;
  168. }
  169. class GridFieldEquatable extends Equatable {
  170. final UnmodifiableListView<GridFieldPB> _fields;
  171. const GridFieldEquatable(
  172. UnmodifiableListView<GridFieldPB> fields,
  173. ) : _fields = fields;
  174. @override
  175. List<Object?> get props {
  176. if (_fields.isEmpty) {
  177. return [];
  178. }
  179. return [
  180. _fields.length,
  181. _fields
  182. .map((field) => field.width)
  183. .reduce((value, element) => value + element),
  184. ];
  185. }
  186. UnmodifiableListView<GridFieldPB> get value => UnmodifiableListView(_fields);
  187. }
  188. class TextItem extends ColumnItem {
  189. final String s;
  190. TextItem(this.s);
  191. @override
  192. String get id => s;
  193. }
  194. class RichTextItem extends ColumnItem {
  195. final String title;
  196. final String subtitle;
  197. RichTextItem({required this.title, required this.subtitle});
  198. @override
  199. String get id => title;
  200. }