grid_bloc.dart 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import 'dart:async';
  2. import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
  3. import 'package:dartz/dartz.dart';
  4. import 'package:flowy_sdk/log.dart';
  5. import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
  6. import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
  7. import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
  8. import 'package:flutter_bloc/flutter_bloc.dart';
  9. import 'package:freezed_annotation/freezed_annotation.dart';
  10. import 'field/grid_listenr.dart';
  11. import 'grid_listener.dart';
  12. import 'grid_service.dart';
  13. part 'grid_bloc.freezed.dart';
  14. class GridBloc extends Bloc<GridEvent, GridState> {
  15. final View view;
  16. final GridService _gridService;
  17. final GridListener _gridListener;
  18. final GridFieldsListener _fieldListener;
  19. GridBloc({required this.view})
  20. : _fieldListener = GridFieldsListener(gridId: view.id),
  21. _gridService = GridService(),
  22. _gridListener = GridListener(gridId: view.id),
  23. super(GridState.initial()) {
  24. on<GridEvent>(
  25. (event, emit) async {
  26. await event.map(
  27. initial: (InitialGrid value) async {
  28. await _initGrid(emit);
  29. _startListening();
  30. },
  31. createRow: (_CreateRow value) {
  32. _gridService.createRow(gridId: view.id);
  33. },
  34. updateDesc: (_Desc value) {},
  35. didReceiveRowUpdate: (_DidReceiveRowUpdate value) {
  36. emit(state.copyWith(rows: value.rows));
  37. },
  38. didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
  39. emit(state.copyWith(fields: value.fields));
  40. },
  41. );
  42. },
  43. );
  44. }
  45. @override
  46. Future<void> close() async {
  47. await _fieldListener.stop();
  48. await _gridListener.stop();
  49. return super.close();
  50. }
  51. Future<void> _initGrid(Emitter<GridState> emit) async {
  52. _fieldListener.updateFieldsNotifier.addPublishListener((result) {
  53. result.fold(
  54. (fields) => add(GridEvent.didReceiveFieldUpdate(fields)),
  55. (err) => Log.error(err),
  56. );
  57. });
  58. _fieldListener.start();
  59. await _loadGrid(emit);
  60. }
  61. void _startListening() {
  62. _gridListener.rowsUpdateNotifier.addPublishListener((result) {
  63. result.fold((gridBlockChangeset) {
  64. for (final changeset in gridBlockChangeset) {
  65. if (changeset.insertedRows.isNotEmpty) {
  66. _insertRows(changeset.insertedRows);
  67. }
  68. if (changeset.deletedRows.isNotEmpty) {
  69. _deleteRows(changeset.deletedRows);
  70. }
  71. if (changeset.updatedRows.isNotEmpty) {
  72. _updateRows(changeset.updatedRows);
  73. }
  74. }
  75. }, (err) => Log.error(err));
  76. });
  77. _gridListener.start();
  78. }
  79. Future<void> _loadGrid(Emitter<GridState> emit) async {
  80. final result = await _gridService.loadGrid(gridId: view.id);
  81. return Future(
  82. () => result.fold(
  83. (grid) async => await _loadFields(grid, emit),
  84. (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))),
  85. ),
  86. );
  87. }
  88. Future<void> _loadFields(Grid grid, Emitter<GridState> emit) async {
  89. final result = await _gridService.getFields(gridId: grid.id, fieldOrders: grid.fieldOrders);
  90. return Future(
  91. () => result.fold(
  92. (fields) {
  93. emit(state.copyWith(
  94. grid: Some(grid),
  95. fields: fields.items,
  96. rows: _buildRows(grid.blockOrders),
  97. loadingState: GridLoadingState.finish(left(unit)),
  98. ));
  99. },
  100. (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))),
  101. ),
  102. );
  103. }
  104. void _deleteRows(List<RowOrder> deletedRows) {
  105. final List<RowOrder> rows = List.from(state.rows);
  106. rows.retainWhere(
  107. (row) => deletedRows.where((deletedRow) => deletedRow.rowId == row.rowId).isEmpty,
  108. );
  109. add(GridEvent.didReceiveRowUpdate(rows));
  110. }
  111. void _insertRows(List<IndexRowOrder> createdRows) {
  112. final List<RowOrder> rows = List.from(state.rows);
  113. for (final newRow in createdRows) {
  114. if (newRow.hasIndex()) {
  115. rows.insert(newRow.index, newRow.rowOrder);
  116. } else {
  117. rows.add(newRow.rowOrder);
  118. }
  119. }
  120. add(GridEvent.didReceiveRowUpdate(rows));
  121. }
  122. void _updateRows(List<RowOrder> updatedRows) {
  123. final List<RowOrder> rows = List.from(state.rows);
  124. for (final updatedRow in updatedRows) {
  125. final index = rows.indexWhere((row) => row.rowId == updatedRow.rowId);
  126. if (index != -1) {
  127. rows.removeAt(index);
  128. rows.insert(index, updatedRow);
  129. }
  130. }
  131. add(GridEvent.didReceiveRowUpdate(rows));
  132. }
  133. List<RowOrder> _buildRows(List<GridBlockOrder> blockOrders) {
  134. return blockOrders.expand((blockOrder) => blockOrder.rowOrders).toList();
  135. }
  136. }
  137. @freezed
  138. class GridEvent with _$GridEvent {
  139. const factory GridEvent.initial() = InitialGrid;
  140. const factory GridEvent.updateDesc(String gridId, String desc) = _Desc;
  141. const factory GridEvent.createRow() = _CreateRow;
  142. const factory GridEvent.didReceiveRowUpdate(List<RowOrder> rows) = _DidReceiveRowUpdate;
  143. const factory GridEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
  144. }
  145. @freezed
  146. class GridState with _$GridState {
  147. const factory GridState({
  148. required GridLoadingState loadingState,
  149. required List<Field> fields,
  150. required List<RowOrder> rows,
  151. required Option<Grid> grid,
  152. }) = _GridState;
  153. factory GridState.initial() => GridState(
  154. loadingState: const _Loading(),
  155. fields: [],
  156. rows: [],
  157. grid: none(),
  158. );
  159. }
  160. @freezed
  161. class GridLoadingState with _$GridLoadingState {
  162. const factory GridLoadingState.loading() = _Loading;
  163. const factory GridLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish;
  164. }