grid_bloc.dart 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import 'dart:async';
  2. import 'package:dartz/dartz.dart';
  3. import 'package:equatable/equatable.dart';
  4. import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
  5. import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
  6. import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart';
  7. import 'package:flutter_bloc/flutter_bloc.dart';
  8. import 'package:freezed_annotation/freezed_annotation.dart';
  9. import 'cell/cell_service/cell_service.dart';
  10. import 'grid_service.dart';
  11. import 'row/row_service.dart';
  12. import 'dart:collection';
  13. part 'grid_bloc.freezed.dart';
  14. class GridBloc extends Bloc<GridEvent, GridState> {
  15. final GridService _gridService;
  16. final GridFieldCache fieldCache;
  17. late final GridRowCache rowCache;
  18. late final GridCellCache cellCache;
  19. GridBloc({required View view})
  20. : _gridService = GridService(gridId: view.id),
  21. fieldCache = GridFieldCache(gridId: view.id),
  22. super(GridState.initial(view.id)) {
  23. rowCache = GridRowCache(
  24. gridId: view.id,
  25. fieldDelegate: GridRowCacheDelegateImpl(fieldCache),
  26. );
  27. cellCache = GridCellCache(
  28. gridId: view.id,
  29. fieldDelegate: GridCellCacheDelegateImpl(fieldCache),
  30. );
  31. on<GridEvent>(
  32. (event, emit) async {
  33. await event.when(
  34. initial: () async {
  35. _startListening();
  36. await _loadGrid(emit);
  37. },
  38. createRow: () {
  39. _gridService.createRow();
  40. },
  41. didReceiveRowUpdate: (rows, listState) {
  42. emit(state.copyWith(rows: rows, listState: listState));
  43. },
  44. didReceiveFieldUpdate: (fields) {
  45. emit(state.copyWith(rows: rowCache.clonedRows, fields: GridFieldEquatable(fields)));
  46. },
  47. );
  48. },
  49. );
  50. }
  51. @override
  52. Future<void> close() async {
  53. await _gridService.closeGrid();
  54. await cellCache.dispose();
  55. await rowCache.dispose();
  56. await fieldCache.dispose();
  57. return super.close();
  58. }
  59. void _startListening() {
  60. fieldCache.addListener(
  61. listenWhen: () => !isClosed,
  62. onChanged: (fields) => add(GridEvent.didReceiveFieldUpdate(fields)),
  63. );
  64. rowCache.addListener(
  65. listenWhen: () => !isClosed,
  66. onChanged: (rows, listState) => add(GridEvent.didReceiveRowUpdate(rowCache.clonedRows, listState)),
  67. );
  68. }
  69. Future<void> _loadGrid(Emitter<GridState> emit) async {
  70. final result = await _gridService.loadGrid();
  71. return Future(
  72. () => result.fold(
  73. (grid) async => await _loadFields(grid, emit),
  74. (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))),
  75. ),
  76. );
  77. }
  78. Future<void> _loadFields(Grid grid, Emitter<GridState> emit) async {
  79. final result = await _gridService.getFields(fieldOrders: grid.fieldOrders);
  80. return Future(
  81. () => result.fold(
  82. (fields) {
  83. fieldCache.fields = fields.items;
  84. rowCache.resetRows(grid.blockOrders);
  85. emit(state.copyWith(
  86. grid: Some(grid),
  87. fields: GridFieldEquatable(fieldCache.fields),
  88. rows: rowCache.clonedRows,
  89. loadingState: GridLoadingState.finish(left(unit)),
  90. ));
  91. },
  92. (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))),
  93. ),
  94. );
  95. }
  96. }
  97. @freezed
  98. class GridEvent with _$GridEvent {
  99. const factory GridEvent.initial() = InitialGrid;
  100. const factory GridEvent.createRow() = _CreateRow;
  101. const factory GridEvent.didReceiveRowUpdate(List<GridRow> rows, GridRowChangeReason listState) = _DidReceiveRowUpdate;
  102. const factory GridEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
  103. }
  104. @freezed
  105. class GridState with _$GridState {
  106. const factory GridState({
  107. required String gridId,
  108. required Option<Grid> grid,
  109. required GridFieldEquatable fields,
  110. required List<GridRow> rows,
  111. required GridLoadingState loadingState,
  112. required GridRowChangeReason listState,
  113. }) = _GridState;
  114. factory GridState.initial(String gridId) => GridState(
  115. fields: const GridFieldEquatable([]),
  116. rows: [],
  117. grid: none(),
  118. gridId: gridId,
  119. loadingState: const _Loading(),
  120. listState: const InitialListState(),
  121. );
  122. }
  123. @freezed
  124. class GridLoadingState with _$GridLoadingState {
  125. const factory GridLoadingState.loading() = _Loading;
  126. const factory GridLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish;
  127. }
  128. class GridFieldEquatable extends Equatable {
  129. final List<Field> _fields;
  130. const GridFieldEquatable(List<Field> fields) : _fields = fields;
  131. @override
  132. List<Object?> get props {
  133. return [
  134. _fields.length,
  135. _fields.map((field) => field.width).reduce((value, element) => value + element),
  136. ];
  137. }
  138. UnmodifiableListView<Field> get value => UnmodifiableListView(_fields);
  139. }