grid_service.dart 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import 'dart:collection';
  2. import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart';
  3. import 'package:dartz/dartz.dart';
  4. import 'package:flowy_sdk/dispatch/dispatch.dart';
  5. import 'package:flowy_sdk/log.dart';
  6. import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
  7. import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
  8. import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
  9. import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
  10. import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
  11. import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
  12. import 'package:flutter/foundation.dart';
  13. import 'row/row_service.dart';
  14. class GridService {
  15. final String gridId;
  16. GridService({
  17. required this.gridId,
  18. });
  19. Future<Either<Grid, FlowyError>> loadGrid() async {
  20. await FolderEventSetLatestView(ViewId(value: gridId)).send();
  21. final payload = GridId(value: gridId);
  22. return GridEventGetGrid(payload).send();
  23. }
  24. Future<Either<Row, FlowyError>> createRow({Option<String>? startRowId}) {
  25. CreateRowPayload payload = CreateRowPayload.create()..gridId = gridId;
  26. startRowId?.fold(() => null, (id) => payload.startRowId = id);
  27. return GridEventCreateRow(payload).send();
  28. }
  29. Future<Either<RepeatedField, FlowyError>> getFields({required List<FieldOrder> fieldOrders}) {
  30. final payload = QueryFieldPayload.create()
  31. ..gridId = gridId
  32. ..fieldOrders = RepeatedFieldOrder(items: fieldOrders);
  33. return GridEventGetFields(payload).send();
  34. }
  35. Future<Either<Unit, FlowyError>> closeGrid() {
  36. final request = ViewId(value: gridId);
  37. return FolderEventCloseView(request).send();
  38. }
  39. }
  40. class FieldsNotifier extends ChangeNotifier {
  41. List<Field> _fields = [];
  42. set fields(List<Field> fields) {
  43. _fields = fields;
  44. notifyListeners();
  45. }
  46. List<Field> get fields => _fields;
  47. }
  48. typedef FieldChangesetCallback = void Function(GridFieldChangeset);
  49. typedef FieldsCallback = void Function(List<Field>);
  50. class GridFieldCache {
  51. final String gridId;
  52. late final GridFieldsListener _fieldListener;
  53. FieldsNotifier? _fieldNotifier = FieldsNotifier();
  54. final Map<FieldsCallback, VoidCallback> _fieldsCallbackMap = {};
  55. final Map<FieldChangesetCallback, FieldChangesetCallback> _changesetCallbackMap = {};
  56. GridFieldCache({required this.gridId}) {
  57. _fieldListener = GridFieldsListener(gridId: gridId);
  58. _fieldListener.start(onFieldsChanged: (result) {
  59. result.fold(
  60. (changeset) {
  61. _deleteFields(changeset.deletedFields);
  62. _insertFields(changeset.insertedFields);
  63. _updateFields(changeset.updatedFields);
  64. for (final listener in _changesetCallbackMap.values) {
  65. listener(changeset);
  66. }
  67. },
  68. (err) => Log.error(err),
  69. );
  70. });
  71. }
  72. Future<void> dispose() async {
  73. await _fieldListener.stop();
  74. _fieldNotifier?.dispose();
  75. _fieldNotifier = null;
  76. }
  77. UnmodifiableListView<Field> get unmodifiableFields => UnmodifiableListView(_fieldNotifier?.fields ?? []);
  78. List<Field> get fields => [..._fieldNotifier?.fields ?? []];
  79. set fields(List<Field> fields) {
  80. _fieldNotifier?.fields = [...fields];
  81. }
  82. void addListener({
  83. FieldsCallback? onFields,
  84. FieldChangesetCallback? onChangeset,
  85. bool Function()? listenWhen,
  86. }) {
  87. if (onChangeset != null) {
  88. fn(c) {
  89. if (listenWhen != null && listenWhen() == false) {
  90. return;
  91. }
  92. onChangeset(c);
  93. }
  94. _changesetCallbackMap[onChangeset] = fn;
  95. }
  96. if (onFields != null) {
  97. fn() {
  98. if (listenWhen != null && listenWhen() == false) {
  99. return;
  100. }
  101. onFields(fields);
  102. }
  103. _fieldsCallbackMap[onFields] = fn;
  104. _fieldNotifier?.addListener(fn);
  105. }
  106. }
  107. void removeListener({
  108. FieldsCallback? onFieldsListener,
  109. FieldChangesetCallback? onChangsetListener,
  110. }) {
  111. if (onFieldsListener != null) {
  112. final fn = _fieldsCallbackMap.remove(onFieldsListener);
  113. if (fn != null) {
  114. _fieldNotifier?.removeListener(fn);
  115. }
  116. }
  117. if (onChangsetListener != null) {
  118. _changesetCallbackMap.remove(onChangsetListener);
  119. }
  120. }
  121. void _deleteFields(List<FieldOrder> deletedFields) {
  122. if (deletedFields.isEmpty) {
  123. return;
  124. }
  125. final List<Field> newFields = fields;
  126. final Map<String, FieldOrder> deletedFieldMap = {
  127. for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder
  128. };
  129. newFields.retainWhere((field) => (deletedFieldMap[field.id] == null));
  130. _fieldNotifier?.fields = newFields;
  131. }
  132. void _insertFields(List<IndexField> insertedFields) {
  133. if (insertedFields.isEmpty) {
  134. return;
  135. }
  136. final List<Field> newFields = fields;
  137. for (final indexField in insertedFields) {
  138. if (newFields.length > indexField.index) {
  139. newFields.insert(indexField.index, indexField.field_1);
  140. } else {
  141. newFields.add(indexField.field_1);
  142. }
  143. }
  144. _fieldNotifier?.fields = newFields;
  145. }
  146. void _updateFields(List<Field> updatedFields) {
  147. if (updatedFields.isEmpty) {
  148. return;
  149. }
  150. final List<Field> newFields = fields;
  151. for (final updatedField in updatedFields) {
  152. final index = newFields.indexWhere((field) => field.id == updatedField.id);
  153. if (index != -1) {
  154. newFields.removeAt(index);
  155. newFields.insert(index, updatedField);
  156. }
  157. }
  158. _fieldNotifier?.fields = newFields;
  159. }
  160. }
  161. class GridRowCacheDelegateImpl extends GridRowCacheDelegate {
  162. final GridFieldCache _cache;
  163. FieldChangesetCallback? _onChangesetFn;
  164. FieldsCallback? _onFieldFn;
  165. GridRowCacheDelegateImpl(GridFieldCache cache) : _cache = cache;
  166. @override
  167. UnmodifiableListView<Field> get fields => _cache.unmodifiableFields;
  168. @override
  169. void onFieldsChanged(VoidCallback callback) {
  170. _onFieldFn = (_) => callback();
  171. _cache.addListener(onFields: _onFieldFn);
  172. }
  173. @override
  174. void onFieldUpdated(void Function(Field) callback) {
  175. _onChangesetFn = (GridFieldChangeset changeset) {
  176. for (final updatedField in changeset.updatedFields) {
  177. callback(updatedField);
  178. }
  179. };
  180. _cache.addListener(onChangeset: _onChangesetFn);
  181. }
  182. @override
  183. void dispose() {
  184. if (_onFieldFn != null) {
  185. _cache.removeListener(onFieldsListener: _onFieldFn!);
  186. _onFieldFn = null;
  187. }
  188. if (_onChangesetFn != null) {
  189. _cache.removeListener(onChangsetListener: _onChangesetFn!);
  190. _onChangesetFn = null;
  191. }
  192. }
  193. }