diff --git a/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart new file mode 100644 index 0000000000..24ecee521c --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart @@ -0,0 +1,90 @@ +import 'dart:async'; +import 'dart:collection'; +import 'dart:typed_data'; + +import 'package:app_flowy/core/notification_helper.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flowy_infra/notifier.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; + +class GridBlockCache { + final String gridId; + void Function(GridBlockUpdateNotifierValue)? _onBlockChanged; + + final LinkedHashMap _listeners = LinkedHashMap(); + GridBlockCache({required this.gridId}); + + void start(void Function(GridBlockUpdateNotifierValue) onBlockChanged) { + _onBlockChanged = onBlockChanged; + for (final listener in _listeners.values) { + listener.start(onBlockChanged); + } + } + + Future dispose() async { + for (final listener in _listeners.values) { + await listener.stop(); + } + } + + void addBlockListener(String blockId) { + if (_onBlockChanged == null) { + Log.error("Should call start() first"); + return; + } + if (_listeners.containsKey(blockId)) { + Log.error("Duplicate block listener"); + return; + } + + final listener = _GridBlockListener(blockId: blockId); + listener.start(_onBlockChanged!); + _listeners[blockId] = listener; + } +} + +typedef GridBlockUpdateNotifierValue = Either, FlowyError>; + +class _GridBlockListener { + final String blockId; + PublishNotifier? _rowsUpdateNotifier = PublishNotifier(); + GridNotificationListener? _listener; + + _GridBlockListener({required this.blockId}); + + void start(void Function(GridBlockUpdateNotifierValue) onBlockChanged) { + if (_listener != null) { + _listener?.stop(); + } + + _listener = GridNotificationListener( + objectId: blockId, + handler: _handler, + ); + + _rowsUpdateNotifier?.addPublishListener(onBlockChanged); + } + + void _handler(GridNotification ty, Either result) { + switch (ty) { + case GridNotification.DidUpdateGridRow: + result.fold( + (payload) => _rowsUpdateNotifier?.value = left([GridRowsChangeset.fromBuffer(payload)]), + (error) => _rowsUpdateNotifier?.value = right(error), + ); + break; + + default: + break; + } + } + + Future stop() async { + await _listener?.stop(); + _rowsUpdateNotifier?.dispose(); + _rowsUpdateNotifier = null; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart b/frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart new file mode 100644 index 0000000000..e69de29bb2 diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_cache.dart similarity index 77% rename from frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_cache.dart index 5e09573506..fb7ce5734a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_cache.dart @@ -2,21 +2,21 @@ part of 'cell_service.dart'; typedef GridCellMap = LinkedHashMap; -class GridCellCacheData { - GridCellCacheKey key; +class _GridCellCacheObject { + _GridCellCacheKey key; dynamic object; - GridCellCacheData({ + _GridCellCacheObject({ required this.key, required this.object, }); } -class GridCellCacheKey { +class _GridCellCacheKey { final String fieldId; - final String objectId; - GridCellCacheKey({ + final String rowId; + _GridCellCacheKey({ required this.fieldId, - required this.objectId, + required this.rowId, }); } @@ -51,46 +51,46 @@ class GridCellCache { }); } - void addFieldListener(GridCellCacheKey cacheKey, VoidCallback onFieldChanged) { + void addFieldListener(_GridCellCacheKey cacheKey, VoidCallback onFieldChanged) { var map = _fieldListenerByFieldId[cacheKey.fieldId]; if (map == null) { _fieldListenerByFieldId[cacheKey.fieldId] = {}; map = _fieldListenerByFieldId[cacheKey.fieldId]; - map![cacheKey.objectId] = [onFieldChanged]; + map![cacheKey.rowId] = [onFieldChanged]; } else { - var objects = map[cacheKey.objectId]; + var objects = map[cacheKey.rowId]; if (objects == null) { - map[cacheKey.objectId] = [onFieldChanged]; + map[cacheKey.rowId] = [onFieldChanged]; } else { objects.add(onFieldChanged); } } } - void removeFieldListener(GridCellCacheKey cacheKey, VoidCallback fn) { - var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.objectId]; + void removeFieldListener(_GridCellCacheKey cacheKey, VoidCallback fn) { + var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId]; final index = callbacks?.indexWhere((callback) => callback == fn); if (index != null && index != -1) { callbacks?.removeAt(index); } } - void insert(T item) { + void insert(T item) { var map = _cellDataByFieldId[item.key.fieldId]; if (map == null) { _cellDataByFieldId[item.key.fieldId] = {}; map = _cellDataByFieldId[item.key.fieldId]; } - map![item.key.objectId] = item.object; + map![item.key.rowId] = item.object; } - T? get(GridCellCacheKey key) { + T? get(_GridCellCacheKey key) { final map = _cellDataByFieldId[key.fieldId]; if (map == null) { return null; } else { - final object = map[key.objectId]; + final object = map[key.rowId]; if (object is T) { return object; } else { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart similarity index 100% rename from frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart similarity index 100% rename from frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart index 9283c0d22b..d1b8ad296a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart @@ -19,10 +19,10 @@ import 'package:app_flowy/workspace/application/grid/cell/select_option_service. import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'dart:convert' show utf8; part 'cell_service.freezed.dart'; -part 'data_loader.dart'; +part 'cell_data_loader.dart'; part 'context_builder.dart'; -part 'data_cache.dart'; -part 'data_persistence.dart'; +part 'cell_data_cache.dart'; +part 'cell_data_persistence.dart'; // key: rowId diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart index 3041c563d9..6b97bc1456 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart @@ -100,7 +100,7 @@ class GridCellContextBuilder { class _GridCellContext extends Equatable { final GridCell gridCell; final GridCellCache cellCache; - final GridCellCacheKey _cacheKey; + final _GridCellCacheKey _cacheKey; final IGridCellDataLoader cellDataLoader; final _GridCellDataPersistence cellDataPersistence; final FieldService _fieldService; @@ -118,7 +118,7 @@ class _GridCellContext extends Equatable { required this.cellDataLoader, required this.cellDataPersistence, }) : _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), - _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id); + _cacheKey = _GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id); _GridCellContext clone() { return _GridCellContext( @@ -213,7 +213,7 @@ class _GridCellContext extends Equatable { _loadDataOperation = Timer(const Duration(milliseconds: 10), () { cellDataLoader.loadData().then((data) { _cellDataNotifier?.value = data; - cellCache.insert(GridCellCacheData(key: _cacheKey, object: data)); + cellCache.insert(_GridCellCacheObject(key: _cacheKey, object: data)); }); }); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart index 16b4beb041..bc61e5828a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -1,11 +1,13 @@ import 'dart:async'; import 'package:dartz/dartz.dart'; import 'package:equatable/equatable.dart'; +import 'package:flowy_sdk/log.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/protobuf.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'block/block_listener.dart'; import 'cell/cell_service/cell_service.dart'; import 'grid_service.dart'; import 'row/row_service.dart'; @@ -19,9 +21,12 @@ class GridBloc extends Bloc { late final GridRowCache rowCache; late final GridCellCache cellCache; + final GridBlockCache blockCache; + GridBloc({required View view}) : _gridService = GridService(gridId: view.id), fieldCache = GridFieldCache(gridId: view.id), + blockCache = GridBlockCache(gridId: view.id), super(GridState.initial(view.id)) { rowCache = GridRowCache( gridId: view.id, @@ -33,6 +38,13 @@ class GridBloc extends Bloc { fieldDelegate: GridCellCacheDelegateImpl(fieldCache), ); + blockCache.start((result) { + result.fold( + (changesets) => rowCache.applyChangesets(changesets), + (err) => Log.error(err), + ); + }); + on( (event, emit) async { await event.when( @@ -60,6 +72,7 @@ class GridBloc extends Bloc { await cellCache.dispose(); await rowCache.dispose(); await fieldCache.dispose(); + await blockCache.dispose(); return super.close(); } @@ -79,7 +92,15 @@ class GridBloc extends Bloc { final result = await _gridService.loadGrid(); return Future( () => result.fold( - (grid) async => await _loadFields(grid, emit), + (grid) async { + for (final block in grid.blocks) { + blockCache.addBlockListener(block.id); + } + final rowOrders = grid.blocks.expand((block) => block.rowOrders).toList(); + rowCache.initialRows(rowOrders); + + await _loadFields(grid, emit); + }, (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))), ), ); @@ -91,7 +112,6 @@ class GridBloc extends Bloc { () => result.fold( (fields) { fieldCache.fields = fields.items; - rowCache.resetRows(grid.blockOrders); emit(state.copyWith( grid: Some(grid), @@ -143,7 +163,6 @@ class GridLoadingState with _$GridLoadingState { class GridFieldEquatable extends Equatable { final List _fields; - const GridFieldEquatable(List fields) : _fields = fields; @override diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart deleted file mode 100644 index e6c7dc9de7..0000000000 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:dartz/dartz.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; -import 'package:flowy_infra/notifier.dart'; -import 'dart:async'; -import 'dart:typed_data'; -import 'package:app_flowy/core/notification_helper.dart'; - -class GridRowListener { - final String gridId; - PublishNotifier, FlowyError>> rowsUpdateNotifier = PublishNotifier(comparable: null); - GridNotificationListener? _listener; - - GridRowListener({required this.gridId}); - - void start() { - _listener = GridNotificationListener( - objectId: gridId, - handler: _handler, - ); - } - - void _handler(GridNotification ty, Either result) { - switch (ty) { - case GridNotification.DidUpdateGridRow: - result.fold( - (payload) => rowsUpdateNotifier.value = left([GridRowsChangeset.fromBuffer(payload)]), - (error) => rowsUpdateNotifier.value = right(error), - ); - break; - - default: - break; - } - } - - Future stop() async { - await _listener?.stop(); - rowsUpdateNotifier.dispose(); - } -} diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart index 64fa164251..8869645e42 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart @@ -10,7 +10,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:app_flowy/workspace/application/grid/grid_listener.dart'; part 'row_service.freezed.dart'; typedef RowUpdateCallback = void Function(); @@ -24,7 +23,6 @@ abstract class GridRowFieldDelegate { class GridRowCache { final String gridId; final RowsNotifier _rowsNotifier; - final GridRowListener _rowsListener; final GridRowFieldDelegate _fieldDelegate; List get clonedRows => _rowsNotifier.clonedRows; @@ -39,32 +37,23 @@ class GridRowCache { ); }, ), - _rowsListener = GridRowListener(gridId: gridId), _fieldDelegate = fieldDelegate { // fieldDelegate.onFieldChanged(() => _rowsNotifier.fieldDidChange()); - - // listen on the row update - _rowsListener.rowsUpdateNotifier.addPublishListener((result) { - result.fold( - (changesets) { - for (final changeset in changesets) { - _rowsNotifier.deleteRows(changeset.deletedRows); - _rowsNotifier.insertRows(changeset.insertedRows); - _rowsNotifier.updateRows(changeset.updatedRows); - } - }, - (err) => Log.error(err), - ); - }); - _rowsListener.start(); } Future dispose() async { - await _rowsListener.stop(); _rowsNotifier.dispose(); } + void applyChangesets(List changesets) { + for (final changeset in changesets) { + _rowsNotifier.deleteRows(changeset.deletedRows); + _rowsNotifier.insertRows(changeset.insertedRows); + _rowsNotifier.updateRows(changeset.updatedRows); + } + } + void addListener({ void Function(List, GridRowChangeReason)? onChanged, bool Function()? listenWhen, @@ -130,9 +119,8 @@ class GridRowCache { return _makeGridCells(rowId, data); } - void resetRows(List blocks) { - final rowOrders = blocks.expand((block) => block.rowOrders).toList(); - _rowsNotifier.reset(rowOrders); + void initialRows(List rowOrders) { + _rowsNotifier.initialRows(rowOrders); } Future _loadRow(String rowId) async { @@ -142,7 +130,11 @@ class GridRowCache { final result = await GridEventGetRow(payload).send(); result.fold( - (rowData) => _rowsNotifier.rowData = rowData, + (rowData) { + if (rowData.hasRow()) { + _rowsNotifier.rowData = rowData.row; + } + }, (err) => Log.error(err), ); } @@ -173,7 +165,9 @@ class RowsNotifier extends ChangeNotifier { required this.rowBuilder, }); - void reset(List rowOrders) { + List get clonedRows => [..._rows]; + + void initialRows(List rowOrders) { _rowDataMap = HashMap(); final rows = rowOrders.map((rowOrder) => rowBuilder(rowOrder)).toList(); _update(rows, const GridRowChangeReason.initial()); @@ -199,20 +193,20 @@ class RowsNotifier extends ChangeNotifier { _update(newRows, GridRowChangeReason.delete(deletedIndex)); } - void insertRows(List createdRows) { - if (createdRows.isEmpty) { + void insertRows(List insertRows) { + if (insertRows.isEmpty) { return; } InsertedIndexs insertIndexs = []; final List newRows = clonedRows; - for (final createdRow in createdRows) { + for (final insertRow in insertRows) { final insertIndex = InsertedIndex( - index: createdRow.index, - rowId: createdRow.rowOrder.rowId, + index: insertRow.index, + rowId: insertRow.rowOrder.rowId, ); insertIndexs.add(insertIndex); - newRows.insert(createdRow.index, (rowBuilder(createdRow.rowOrder))); + newRows.insert(insertRow.index, (rowBuilder(insertRow.rowOrder))); } _update(newRows, GridRowChangeReason.insert(insertIndexs)); } @@ -281,8 +275,6 @@ class RowsNotifier extends ChangeNotifier { Row? rowDataWithId(String rowId) { return _rowDataMap[rowId]; } - - List get clonedRows => [..._rows]; } class RowService { @@ -310,7 +302,7 @@ class RowService { return GridEventMoveItem(payload).send(); } - Future> getRow() { + Future> getRow() { final payload = RowIdentifierPayload.create() ..gridId = gridId ..rowId = rowId; diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index d02b2d59ca..901a3197ea 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -48,12 +48,7 @@ pub(crate) async fn get_grid_blocks_handler( ) -> DataResult { let params: QueryGridBlocksParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; - let block_ids = params - .block_orders - .into_iter() - .map(|block| block.block_id) - .collect::>(); - let repeated_grid_block = editor.get_blocks(Some(block_ids)).await?; + let repeated_grid_block = editor.get_blocks(Some(params.block_ids)).await?; data_result(repeated_grid_block) } @@ -220,13 +215,13 @@ async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType) pub(crate) async fn get_row_handler( data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: RowIdentifier = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; - match editor.get_row(¶ms.row_id).await? { - None => Err(FlowyError::record_not_found().context("Can not find the row")), - Some(row) => data_result(row), - } + let row = OptionalRow { + row: editor.get_row(¶ms.row_id).await?, + }; + data_result(row) } #[tracing::instrument(level = "debug", skip(data, manager), err)] diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index cb8f2c1e76..cffa903c1d 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -99,7 +99,7 @@ pub enum GridEvent { #[event(input = "CreateRowPayload", output = "Row")] CreateRow = 50, - #[event(input = "RowIdentifierPayload", output = "Row")] + #[event(input = "RowIdentifierPayload", output = "OptionalRow")] GetRow = 51, #[event(input = "RowIdentifierPayload")] diff --git a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs index 462f25e041..a0ce303f94 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs @@ -2,7 +2,7 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::manager::GridUser; use crate::services::block_revision_editor::GridBlockRevisionEditor; use crate::services::persistence::block_index::BlockIndexCache; -use crate::services::row::{group_row_orders, GridBlockSnapshot}; +use crate::services::row::{block_from_row_orders, GridBlockSnapshot}; use dashmap::DashMap; use flowy_error::FlowyResult; use flowy_grid_data_model::entities::{ @@ -77,7 +77,7 @@ impl GridBlockManager { index_row_order.index = row_index; let _ = self - .notify_did_update_block(GridRowsChangeset::insert(block_id, vec![index_row_order])) + .notify_did_update_block(block_id, GridRowsChangeset::insert(block_id, vec![index_row_order])) .await?; Ok(row_count) } @@ -102,7 +102,7 @@ impl GridBlockManager { changesets.push(GridBlockRevisionChangeset::from_row_count(&block_id, row_count)); let _ = self - .notify_did_update_block(GridRowsChangeset::insert(&block_id, inserted_row_orders)) + .notify_did_update_block(&block_id, GridRowsChangeset::insert(&block_id, inserted_row_orders)) .await?; } @@ -121,7 +121,9 @@ impl GridBlockManager { if let Some(row) = row_builder(row_rev.clone()) { let row_order = UpdatedRowOrder::new(&row_rev, row); let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]); - let _ = self.notify_did_update_block(block_order_changeset).await?; + let _ = self + .notify_did_update_block(&editor.block_id, block_order_changeset) + .await?; } } } @@ -137,7 +139,7 @@ impl GridBlockManager { Some(row_order) => { let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?; let _ = self - .notify_did_update_block(GridRowsChangeset::delete(&block_id, vec![row_order])) + .notify_did_update_block(&block_id, GridRowsChangeset::delete(&block_id, vec![row_order])) .await?; } } @@ -147,15 +149,15 @@ impl GridBlockManager { pub(crate) async fn delete_rows(&self, row_orders: Vec) -> FlowyResult> { let mut changesets = vec![]; - for block_order in group_row_orders(row_orders) { - let editor = self.get_editor(&block_order.block_id).await?; + for block_order in block_from_row_orders(row_orders) { + let editor = self.get_editor(&block_order.id).await?; let row_ids = block_order .row_orders .into_iter() .map(|row_order| Cow::Owned(row_order.row_id)) .collect::>>(); let row_count = editor.delete_rows(row_ids).await?; - let changeset = GridBlockRevisionChangeset::from_row_count(&block_order.block_id, row_count); + let changeset = GridBlockRevisionChangeset::from_row_count(&block_order.id, row_count); changesets.push(changeset); } @@ -181,7 +183,9 @@ impl GridBlockManager { updated_rows: vec![], }; - let _ = self.notify_did_update_block(notified_changeset).await?; + let _ = self + .notify_did_update_block(&editor.block_id, notified_changeset) + .await?; } } @@ -241,8 +245,8 @@ impl GridBlockManager { Ok(block_cell_revs) } - async fn notify_did_update_block(&self, changeset: GridRowsChangeset) -> FlowyResult<()> { - send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridRow) + async fn notify_did_update_block(&self, block_id: &str, changeset: GridRowsChangeset) -> FlowyResult<()> { + send_dart_notification(block_id, GridNotification::DidUpdateGridRow) .payload(changeset) .send(); Ok(()) diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index bdb6f940e0..a010362ad0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -424,8 +424,8 @@ impl GridRevisionEditor { let mut block_orders = vec![]; for block_order in pad_read_guard.get_block_revs() { let row_orders = self.block_manager.get_row_orders(&block_order.block_id).await?; - let block_order = GridBlockOrder { - block_id: block_order.block_id, + let block_order = GridBlock { + id: block_order.block_id, row_orders, }; block_orders.push(block_order); @@ -434,7 +434,7 @@ impl GridRevisionEditor { Ok(Grid { id: self.grid_id.clone(), field_orders, - block_orders, + blocks: block_orders, }) } diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs index 07bd3c1bf7..3b4d4ad46b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs @@ -1,6 +1,6 @@ use crate::services::row::decode_cell_data_from_type_option_cell_data; use flowy_error::FlowyResult; -use flowy_grid_data_model::entities::{Cell, GridBlock, GridBlockOrder, RepeatedGridBlock, Row, RowOrder}; +use flowy_grid_data_model::entities::{Cell, GridBlock, RepeatedGridBlock, Row, RowOrder}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, RowRevision}; use std::collections::HashMap; use std::sync::Arc; @@ -10,13 +10,13 @@ pub struct GridBlockSnapshot { pub row_revs: Vec>, } -pub(crate) fn group_row_orders(row_orders: Vec) -> Vec { - let mut map: HashMap = HashMap::new(); +pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec { + let mut map: HashMap = HashMap::new(); row_orders.into_iter().for_each(|row_order| { // Memory Optimization: escape clone block_id let block_id = row_order.block_id.clone(); map.entry(block_id) - .or_insert_with(|| GridBlockOrder::new(&row_order.block_id)) + .or_insert_with(|| GridBlock::new(&row_order.block_id, vec![])) .row_orders .push(row_order); }); diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs index e2520e0419..6cb976cff3 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test.rs @@ -6,7 +6,7 @@ use flowy_grid_data_model::entities::{ }; #[tokio::test] -async fn grid_setting_create_text_filter_test() { +async fn grid_filter_create_test() { let test = GridEditorTest::new().await; let field_rev = test.text_field(); let payload = CreateGridFilterPayload::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned())); @@ -16,7 +16,7 @@ async fn grid_setting_create_text_filter_test() { #[tokio::test] #[should_panic] -async fn grid_setting_create_text_filter_panic_test() { +async fn grid_filter_invalid_condition_panic_test() { let test = GridEditorTest::new().await; let field_rev = test.text_field(); @@ -27,7 +27,7 @@ async fn grid_setting_create_text_filter_panic_test() { } #[tokio::test] -async fn grid_setting_delete_text_filter_test() { +async fn grid_filter_delete_test() { let mut test = GridEditorTest::new().await; let field_rev = test.text_field(); let payload = CreateGridFilterPayload::new(field_rev, 100, Some("abc".to_owned())); @@ -43,4 +43,4 @@ async fn grid_setting_delete_text_filter_test() { } #[tokio::test] -async fn grid_setting_sort_test() {} +async fn grid_filter_get_rows_test() {} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs index 8320a463da..888e11a4bc 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs @@ -1,4 +1,5 @@ use crate::grid::script::GridEditorTest; +use flowy_grid::services::field::DateCellContentChangeset; use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; use flowy_grid_data_model::entities::FieldType; use flowy_grid_data_model::revision::FieldRevision; @@ -17,13 +18,47 @@ impl<'a> GridRowTestBuilder<'a> { Self { test, inner_builder } } - pub fn update_text_cell(&mut self) -> Self { - let text_field = self - .test + pub fn update_text_cell(mut self, data: String) -> Self { + let text_field = self.field_rev_with_type(&FieldType::DateTime); + self.inner_builder.add_cell(&text_field.id, data).unwrap(); + self + } + + pub fn update_number_cell(mut self, data: String) -> Self { + let number_field = self.field_rev_with_type(&FieldType::DateTime); + self.inner_builder.add_cell(&number_field.id, data).unwrap(); + self + } + + pub fn update_date_cell(mut self, value: i64) -> Self { + let value = serde_json::to_string(&DateCellContentChangeset { + date: Some(value.to_string()), + time: None, + }) + .unwrap(); + let date_field = self.field_rev_with_type(&FieldType::DateTime); + self.inner_builder.add_cell(&date_field.id, value).unwrap(); + self + } + + pub fn update_checkbox_cell(mut self, data: bool) -> Self { + let number_field = self.field_rev_with_type(&FieldType::Checkbox); + self.inner_builder.add_cell(&number_field.id, data.to_string()).unwrap(); + self + } + + pub fn update_url_cell(mut self, data: String) -> Self { + let number_field = self.field_rev_with_type(&FieldType::Checkbox); + self.inner_builder.add_cell(&number_field.id, data).unwrap(); + self + } + + pub fn field_rev_with_type(&self, field_type: &FieldType) -> &FieldRevision { + self.test .field_revs .iter() - .find(|field_rev| field_rev.field_type == FieldType::RichText); - // self.inner_builder + .find(|field_rev| field_rev.field_type == &field_type) + .unwrap() } pub fn build(self) -> CreateRowRevisionPayload { diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs index dd5cf40e3b..27659558af 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -15,7 +15,7 @@ pub struct Grid { pub field_orders: Vec, #[pb(index = 3)] - pub block_orders: Vec, + pub blocks: Vec, } #[derive(Debug, Default, Clone, ProtoBuf)] @@ -42,6 +42,12 @@ pub struct Row { pub height: i32, } +#[derive(Debug, Default, ProtoBuf)] +pub struct OptionalRow { + #[pb(index = 1, one_of)] + pub row: Option, +} + #[derive(Debug, Default, ProtoBuf)] pub struct RepeatedRow { #[pb(index = 1)] @@ -66,24 +72,6 @@ impl std::convert::From> for RepeatedGridBlock { } } -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridBlockOrder { - #[pb(index = 1)] - pub block_id: String, - - #[pb(index = 2)] - pub row_orders: Vec, -} - -impl GridBlockOrder { - pub fn new(block_id: &str) -> Self { - GridBlockOrder { - block_id: block_id.to_owned(), - row_orders: vec![], - } - } -} - #[derive(Debug, Clone, Default, ProtoBuf)] pub struct IndexRowOrder { #[pb(index = 1)] @@ -168,7 +156,7 @@ impl GridRowsChangeset { } } -#[derive(Debug, Default, ProtoBuf)] +#[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridBlock { #[pb(index = 1)] pub id: String, @@ -305,12 +293,12 @@ pub struct QueryGridBlocksPayload { pub grid_id: String, #[pb(index = 2)] - pub block_orders: Vec, + pub block_ids: Vec, } pub struct QueryGridBlocksParams { pub grid_id: String, - pub block_orders: Vec, + pub block_ids: Vec, } impl TryInto for QueryGridBlocksPayload { @@ -320,7 +308,7 @@ impl TryInto for QueryGridBlocksPayload { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; Ok(QueryGridBlocksParams { grid_id: grid_id.0, - block_orders: self.block_orders, + block_ids: self.block_ids, }) } } diff --git a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs index e5ae2ef28c..58974c0d34 100644 --- a/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs +++ b/shared-lib/flowy-grid-data-model/src/revision/grid_rev.rs @@ -32,7 +32,7 @@ pub struct GridRevision { pub fields: Vec, pub blocks: Vec, - #[serde(default)] + #[serde(default, skip)] pub setting: GridSettingRevision, }