field_service.dart 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import 'package:dartz/dartz.dart';
  2. import 'package:flowy_infra/notifier.dart';
  3. import 'package:flowy_sdk/dispatch/dispatch.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-grid/field_entities.pb.dart';
  7. import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
  8. import 'package:flutter/foundation.dart';
  9. import 'package:freezed_annotation/freezed_annotation.dart';
  10. import 'package:protobuf/protobuf.dart';
  11. part 'field_service.freezed.dart';
  12. /// FieldService consists of lots of event functions. We define the events in the backend(Rust),
  13. /// you can find the corresponding event implementation in event_map.rs of the corresponding crate.
  14. ///
  15. /// You could check out the rust-lib/flowy-grid/event_map.rs for more information.
  16. class FieldService {
  17. final String gridId;
  18. final String fieldId;
  19. FieldService({required this.gridId, required this.fieldId});
  20. Future<Either<Unit, FlowyError>> moveField(int fromIndex, int toIndex) {
  21. final payload = MoveItemPayloadPB.create()
  22. ..gridId = gridId
  23. ..itemId = fieldId
  24. ..ty = MoveItemTypePB.MoveField
  25. ..fromIndex = fromIndex
  26. ..toIndex = toIndex;
  27. return GridEventMoveItem(payload).send();
  28. }
  29. Future<Either<Unit, FlowyError>> updateField({
  30. String? name,
  31. FieldType? fieldType,
  32. bool? frozen,
  33. bool? visibility,
  34. double? width,
  35. List<int>? typeOptionData,
  36. }) {
  37. var payload = FieldChangesetPayloadPB.create()
  38. ..gridId = gridId
  39. ..fieldId = fieldId;
  40. if (name != null) {
  41. payload.name = name;
  42. }
  43. if (fieldType != null) {
  44. payload.fieldType = fieldType;
  45. }
  46. if (frozen != null) {
  47. payload.frozen = frozen;
  48. }
  49. if (visibility != null) {
  50. payload.visibility = visibility;
  51. }
  52. if (width != null) {
  53. payload.width = width.toInt();
  54. }
  55. if (typeOptionData != null) {
  56. payload.typeOptionData = typeOptionData;
  57. }
  58. return GridEventUpdateField(payload).send();
  59. }
  60. // Create the field if it does not exist. Otherwise, update the field.
  61. static Future<Either<Unit, FlowyError>> insertField({
  62. required String gridId,
  63. required GridFieldPB field,
  64. List<int>? typeOptionData,
  65. String? startFieldId,
  66. }) {
  67. var payload = InsertFieldPayloadPB.create()
  68. ..gridId = gridId
  69. ..field_2 = field
  70. ..typeOptionData = typeOptionData ?? [];
  71. if (startFieldId != null) {
  72. payload.startFieldId = startFieldId;
  73. }
  74. return GridEventInsertField(payload).send();
  75. }
  76. static Future<Either<Unit, FlowyError>> updateFieldTypeOption({
  77. required String gridId,
  78. required String fieldId,
  79. required List<int> typeOptionData,
  80. }) {
  81. var payload = UpdateFieldTypeOptionPayloadPB.create()
  82. ..gridId = gridId
  83. ..fieldId = fieldId
  84. ..typeOptionData = typeOptionData;
  85. return GridEventUpdateFieldTypeOption(payload).send();
  86. }
  87. Future<Either<Unit, FlowyError>> deleteField() {
  88. final payload = DeleteFieldPayloadPB.create()
  89. ..gridId = gridId
  90. ..fieldId = fieldId;
  91. return GridEventDeleteField(payload).send();
  92. }
  93. Future<Either<Unit, FlowyError>> duplicateField() {
  94. final payload = DuplicateFieldPayloadPB.create()
  95. ..gridId = gridId
  96. ..fieldId = fieldId;
  97. return GridEventDuplicateField(payload).send();
  98. }
  99. Future<Either<FieldTypeOptionDataPB, FlowyError>> getFieldTypeOptionData({
  100. required FieldType fieldType,
  101. }) {
  102. final payload = GridFieldTypeOptionIdPB.create()
  103. ..gridId = gridId
  104. ..fieldId = fieldId
  105. ..fieldType = fieldType;
  106. return GridEventGetFieldTypeOption(payload).send().then((result) {
  107. return result.fold(
  108. (data) => left(data),
  109. (err) => right(err),
  110. );
  111. });
  112. }
  113. }
  114. @freezed
  115. class GridFieldCellContext with _$GridFieldCellContext {
  116. const factory GridFieldCellContext({
  117. required String gridId,
  118. required GridFieldPB field,
  119. }) = _GridFieldCellContext;
  120. }
  121. abstract class IFieldTypeOptionLoader {
  122. String get gridId;
  123. Future<Either<FieldTypeOptionDataPB, FlowyError>> load();
  124. Future<Either<FieldTypeOptionDataPB, FlowyError>> switchToField(
  125. String fieldId, FieldType fieldType) {
  126. final payload = EditFieldPayloadPB.create()
  127. ..gridId = gridId
  128. ..fieldId = fieldId
  129. ..fieldType = fieldType;
  130. return GridEventSwitchToField(payload).send();
  131. }
  132. }
  133. class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {
  134. @override
  135. final String gridId;
  136. NewFieldTypeOptionLoader({
  137. required this.gridId,
  138. });
  139. @override
  140. Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
  141. final payload = CreateFieldPayloadPB.create()
  142. ..gridId = gridId
  143. ..fieldType = FieldType.RichText;
  144. return GridEventCreateFieldTypeOption(payload).send();
  145. }
  146. }
  147. class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
  148. @override
  149. final String gridId;
  150. final GridFieldPB field;
  151. FieldTypeOptionLoader({
  152. required this.gridId,
  153. required this.field,
  154. });
  155. @override
  156. Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {
  157. final payload = GridFieldTypeOptionIdPB.create()
  158. ..gridId = gridId
  159. ..fieldId = field.id
  160. ..fieldType = field.fieldType;
  161. return GridEventGetFieldTypeOption(payload).send();
  162. }
  163. }
  164. class TypeOptionDataController {
  165. final String gridId;
  166. final IFieldTypeOptionLoader _loader;
  167. late FieldTypeOptionDataPB _data;
  168. final PublishNotifier<GridFieldPB> _fieldNotifier = PublishNotifier();
  169. TypeOptionDataController({
  170. required this.gridId,
  171. required IFieldTypeOptionLoader loader,
  172. }) : _loader = loader;
  173. Future<Either<Unit, FlowyError>> loadTypeOptionData() async {
  174. final result = await _loader.load();
  175. return result.fold(
  176. (data) {
  177. data.freeze();
  178. _data = data;
  179. _fieldNotifier.value = data.field_2;
  180. return left(unit);
  181. },
  182. (err) {
  183. Log.error(err);
  184. return right(err);
  185. },
  186. );
  187. }
  188. GridFieldPB get field => _data.field_2;
  189. set field(GridFieldPB field) {
  190. _updateData(newField: field);
  191. }
  192. List<int> get typeOptionData => _data.typeOptionData;
  193. set fieldName(String name) {
  194. _updateData(newName: name);
  195. }
  196. set typeOptionData(List<int> typeOptionData) {
  197. _updateData(newTypeOptionData: typeOptionData);
  198. }
  199. void _updateData(
  200. {String? newName, GridFieldPB? newField, List<int>? newTypeOptionData}) {
  201. _data = _data.rebuild((rebuildData) {
  202. if (newName != null) {
  203. rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {
  204. rebuildField.name = newName;
  205. });
  206. }
  207. if (newField != null) {
  208. rebuildData.field_2 = newField;
  209. }
  210. if (newTypeOptionData != null) {
  211. rebuildData.typeOptionData = newTypeOptionData;
  212. }
  213. });
  214. _fieldNotifier.value = _data.field_2;
  215. FieldService.insertField(
  216. gridId: gridId,
  217. field: field,
  218. typeOptionData: typeOptionData,
  219. );
  220. }
  221. Future<void> switchToField(FieldType newFieldType) {
  222. return _loader.switchToField(field.id, newFieldType).then((result) {
  223. return result.fold(
  224. (fieldTypeOptionData) {
  225. _updateData(
  226. newField: fieldTypeOptionData.field_2,
  227. newTypeOptionData: fieldTypeOptionData.typeOptionData,
  228. );
  229. },
  230. (err) {
  231. Log.error(err);
  232. },
  233. );
  234. });
  235. }
  236. void Function() addFieldListener(void Function(GridFieldPB) callback) {
  237. listener() {
  238. callback(field);
  239. }
  240. _fieldNotifier.addListener(listener);
  241. return listener;
  242. }
  243. void removeFieldListener(void Function() listener) {
  244. _fieldNotifier.removeListener(listener);
  245. }
  246. }