2022-05-14 18:21:32 +08:00
|
|
|
import 'dart:collection';
|
|
|
|
|
2022-08-09 11:59:22 +08:00
|
|
|
import 'package:app_flowy/plugins/grid/application/field/grid_listener.dart';
|
2022-04-10 16:29:45 +08:00
|
|
|
import 'package:dartz/dartz.dart';
|
2022-03-03 10:51:52 +08:00
|
|
|
import 'package:flowy_sdk/dispatch/dispatch.dart';
|
2022-04-16 22:26:34 +08:00
|
|
|
import 'package:flowy_sdk/log.dart';
|
2022-03-03 10:51:52 +08:00
|
|
|
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
2022-07-04 15:00:54 +08:00
|
|
|
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
|
2022-07-01 20:32:11 +08:00
|
|
|
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.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:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
|
2022-04-14 13:29:42 +08:00
|
|
|
import 'package:flutter/foundation.dart';
|
2022-04-19 21:52:46 +08:00
|
|
|
import 'row/row_service.dart';
|
|
|
|
|
2022-03-03 10:51:52 +08:00
|
|
|
class GridService {
|
2022-04-10 16:29:45 +08:00
|
|
|
final String gridId;
|
|
|
|
GridService({
|
|
|
|
required this.gridId,
|
|
|
|
});
|
|
|
|
|
2022-07-17 13:38:53 +08:00
|
|
|
Future<Either<GridPB, FlowyError>> loadGrid() async {
|
2022-07-19 14:11:29 +08:00
|
|
|
await FolderEventSetLatestView(ViewIdPB(value: gridId)).send();
|
2022-03-06 21:22:42 +08:00
|
|
|
|
2022-07-17 13:38:53 +08:00
|
|
|
final payload = GridIdPB(value: gridId);
|
2022-06-27 20:53:47 +08:00
|
|
|
return GridEventGetGrid(payload).send();
|
2022-03-03 10:51:52 +08:00
|
|
|
}
|
|
|
|
|
2022-08-09 10:35:27 +08:00
|
|
|
Future<Either<GridRowPB, FlowyError>> createRow(
|
|
|
|
{Option<String>? startRowId}) {
|
2022-07-17 14:13:12 +08:00
|
|
|
CreateRowPayloadPB payload = CreateRowPayloadPB.create()..gridId = gridId;
|
2022-03-20 17:17:06 +08:00
|
|
|
startRowId?.fold(() => null, (id) => payload.startRowId = id);
|
2022-03-16 16:10:35 +08:00
|
|
|
return GridEventCreateRow(payload).send();
|
2022-03-03 22:17:07 +08:00
|
|
|
}
|
|
|
|
|
2022-08-09 10:35:27 +08:00
|
|
|
Future<Either<RepeatedGridFieldPB, FlowyError>> getFields(
|
|
|
|
{required List<GridFieldIdPB> fieldIds}) {
|
2022-07-17 14:13:12 +08:00
|
|
|
final payload = QueryFieldPayloadPB.create()
|
2022-03-05 17:52:25 +08:00
|
|
|
..gridId = gridId
|
2022-07-17 14:13:12 +08:00
|
|
|
..fieldIds = RepeatedGridFieldIdPB(items: fieldIds);
|
2022-03-05 17:52:25 +08:00
|
|
|
return GridEventGetFields(payload).send();
|
2022-03-03 10:51:52 +08:00
|
|
|
}
|
2022-04-10 16:29:45 +08:00
|
|
|
|
|
|
|
Future<Either<Unit, FlowyError>> closeGrid() {
|
2022-07-19 14:11:29 +08:00
|
|
|
final request = ViewIdPB(value: gridId);
|
2022-04-10 16:29:45 +08:00
|
|
|
return FolderEventCloseView(request).send();
|
|
|
|
}
|
2022-03-03 10:51:52 +08:00
|
|
|
}
|
2022-04-14 13:29:42 +08:00
|
|
|
|
|
|
|
class FieldsNotifier extends ChangeNotifier {
|
2022-07-17 14:13:12 +08:00
|
|
|
List<GridFieldPB> _fields = [];
|
2022-04-14 13:29:42 +08:00
|
|
|
|
2022-07-17 14:13:12 +08:00
|
|
|
set fields(List<GridFieldPB> fields) {
|
2022-04-14 13:29:42 +08:00
|
|
|
_fields = fields;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2022-07-17 14:13:12 +08:00
|
|
|
List<GridFieldPB> get fields => _fields;
|
2022-04-14 13:29:42 +08:00
|
|
|
}
|
|
|
|
|
2022-07-17 14:13:12 +08:00
|
|
|
typedef FieldChangesetCallback = void Function(GridFieldChangesetPB);
|
|
|
|
typedef FieldsCallback = void Function(List<GridFieldPB>);
|
2022-04-25 22:03:10 +08:00
|
|
|
|
2022-04-14 13:29:42 +08:00
|
|
|
class GridFieldCache {
|
2022-04-16 22:26:34 +08:00
|
|
|
final String gridId;
|
2022-07-16 15:38:38 +08:00
|
|
|
final GridFieldsListener _fieldListener;
|
2022-05-19 10:53:11 +08:00
|
|
|
FieldsNotifier? _fieldNotifier = FieldsNotifier();
|
2022-07-03 15:53:28 +08:00
|
|
|
final Map<FieldsCallback, VoidCallback> _fieldsCallbackMap = {};
|
2022-08-09 10:35:27 +08:00
|
|
|
final Map<FieldChangesetCallback, FieldChangesetCallback>
|
|
|
|
_changesetCallbackMap = {};
|
2022-04-25 22:03:10 +08:00
|
|
|
|
2022-08-09 10:35:27 +08:00
|
|
|
GridFieldCache({required this.gridId})
|
|
|
|
: _fieldListener = GridFieldsListener(gridId: gridId) {
|
2022-04-25 08:13:09 +08:00
|
|
|
_fieldListener.start(onFieldsChanged: (result) {
|
2022-04-16 22:26:34 +08:00
|
|
|
result.fold(
|
|
|
|
(changeset) {
|
|
|
|
_deleteFields(changeset.deletedFields);
|
|
|
|
_insertFields(changeset.insertedFields);
|
|
|
|
_updateFields(changeset.updatedFields);
|
2022-07-03 15:53:28 +08:00
|
|
|
for (final listener in _changesetCallbackMap.values) {
|
2022-04-25 22:03:10 +08:00
|
|
|
listener(changeset);
|
|
|
|
}
|
2022-04-16 22:26:34 +08:00
|
|
|
},
|
|
|
|
(err) => Log.error(err),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2022-04-14 13:29:42 +08:00
|
|
|
|
2022-04-16 22:26:34 +08:00
|
|
|
Future<void> dispose() async {
|
|
|
|
await _fieldListener.stop();
|
2022-05-19 10:53:11 +08:00
|
|
|
_fieldNotifier?.dispose();
|
|
|
|
_fieldNotifier = null;
|
2022-04-14 13:29:42 +08:00
|
|
|
}
|
|
|
|
|
2022-08-09 10:35:27 +08:00
|
|
|
UnmodifiableListView<GridFieldPB> get unmodifiableFields =>
|
|
|
|
UnmodifiableListView(_fieldNotifier?.fields ?? []);
|
2022-04-14 13:29:42 +08:00
|
|
|
|
2022-07-17 14:13:12 +08:00
|
|
|
List<GridFieldPB> get fields => [..._fieldNotifier?.fields ?? []];
|
2022-04-14 13:29:42 +08:00
|
|
|
|
2022-07-17 14:13:12 +08:00
|
|
|
set fields(List<GridFieldPB> fields) {
|
2022-05-19 10:53:11 +08:00
|
|
|
_fieldNotifier?.fields = [...fields];
|
2022-04-14 13:29:42 +08:00
|
|
|
}
|
|
|
|
|
2022-07-03 15:53:28 +08:00
|
|
|
void addListener({
|
|
|
|
FieldsCallback? onFields,
|
|
|
|
FieldChangesetCallback? onChangeset,
|
|
|
|
bool Function()? listenWhen,
|
|
|
|
}) {
|
|
|
|
if (onChangeset != null) {
|
|
|
|
fn(c) {
|
|
|
|
if (listenWhen != null && listenWhen() == false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
onChangeset(c);
|
2022-04-16 22:26:34 +08:00
|
|
|
}
|
|
|
|
|
2022-07-03 15:53:28 +08:00
|
|
|
_changesetCallbackMap[onChangeset] = fn;
|
2022-04-17 14:50:29 +08:00
|
|
|
}
|
|
|
|
|
2022-07-03 15:53:28 +08:00
|
|
|
if (onFields != null) {
|
|
|
|
fn() {
|
|
|
|
if (listenWhen != null && listenWhen() == false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
onFields(fields);
|
|
|
|
}
|
2022-04-17 14:50:29 +08:00
|
|
|
|
2022-07-03 15:53:28 +08:00
|
|
|
_fieldsCallbackMap[onFields] = fn;
|
|
|
|
_fieldNotifier?.addListener(fn);
|
|
|
|
}
|
2022-04-14 21:16:29 +08:00
|
|
|
}
|
|
|
|
|
2022-07-03 15:53:28 +08:00
|
|
|
void removeListener({
|
|
|
|
FieldsCallback? onFieldsListener,
|
2022-08-09 11:59:22 +08:00
|
|
|
FieldChangesetCallback? onChangesetListener,
|
2022-07-03 15:53:28 +08:00
|
|
|
}) {
|
|
|
|
if (onFieldsListener != null) {
|
|
|
|
final fn = _fieldsCallbackMap.remove(onFieldsListener);
|
|
|
|
if (fn != null) {
|
|
|
|
_fieldNotifier?.removeListener(fn);
|
|
|
|
}
|
|
|
|
}
|
2022-04-25 22:03:10 +08:00
|
|
|
|
2022-08-09 11:59:22 +08:00
|
|
|
if (onChangesetListener != null) {
|
|
|
|
_changesetCallbackMap.remove(onChangesetListener);
|
2022-04-25 22:03:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-17 14:13:12 +08:00
|
|
|
void _deleteFields(List<GridFieldIdPB> deletedFields) {
|
2022-04-14 13:29:42 +08:00
|
|
|
if (deletedFields.isEmpty) {
|
|
|
|
return;
|
|
|
|
}
|
2022-07-17 14:13:12 +08:00
|
|
|
final List<GridFieldPB> newFields = fields;
|
|
|
|
final Map<String, GridFieldIdPB> deletedFieldMap = {
|
2022-04-14 13:29:42 +08:00
|
|
|
for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder
|
|
|
|
};
|
|
|
|
|
2022-05-19 10:53:11 +08:00
|
|
|
newFields.retainWhere((field) => (deletedFieldMap[field.id] == null));
|
|
|
|
_fieldNotifier?.fields = newFields;
|
2022-04-14 13:29:42 +08:00
|
|
|
}
|
|
|
|
|
2022-07-17 14:13:12 +08:00
|
|
|
void _insertFields(List<IndexFieldPB> insertedFields) {
|
2022-04-14 13:29:42 +08:00
|
|
|
if (insertedFields.isEmpty) {
|
|
|
|
return;
|
|
|
|
}
|
2022-07-17 14:13:12 +08:00
|
|
|
final List<GridFieldPB> newFields = fields;
|
2022-04-14 13:29:42 +08:00
|
|
|
for (final indexField in insertedFields) {
|
2022-05-19 10:53:11 +08:00
|
|
|
if (newFields.length > indexField.index) {
|
|
|
|
newFields.insert(indexField.index, indexField.field_1);
|
2022-04-14 13:29:42 +08:00
|
|
|
} else {
|
2022-05-19 10:53:11 +08:00
|
|
|
newFields.add(indexField.field_1);
|
2022-04-14 13:29:42 +08:00
|
|
|
}
|
|
|
|
}
|
2022-05-19 10:53:11 +08:00
|
|
|
_fieldNotifier?.fields = newFields;
|
2022-04-14 13:29:42 +08:00
|
|
|
}
|
|
|
|
|
2022-07-17 14:13:12 +08:00
|
|
|
void _updateFields(List<GridFieldPB> updatedFields) {
|
2022-04-14 13:29:42 +08:00
|
|
|
if (updatedFields.isEmpty) {
|
|
|
|
return;
|
|
|
|
}
|
2022-07-17 14:13:12 +08:00
|
|
|
final List<GridFieldPB> newFields = fields;
|
2022-04-14 13:29:42 +08:00
|
|
|
for (final updatedField in updatedFields) {
|
2022-08-09 10:35:27 +08:00
|
|
|
final index =
|
|
|
|
newFields.indexWhere((field) => field.id == updatedField.id);
|
2022-04-14 13:29:42 +08:00
|
|
|
if (index != -1) {
|
2022-05-19 10:53:11 +08:00
|
|
|
newFields.removeAt(index);
|
|
|
|
newFields.insert(index, updatedField);
|
2022-04-14 13:29:42 +08:00
|
|
|
}
|
|
|
|
}
|
2022-05-19 10:53:11 +08:00
|
|
|
_fieldNotifier?.fields = newFields;
|
2022-04-14 13:29:42 +08:00
|
|
|
}
|
|
|
|
}
|
2022-04-19 21:52:46 +08:00
|
|
|
|
2022-07-16 11:53:39 +08:00
|
|
|
class GridRowCacheFieldNotifierImpl extends GridRowCacheFieldNotifier {
|
2022-04-19 21:52:46 +08:00
|
|
|
final GridFieldCache _cache;
|
2022-07-03 15:53:28 +08:00
|
|
|
FieldChangesetCallback? _onChangesetFn;
|
|
|
|
FieldsCallback? _onFieldFn;
|
2022-07-16 11:53:39 +08:00
|
|
|
GridRowCacheFieldNotifierImpl(GridFieldCache cache) : _cache = cache;
|
2022-04-19 21:52:46 +08:00
|
|
|
|
|
|
|
@override
|
2022-07-17 14:13:12 +08:00
|
|
|
UnmodifiableListView<GridFieldPB> get fields => _cache.unmodifiableFields;
|
2022-04-19 21:52:46 +08:00
|
|
|
|
|
|
|
@override
|
2022-07-03 15:53:28 +08:00
|
|
|
void onFieldsChanged(VoidCallback callback) {
|
|
|
|
_onFieldFn = (_) => callback();
|
|
|
|
_cache.addListener(onFields: _onFieldFn);
|
2022-04-19 21:52:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
2022-07-17 14:13:12 +08:00
|
|
|
void onFieldChanged(void Function(GridFieldPB) callback) {
|
|
|
|
_onChangesetFn = (GridFieldChangesetPB changeset) {
|
2022-04-25 22:03:10 +08:00
|
|
|
for (final updatedField in changeset.updatedFields) {
|
2022-07-03 15:53:28 +08:00
|
|
|
callback(updatedField);
|
2022-04-19 21:52:46 +08:00
|
|
|
}
|
2022-07-03 15:53:28 +08:00
|
|
|
};
|
2022-04-25 22:03:10 +08:00
|
|
|
|
2022-07-03 15:53:28 +08:00
|
|
|
_cache.addListener(onChangeset: _onChangesetFn);
|
2022-04-25 22:03:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void dispose() {
|
2022-07-03 15:53:28 +08:00
|
|
|
if (_onFieldFn != null) {
|
|
|
|
_cache.removeListener(onFieldsListener: _onFieldFn!);
|
|
|
|
_onFieldFn = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_onChangesetFn != null) {
|
2022-08-09 11:59:22 +08:00
|
|
|
_cache.removeListener(onChangesetListener: _onChangesetFn!);
|
2022-07-03 15:53:28 +08:00
|
|
|
_onChangesetFn = null;
|
2022-04-25 22:03:10 +08:00
|
|
|
}
|
2022-04-19 21:52:46 +08:00
|
|
|
}
|
|
|
|
}
|