field_cache.dart 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. import 'dart:collection';
  2. import 'package:app_flowy/plugins/grid/application/field/grid_listener.dart';
  3. import 'package:app_flowy/plugins/grid/application/grid_service.dart';
  4. import 'package:app_flowy/plugins/grid/application/setting/setting_listener.dart';
  5. import 'package:dartz/dartz.dart';
  6. import 'package:flowy_sdk/log.dart';
  7. import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
  8. import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
  9. import 'package:flutter/foundation.dart';
  10. import '../row/row_cache.dart';
  11. class _GridFieldNotifier extends ChangeNotifier {
  12. List<GridFieldContext> _fieldContexts = [];
  13. set fieldContexts(List<GridFieldContext> fieldContexts) {
  14. _fieldContexts = fieldContexts;
  15. notifyListeners();
  16. }
  17. void notify() {
  18. notifyListeners();
  19. }
  20. List<GridFieldContext> get fieldContexts => _fieldContexts;
  21. }
  22. typedef OnChangeset = void Function(FieldChangesetPB);
  23. typedef OnReceiveFields = void Function(List<GridFieldContext>);
  24. class GridFieldController {
  25. final String gridId;
  26. final GridFieldsListener _fieldListener;
  27. final SettingListener _settingListener;
  28. final Map<OnReceiveFields, VoidCallback> _fieldCallbackMap = {};
  29. final Map<OnChangeset, OnChangeset> _changesetCallbackMap = {};
  30. _GridFieldNotifier? _fieldNotifier = _GridFieldNotifier();
  31. final GridFFIService _gridFFIService;
  32. GridFieldController({required this.gridId})
  33. : _fieldListener = GridFieldsListener(gridId: gridId),
  34. _gridFFIService = GridFFIService(gridId: gridId),
  35. _settingListener = SettingListener(gridId: gridId) {
  36. //Listen on field's changes
  37. _fieldListener.start(onFieldsChanged: (result) {
  38. result.fold(
  39. (changeset) {
  40. _deleteFields(changeset.deletedFields);
  41. _insertFields(changeset.insertedFields);
  42. _updateFields(changeset.updatedFields);
  43. for (final listener in _changesetCallbackMap.values) {
  44. listener(changeset);
  45. }
  46. },
  47. (err) => Log.error(err),
  48. );
  49. });
  50. //Listen on setting changes
  51. _settingListener.start(onSettingUpdated: (result) {
  52. result.fold(
  53. (setting) {
  54. final List<String> groupFieldIds = setting.groupConfigurations.items
  55. .map((item) => item.groupFieldId)
  56. .toList();
  57. bool isChanged = false;
  58. if (_fieldNotifier != null) {
  59. for (var field in _fieldNotifier!.fieldContexts) {
  60. if (groupFieldIds.contains(field.id)) {
  61. field._isGroupField = true;
  62. isChanged = true;
  63. }
  64. }
  65. if (isChanged) _fieldNotifier?.notify();
  66. }
  67. },
  68. (r) => Log.error(r),
  69. );
  70. });
  71. }
  72. Future<void> dispose() async {
  73. await _fieldListener.stop();
  74. _fieldNotifier?.dispose();
  75. _fieldNotifier = null;
  76. }
  77. List<GridFieldContext> get fieldContexts =>
  78. [..._fieldNotifier?.fieldContexts ?? []];
  79. Future<Either<Unit, FlowyError>> loadFields(
  80. {required List<FieldIdPB> fieldIds}) async {
  81. final result = await _gridFFIService.getFields(fieldIds: fieldIds);
  82. return Future(
  83. () => result.fold(
  84. (newFields) {
  85. _fieldNotifier?.fieldContexts = newFields.items
  86. .map((field) => GridFieldContext(field: field))
  87. .toList();
  88. return left(unit);
  89. },
  90. (err) => right(err),
  91. ),
  92. );
  93. }
  94. void addListener({
  95. OnReceiveFields? onFields,
  96. OnChangeset? onChangeset,
  97. bool Function()? listenWhen,
  98. }) {
  99. if (onChangeset != null) {
  100. callback(c) {
  101. if (listenWhen != null && listenWhen() == false) {
  102. return;
  103. }
  104. onChangeset(c);
  105. }
  106. _changesetCallbackMap[onChangeset] = callback;
  107. }
  108. if (onFields != null) {
  109. callback() {
  110. if (listenWhen != null && listenWhen() == false) {
  111. return;
  112. }
  113. onFields(fieldContexts);
  114. }
  115. _fieldCallbackMap[onFields] = callback;
  116. _fieldNotifier?.addListener(callback);
  117. }
  118. }
  119. void removeListener({
  120. OnReceiveFields? onFieldsListener,
  121. OnChangeset? onChangesetListener,
  122. }) {
  123. if (onFieldsListener != null) {
  124. final callback = _fieldCallbackMap.remove(onFieldsListener);
  125. if (callback != null) {
  126. _fieldNotifier?.removeListener(callback);
  127. }
  128. }
  129. if (onChangesetListener != null) {
  130. _changesetCallbackMap.remove(onChangesetListener);
  131. }
  132. }
  133. void _deleteFields(List<FieldIdPB> deletedFields) {
  134. if (deletedFields.isEmpty) {
  135. return;
  136. }
  137. final List<GridFieldContext> newFields = fieldContexts;
  138. final Map<String, FieldIdPB> deletedFieldMap = {
  139. for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder
  140. };
  141. newFields.retainWhere((field) => (deletedFieldMap[field.id] == null));
  142. _fieldNotifier?.fieldContexts = newFields;
  143. }
  144. void _insertFields(List<IndexFieldPB> insertedFields) {
  145. if (insertedFields.isEmpty) {
  146. return;
  147. }
  148. final List<GridFieldContext> newFields = fieldContexts;
  149. for (final indexField in insertedFields) {
  150. final gridField = GridFieldContext(field: indexField.field_1);
  151. if (newFields.length > indexField.index) {
  152. newFields.insert(indexField.index, gridField);
  153. } else {
  154. newFields.add(gridField);
  155. }
  156. }
  157. _fieldNotifier?.fieldContexts = newFields;
  158. }
  159. void _updateFields(List<FieldPB> updatedFields) {
  160. if (updatedFields.isEmpty) {
  161. return;
  162. }
  163. final List<GridFieldContext> newFields = fieldContexts;
  164. for (final updatedField in updatedFields) {
  165. final index =
  166. newFields.indexWhere((field) => field.id == updatedField.id);
  167. if (index != -1) {
  168. newFields.removeAt(index);
  169. final gridField = GridFieldContext(field: updatedField);
  170. newFields.insert(index, gridField);
  171. }
  172. }
  173. _fieldNotifier?.fieldContexts = newFields;
  174. }
  175. }
  176. class GridRowFieldNotifierImpl extends IGridRowFieldNotifier {
  177. final GridFieldController _cache;
  178. OnChangeset? _onChangesetFn;
  179. OnReceiveFields? _onFieldFn;
  180. GridRowFieldNotifierImpl(GridFieldController cache) : _cache = cache;
  181. @override
  182. UnmodifiableListView<GridFieldContext> get fields =>
  183. UnmodifiableListView(_cache.fieldContexts);
  184. @override
  185. void onRowFieldsChanged(VoidCallback callback) {
  186. _onFieldFn = (_) => callback();
  187. _cache.addListener(onFields: _onFieldFn);
  188. }
  189. @override
  190. void onRowFieldChanged(void Function(FieldPB) callback) {
  191. _onChangesetFn = (FieldChangesetPB changeset) {
  192. for (final updatedField in changeset.updatedFields) {
  193. callback(updatedField);
  194. }
  195. };
  196. _cache.addListener(onChangeset: _onChangesetFn);
  197. }
  198. @override
  199. void onRowDispose() {
  200. if (_onFieldFn != null) {
  201. _cache.removeListener(onFieldsListener: _onFieldFn!);
  202. _onFieldFn = null;
  203. }
  204. if (_onChangesetFn != null) {
  205. _cache.removeListener(onChangesetListener: _onChangesetFn!);
  206. _onChangesetFn = null;
  207. }
  208. }
  209. }
  210. class GridFieldContext {
  211. final FieldPB _field;
  212. bool _isGroupField = false;
  213. String get id => _field.id;
  214. FieldType get fieldType => _field.fieldType;
  215. bool get visibility => _field.visibility;
  216. double get width => _field.width.toDouble();
  217. bool get isPrimary => _field.isPrimary;
  218. String get name => _field.name;
  219. FieldPB get field => _field;
  220. bool get isGroupField => _isGroupField;
  221. GridFieldContext({required FieldPB field}) : _field = field;
  222. }