| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 | import 'package:dartz/dartz.dart';import 'package:flowy_infra/notifier.dart';import 'package:flowy_sdk/dispatch/dispatch.dart';import 'package:flowy_sdk/log.dart';import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';import 'package:flutter/foundation.dart';import 'package:freezed_annotation/freezed_annotation.dart';import 'package:protobuf/protobuf.dart';part 'field_service.freezed.dart';/// FieldService consists of lots of event functions. We define the events in the backend(Rust),/// you can find the corresponding event implementation in event_map.rs of the corresponding crate.////// You could check out the rust-lib/flowy-grid/event_map.rs for more information.class FieldService {  final String gridId;  final String fieldId;  FieldService({required this.gridId, required this.fieldId});  Future<Either<Unit, FlowyError>> moveField(int fromIndex, int toIndex) {    final payload = MoveItemPayloadPB.create()      ..gridId = gridId      ..itemId = fieldId      ..ty = MoveItemTypePB.MoveField      ..fromIndex = fromIndex      ..toIndex = toIndex;    return GridEventMoveItem(payload).send();  }  Future<Either<Unit, FlowyError>> updateField({    String? name,    FieldType? fieldType,    bool? frozen,    bool? visibility,    double? width,    List<int>? typeOptionData,  }) {    var payload = FieldChangesetPayloadPB.create()      ..gridId = gridId      ..fieldId = fieldId;    if (name != null) {      payload.name = name;    }    if (fieldType != null) {      payload.fieldType = fieldType;    }    if (frozen != null) {      payload.frozen = frozen;    }    if (visibility != null) {      payload.visibility = visibility;    }    if (width != null) {      payload.width = width.toInt();    }    if (typeOptionData != null) {      payload.typeOptionData = typeOptionData;    }    return GridEventUpdateField(payload).send();  }  // Create the field if it does not exist. Otherwise, update the field.  static Future<Either<Unit, FlowyError>> insertField({    required String gridId,    required GridFieldPB field,    List<int>? typeOptionData,    String? startFieldId,  }) {    var payload = InsertFieldPayloadPB.create()      ..gridId = gridId      ..field_2 = field      ..typeOptionData = typeOptionData ?? [];    if (startFieldId != null) {      payload.startFieldId = startFieldId;    }    return GridEventInsertField(payload).send();  }  static Future<Either<Unit, FlowyError>> updateFieldTypeOption({    required String gridId,    required String fieldId,    required List<int> typeOptionData,  }) {    var payload = UpdateFieldTypeOptionPayloadPB.create()      ..gridId = gridId      ..fieldId = fieldId      ..typeOptionData = typeOptionData;    return GridEventUpdateFieldTypeOption(payload).send();  }  Future<Either<Unit, FlowyError>> deleteField() {    final payload = DeleteFieldPayloadPB.create()      ..gridId = gridId      ..fieldId = fieldId;    return GridEventDeleteField(payload).send();  }  Future<Either<Unit, FlowyError>> duplicateField() {    final payload = DuplicateFieldPayloadPB.create()      ..gridId = gridId      ..fieldId = fieldId;    return GridEventDuplicateField(payload).send();  }  Future<Either<FieldTypeOptionDataPB, FlowyError>> getFieldTypeOptionData({    required FieldType fieldType,  }) {    final payload = GridFieldTypeOptionIdPB.create()      ..gridId = gridId      ..fieldId = fieldId      ..fieldType = fieldType;    return GridEventGetFieldTypeOption(payload).send().then((result) {      return result.fold(        (data) => left(data),        (err) => right(err),      );    });  }}@freezedclass GridFieldCellContext with _$GridFieldCellContext {  const factory GridFieldCellContext({    required String gridId,    required GridFieldPB field,  }) = _GridFieldCellContext;}abstract class IFieldTypeOptionLoader {  String get gridId;  Future<Either<FieldTypeOptionDataPB, FlowyError>> load();  Future<Either<FieldTypeOptionDataPB, FlowyError>> switchToField(String fieldId, FieldType fieldType) {    final payload = EditFieldPayloadPB.create()      ..gridId = gridId      ..fieldId = fieldId      ..fieldType = fieldType;    return GridEventSwitchToField(payload).send();  }}class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {  @override  final String gridId;  NewFieldTypeOptionLoader({    required this.gridId,  });  @override  Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {    final payload = CreateFieldPayloadPB.create()      ..gridId = gridId      ..fieldType = FieldType.RichText;    return GridEventCreateFieldTypeOption(payload).send();  }}class FieldTypeOptionLoader extends IFieldTypeOptionLoader {  @override  final String gridId;  final GridFieldPB field;  FieldTypeOptionLoader({    required this.gridId,    required this.field,  });  @override  Future<Either<FieldTypeOptionDataPB, FlowyError>> load() {    final payload = GridFieldTypeOptionIdPB.create()      ..gridId = gridId      ..fieldId = field.id      ..fieldType = field.fieldType;    return GridEventGetFieldTypeOption(payload).send();  }}class TypeOptionDataController {  final String gridId;  final IFieldTypeOptionLoader _loader;  late FieldTypeOptionDataPB _data;  final PublishNotifier<GridFieldPB> _fieldNotifier = PublishNotifier();  TypeOptionDataController({    required this.gridId,    required IFieldTypeOptionLoader loader,  }) : _loader = loader;  Future<Either<Unit, FlowyError>> loadData() async {    final result = await _loader.load();    return result.fold(      (data) {        data.freeze();        _data = data;        _fieldNotifier.value = data.field_2;        return left(unit);      },      (err) {        Log.error(err);        return right(err);      },    );  }  GridFieldPB get field => _data.field_2;  set field(GridFieldPB field) {    _updateData(newField: field);  }  List<int> get typeOptionData => _data.typeOptionData;  set fieldName(String name) {    _updateData(newName: name);  }  set typeOptionData(List<int> typeOptionData) {    _updateData(newTypeOptionData: typeOptionData);  }  void _updateData({String? newName, GridFieldPB? newField, List<int>? newTypeOptionData}) {    _data = _data.rebuild((rebuildData) {      if (newName != null) {        rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) {          rebuildField.name = newName;        });      }      if (newField != null) {        rebuildData.field_2 = newField;      }      if (newTypeOptionData != null) {        rebuildData.typeOptionData = newTypeOptionData;      }    });    _fieldNotifier.value = _data.field_2;    FieldService.insertField(      gridId: gridId,      field: field,      typeOptionData: typeOptionData,    );  }  Future<void> switchToField(FieldType newFieldType) {    return _loader.switchToField(field.id, newFieldType).then((result) {      return result.fold(        (fieldTypeOptionData) {          _updateData(            newField: fieldTypeOptionData.field_2,            newTypeOptionData: fieldTypeOptionData.typeOptionData,          );        },        (err) {          Log.error(err);        },      );    });  }  void Function() addFieldListener(void Function(GridFieldPB) callback) {    listener() {      callback(field);    }    _fieldNotifier.addListener(listener);    return listener;  }  void removeFieldListener(void Function() listener) {    _fieldNotifier.removeListener(listener);  }}
 |