import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; part 'grid_service.freezed.dart'; class GridService { final String gridId; GridService({ required this.gridId, }); Future> loadGrid() async { await FolderEventSetLatestView(ViewId(value: gridId)).send(); final payload = GridId(value: gridId); return GridEventGetGridData(payload).send(); } Future> createRow({Option? startRowId}) { CreateRowPayload payload = CreateRowPayload.create()..gridId = gridId; startRowId?.fold(() => null, (id) => payload.startRowId = id); return GridEventCreateRow(payload).send(); } Future> getFields({required List fieldOrders}) { final payload = QueryFieldPayload.create() ..gridId = gridId ..fieldOrders = RepeatedFieldOrder(items: fieldOrders); return GridEventGetFields(payload).send(); } Future> closeGrid() { final request = ViewId(value: gridId); return FolderEventCloseView(request).send(); } } class FieldsNotifier extends ChangeNotifier { List _fields = []; set fields(List fields) { _fields = fields; notifyListeners(); } List get fields => _fields; } class GridFieldCache { final FieldsNotifier _fieldNotifier = FieldsNotifier(); GridFieldCache(); void applyChangeset(GridFieldChangeset changeset) { _removeFields(changeset.deletedFields); _insertFields(changeset.insertedFields); _updateFields(changeset.updatedFields); } List get fields => _fieldNotifier.fields; set fields(List fields) { _fieldNotifier.fields = fields; } set onFieldChanged(void Function(List) onChanged) { _fieldNotifier.addListener(() => onChanged(fields)); } void addListener(void Function(List) onFieldChanged) { _fieldNotifier.addListener(() => onFieldChanged(fields)); } void _removeFields(List deletedFields) { if (deletedFields.isEmpty) { return; } final List fields = List.from(_fieldNotifier.fields); final Map deletedFieldMap = { for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder }; fields.retainWhere((field) => (deletedFieldMap[field.id] == null)); _fieldNotifier.fields = fields; } void _insertFields(List insertedFields) { if (insertedFields.isEmpty) { return; } final List fields = List.from(_fieldNotifier.fields); for (final indexField in insertedFields) { if (fields.length > indexField.index) { fields.removeAt(indexField.index); fields.insert(indexField.index, indexField.field_1); } else { fields.add(indexField.field_1); } } _fieldNotifier.fields = fields; } void _updateFields(List updatedFields) { if (updatedFields.isEmpty) { return; } final List fields = List.from(_fieldNotifier.fields); for (final updatedField in updatedFields) { final index = fields.indexWhere((field) => field.id == updatedField.id); if (index != -1) { fields.removeAt(index); fields.insert(index, updatedField); } } _fieldNotifier.fields = fields; } } class GridRowCache { final String gridId; List _fields = []; List _rows = []; GridRowCache({required this.gridId}); List get rows => _rows; void updateWithBlock(List blocks) { _rows = blocks.expand((block) => block.rowOrders).map((rowOrder) { return RowData.fromBlockRow(gridId, rowOrder, _fields); }).toList(); } void updateFields(List fields) { if (fields.isEmpty) { return; } _fields = fields; _rows = _rows.map((row) => row.copyWith(fields: fields)).toList(); } Option deleteRows(List deletedRows) { if (deletedRows.isEmpty) { return none(); } final List newRows = []; final List> deletedIndex = []; final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; _rows.asMap().forEach((index, value) { if (deletedRowMap[value.rowId] == null) { newRows.add(value); } else { deletedIndex.add(Tuple2(index, value)); } }); _rows = newRows; return Some(GridListState.delete(deletedIndex)); } Option insertRows(List createdRows) { if (createdRows.isEmpty) { return none(); } List insertIndexs = []; for (final newRow in createdRows) { if (newRow.hasIndex()) { insertIndexs.add(newRow.index); _rows.insert(newRow.index, _toRowData(newRow.rowOrder)); } else { insertIndexs.add(_rows.length); _rows.add(_toRowData(newRow.rowOrder)); } } return Some(GridListState.insert(insertIndexs)); } void updateRows(List updatedRows) { if (updatedRows.isEmpty) { return; } final List updatedIndexs = []; for (final updatedRow in updatedRows) { final index = _rows.indexWhere((row) => row.rowId == updatedRow.rowId); if (index != -1) { _rows.removeAt(index); _rows.insert(index, _toRowData(updatedRow)); updatedIndexs.add(index); } } } RowData _toRowData(RowOrder rowOrder) { return RowData.fromBlockRow(gridId, rowOrder, _fields); } } @freezed class GridListState with _$GridListState { const factory GridListState.insert(List indexs) = _Insert; const factory GridListState.delete(List> indexs) = _Delete; const factory GridListState.initial() = InitialListState; }