refactor: grid block notification

This commit is contained in:
appflowy 2022-07-02 00:10:13 +08:00
parent c1ea97c729
commit 9803fe1ccb
20 changed files with 243 additions and 203 deletions

View File

@ -13,7 +13,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
class GridBlockCache {
final String gridId;
void Function(GridBlockUpdateNotifierValue)? _onBlockChanged;
final LinkedHashMap<String, _GridBlockListener> _listeners = LinkedHashMap();
GridBlockCache({required this.gridId});

View File

@ -30,6 +30,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
super(GridState.initial(view.id)) {
rowCache = GridRowCache(
gridId: view.id,
blockId: "",
fieldDelegate: GridRowCacheDelegateImpl(fieldCache),
);
@ -96,8 +97,8 @@ class GridBloc extends Bloc<GridEvent, GridState> {
for (final block in grid.blocks) {
blockCache.addBlockListener(block.id);
}
final rowOrders = grid.blocks.expand((block) => block.rowOrders).toList();
rowCache.initialRows(rowOrders);
final rowInfos = grid.blocks.expand((block) => block.rowInfos).toList();
rowCache.initialRows(rowInfos);
await _loadFields(grid, emit);
},

View File

@ -12,7 +12,11 @@ class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState>
final RowService _rowService;
RowActionSheetBloc({required GridRow rowData})
: _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
: _rowService = RowService(
gridId: rowData.gridId,
blockId: rowData.blockId,
rowId: rowData.rowId,
),
super(RowActionSheetState.initial(rowData)) {
on<RowActionSheetEvent>(
(event, emit) async {

View File

@ -17,7 +17,11 @@ class RowBloc extends Bloc<RowEvent, RowState> {
RowBloc({
required GridRow rowData,
required GridRowCache rowCache,
}) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
}) : _rowService = RowService(
gridId: rowData.gridId,
blockId: rowData.blockId,
rowId: rowData.rowId,
),
_rowCache = rowCache,
super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) {
on<RowEvent>(

View File

@ -23,18 +23,23 @@ abstract class GridRowFieldDelegate {
class GridRowCache {
final String gridId;
final String blockId;
final RowsNotifier _rowsNotifier;
final GridRowFieldDelegate _fieldDelegate;
List<GridRow> get clonedRows => _rowsNotifier.clonedRows;
GridRowCache({required this.gridId, required GridRowFieldDelegate fieldDelegate})
: _rowsNotifier = RowsNotifier(
rowBuilder: (rowOrder) {
GridRowCache({
required this.gridId,
required this.blockId,
required GridRowFieldDelegate fieldDelegate,
}) : _rowsNotifier = RowsNotifier(
rowBuilder: (rowInfo) {
return GridRow(
gridId: gridId,
blockId: "test",
fields: fieldDelegate.fields,
rowId: rowOrder.rowId,
height: rowOrder.height.toDouble(),
rowId: rowInfo.rowId,
height: rowInfo.height.toDouble(),
);
},
),
@ -120,13 +125,14 @@ class GridRowCache {
return _makeGridCells(rowId, data);
}
void initialRows(List<RowOrder> rowOrders) {
_rowsNotifier.initialRows(rowOrders);
void initialRows(List<BlockRowInfo> rowInfos) {
_rowsNotifier.initialRows(rowInfos);
}
Future<void> _loadRow(String rowId) async {
final payload = RowIdentifierPayload.create()
final payload = GridRowIdPayload.create()
..gridId = gridId
..blockId = blockId
..rowId = rowId;
final result = await GridEventGetRow(payload).send();
@ -156,34 +162,34 @@ class GridRowCache {
}
class RowsNotifier extends ChangeNotifier {
List<GridRow> _rows = [];
HashMap<String, Row> _rowDataMap = HashMap();
List<GridRow> _allRows = [];
HashMap<String, Row> _rowByRowId = HashMap();
GridRowChangeReason _changeReason = const InitialListState();
final GridRow Function(RowOrder) rowBuilder;
final GridRow Function(BlockRowInfo) rowBuilder;
RowsNotifier({
required this.rowBuilder,
});
List<GridRow> get clonedRows => [..._rows];
List<GridRow> get clonedRows => [..._allRows];
void initialRows(List<RowOrder> rowOrders) {
_rowDataMap = HashMap();
final rows = rowOrders.map((rowOrder) => rowBuilder(rowOrder)).toList();
void initialRows(List<BlockRowInfo> rowInfos) {
_rowByRowId = HashMap();
final rows = rowInfos.map((rowOrder) => rowBuilder(rowOrder)).toList();
_update(rows, const GridRowChangeReason.initial());
}
void deleteRows(List<RowOrder> deletedRows) {
void deleteRows(List<GridRowId> deletedRows) {
if (deletedRows.isEmpty) {
return;
}
final List<GridRow> newRows = [];
final DeletedIndexs deletedIndex = [];
final Map<String, RowOrder> deletedRowMap = {for (var e in deletedRows) e.rowId: e};
final Map<String, GridRowId> deletedRowByRowId = {for (var e in deletedRows) e.rowId: e};
_rows.asMap().forEach((index, row) {
if (deletedRowMap[row.rowId] == null) {
_allRows.asMap().forEach((index, row) {
if (deletedRowByRowId[row.rowId] == null) {
newRows.add(row);
} else {
deletedIndex.add(DeletedIndex(index: index, row: row));
@ -203,10 +209,10 @@ class RowsNotifier extends ChangeNotifier {
for (final insertRow in insertRows) {
final insertIndex = InsertedIndex(
index: insertRow.index,
rowId: insertRow.rowOrder.rowId,
rowId: insertRow.rowInfo.rowId,
);
insertIndexs.add(insertIndex);
newRows.insert(insertRow.index, (rowBuilder(insertRow.rowOrder)));
newRows.insert(insertRow.index, (rowBuilder(insertRow.rowInfo)));
}
_update(newRows, GridRowChangeReason.insert(insertIndexs));
}
@ -219,14 +225,15 @@ class RowsNotifier extends ChangeNotifier {
final UpdatedIndexs updatedIndexs = UpdatedIndexs();
final List<GridRow> newRows = clonedRows;
for (final updatedRow in updatedRows) {
final rowOrder = updatedRow.rowOrder;
final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId);
final rowOrder = updatedRow.rowInfo;
final rowId = updatedRow.rowInfo.rowId;
final index = newRows.indexWhere((row) => row.rowId == rowId);
if (index != -1) {
_rowDataMap[rowOrder.rowId] = updatedRow.row;
_rowByRowId[rowId] = updatedRow.row;
newRows.removeAt(index);
newRows.insert(index, rowBuilder(rowOrder));
updatedIndexs[rowOrder.rowId] = UpdatedIndex(index: index, rowId: rowOrder.rowId);
updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId);
}
}
@ -234,11 +241,11 @@ class RowsNotifier extends ChangeNotifier {
}
void fieldDidChange() {
_update(_rows, const GridRowChangeReason.fieldDidChange());
_update(_allRows, const GridRowChangeReason.fieldDidChange());
}
void _update(List<GridRow> rows, GridRowChangeReason reason) {
_rows = rows;
_allRows = rows;
_changeReason = reason;
_changeReason.map(
@ -253,13 +260,13 @@ class RowsNotifier extends ChangeNotifier {
set rowData(Row rowData) {
rowData.freeze();
_rowDataMap[rowData.id] = rowData;
final index = _rows.indexWhere((row) => row.rowId == rowData.id);
_rowByRowId[rowData.id] = rowData;
final index = _allRows.indexWhere((row) => row.rowId == rowData.id);
if (index != -1) {
// update the corresponding row in _rows if they are not the same
if (_rows[index].data != rowData) {
final row = _rows.removeAt(index).copyWith(data: rowData);
_rows.insert(index, row);
if (_allRows[index].data != rowData) {
final row = _allRows.removeAt(index).copyWith(data: rowData);
_allRows.insert(index, row);
// Calculate the update index
final UpdatedIndexs updatedIndexs = UpdatedIndexs();
@ -273,15 +280,16 @@ class RowsNotifier extends ChangeNotifier {
}
Row? rowDataWithId(String rowId) {
return _rowDataMap[rowId];
return _rowByRowId[rowId];
}
}
class RowService {
final String gridId;
final String blockId;
final String rowId;
RowService({required this.gridId, required this.rowId});
RowService({required this.gridId, required this.blockId, required this.rowId});
Future<Either<Row, FlowyError>> createRow() {
CreateRowPayload payload = CreateRowPayload.create()
@ -303,24 +311,27 @@ class RowService {
}
Future<Either<OptionalRow, FlowyError>> getRow() {
final payload = RowIdentifierPayload.create()
final payload = GridRowIdPayload.create()
..gridId = gridId
..blockId = blockId
..rowId = rowId;
return GridEventGetRow(payload).send();
}
Future<Either<Unit, FlowyError>> deleteRow() {
final payload = RowIdentifierPayload.create()
final payload = GridRowIdPayload.create()
..gridId = gridId
..blockId = blockId
..rowId = rowId;
return GridEventDeleteRow(payload).send();
}
Future<Either<Unit, FlowyError>> duplicateRow() {
final payload = RowIdentifierPayload.create()
final payload = GridRowIdPayload.create()
..gridId = gridId
..blockId = blockId
..rowId = rowId;
return GridEventDuplicateRow(payload).send();
@ -331,6 +342,7 @@ class RowService {
class GridRow with _$GridRow {
const factory GridRow({
required String gridId,
required String blockId,
required String rowId,
required UnmodifiableListView<Field> fields,
required double height,

View File

@ -1,3 +1,4 @@
use crate::entities::GridRowId;
use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
@ -10,46 +11,56 @@ pub struct GridBlock {
pub id: String,
#[pb(index = 2)]
pub row_orders: Vec<RowOrder>,
pub row_infos: Vec<BlockRowInfo>,
}
impl GridBlock {
pub fn new(block_id: &str, row_orders: Vec<RowOrder>) -> Self {
pub fn new(block_id: &str, row_orders: Vec<BlockRowInfo>) -> Self {
Self {
id: block_id.to_owned(),
row_orders,
row_infos: row_orders,
}
}
}
#[derive(Debug, Default, Clone, ProtoBuf)]
pub struct RowOrder {
pub struct BlockRowInfo {
#[pb(index = 1)]
pub row_id: String,
pub block_id: String,
#[pb(index = 2)]
pub block_id: String,
pub row_id: String,
#[pb(index = 3)]
pub height: i32,
}
impl std::convert::From<&RowRevision> for RowOrder {
fn from(row: &RowRevision) -> Self {
impl BlockRowInfo {
pub fn row_id(&self) -> &str {
&self.row_id
}
pub fn block_id(&self) -> &str {
&self.block_id
}
}
impl std::convert::From<&RowRevision> for BlockRowInfo {
fn from(rev: &RowRevision) -> Self {
Self {
row_id: row.id.clone(),
block_id: row.block_id.clone(),
height: row.height,
block_id: rev.block_id.clone(),
row_id: rev.id.clone(),
height: rev.height,
}
}
}
impl std::convert::From<&Arc<RowRevision>> for RowOrder {
fn from(row: &Arc<RowRevision>) -> Self {
impl std::convert::From<&Arc<RowRevision>> for BlockRowInfo {
fn from(rev: &Arc<RowRevision>) -> Self {
Self {
row_id: row.id.clone(),
block_id: row.block_id.clone(),
height: row.height,
block_id: rev.block_id.clone(),
row_id: rev.id.clone(),
height: rev.height,
}
}
}
@ -95,7 +106,7 @@ impl std::convert::From<Vec<GridBlock>> for RepeatedGridBlock {
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct IndexRowOrder {
#[pb(index = 1)]
pub row_order: RowOrder,
pub row_info: BlockRowInfo,
#[pb(index = 2, one_of)]
pub index: Option<i32>,
@ -104,7 +115,7 @@ pub struct IndexRowOrder {
#[derive(Debug, Default, ProtoBuf)]
pub struct UpdatedRowOrder {
#[pb(index = 1)]
pub row_order: RowOrder,
pub row_info: BlockRowInfo,
#[pb(index = 2)]
pub row: Row,
@ -113,31 +124,25 @@ pub struct UpdatedRowOrder {
impl UpdatedRowOrder {
pub fn new(row_rev: &RowRevision, row: Row) -> Self {
Self {
row_order: RowOrder::from(row_rev),
row_info: BlockRowInfo::from(row_rev),
row,
}
}
}
impl std::convert::From<RowOrder> for IndexRowOrder {
fn from(row_order: RowOrder) -> Self {
Self { row_order, index: None }
impl std::convert::From<BlockRowInfo> for IndexRowOrder {
fn from(row_info: BlockRowInfo) -> Self {
Self { row_info, index: None }
}
}
impl std::convert::From<&RowRevision> for IndexRowOrder {
fn from(row: &RowRevision) -> Self {
let row_order = RowOrder::from(row);
let row_order = BlockRowInfo::from(row);
Self::from(row_order)
}
}
#[derive(ProtoBuf, Default)]
pub struct GridBlockNotification {
#[pb(index = 1)]
hide_rows: Vec<String>,
}
#[derive(Debug, Default, ProtoBuf)]
pub struct GridRowsChangeset {
#[pb(index = 1)]
@ -147,7 +152,7 @@ pub struct GridRowsChangeset {
pub inserted_rows: Vec<IndexRowOrder>,
#[pb(index = 3)]
pub deleted_rows: Vec<RowOrder>,
pub deleted_rows: Vec<GridRowId>,
#[pb(index = 4)]
pub updated_rows: Vec<UpdatedRowOrder>,
@ -162,7 +167,7 @@ impl GridRowsChangeset {
}
}
pub fn delete(block_id: &str, deleted_rows: Vec<RowOrder>) -> Self {
pub fn delete(block_id: &str, deleted_rows: Vec<GridRowId>) -> Self {
Self {
block_id: block_id.to_owned(),
inserted_rows: vec![],

View File

@ -3,33 +3,54 @@ use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
#[derive(ProtoBuf, Default)]
pub struct RowIdentifierPayload {
pub struct GridRowIdPayload {
#[pb(index = 1)]
pub grid_id: String,
#[pb(index = 2)]
pub block_id: String,
#[pb(index = 3)]
pub row_id: String,
}
pub struct RowIdentifier {
#[derive(Debug, Default, Clone, ProtoBuf)]
pub struct GridRowId {
#[pb(index = 1)]
pub grid_id: String,
#[pb(index = 2)]
pub block_id: String,
#[pb(index = 3)]
pub row_id: String,
}
impl TryInto<RowIdentifier> for RowIdentifierPayload {
impl TryInto<GridRowId> for GridRowIdPayload {
type Error = ErrorCode;
fn try_into(self) -> Result<RowIdentifier, Self::Error> {
fn try_into(self) -> Result<GridRowId, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
// let block_id = NotEmptyStr::parse(self.block_id).map_err(|_| ErrorCode::BlockIdIsEmpty)?;
let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
Ok(RowIdentifier {
Ok(GridRowId {
grid_id: grid_id.0,
block_id: self.block_id,
row_id: row_id.0,
})
}
}
#[derive(Debug, Default, Clone, ProtoBuf)]
pub struct BlockRowId {
#[pb(index = 1)]
pub block_id: String,
#[pb(index = 2)]
pub row_id: String,
}
#[derive(ProtoBuf, Default)]
pub struct CreateRowPayload {
#[pb(index = 1)]

View File

@ -221,10 +221,10 @@ async fn get_type_option_data(field_rev: &FieldRevision, field_type: &FieldType)
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn get_row_handler(
data: Data<RowIdentifierPayload>,
data: Data<GridRowIdPayload>,
manager: AppData<Arc<GridManager>>,
) -> DataResult<OptionalRow, FlowyError> {
let params: RowIdentifier = data.into_inner().try_into()?;
let params: GridRowId = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let row = OptionalRow {
row: editor.get_row(&params.row_id).await?,
@ -234,10 +234,10 @@ pub(crate) async fn get_row_handler(
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn delete_row_handler(
data: Data<RowIdentifierPayload>,
data: Data<GridRowIdPayload>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: RowIdentifier = data.into_inner().try_into()?;
let params: GridRowId = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.delete_row(&params.row_id).await?;
Ok(())
@ -245,10 +245,10 @@ pub(crate) async fn delete_row_handler(
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn duplicate_row_handler(
data: Data<RowIdentifierPayload>,
data: Data<GridRowIdPayload>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: RowIdentifier = data.into_inner().try_into()?;
let params: GridRowId = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.duplicate_row(&params.row_id).await?;
Ok(())

View File

@ -99,13 +99,13 @@ pub enum GridEvent {
#[event(input = "CreateRowPayload", output = "Row")]
CreateRow = 50,
#[event(input = "RowIdentifierPayload", output = "OptionalRow")]
#[event(input = "GridRowIdPayload", output = "OptionalRow")]
GetRow = 51,
#[event(input = "RowIdentifierPayload")]
#[event(input = "GridRowIdPayload")]
DeleteRow = 52,
#[event(input = "RowIdentifierPayload")]
#[event(input = "GridRowIdPayload")]
DuplicateRow = 53,
#[event(input = "CellIdentifierPayload", output = "Cell")]

View File

@ -1,5 +1,5 @@
use crate::dart_notification::{send_dart_notification, GridNotification};
use crate::entities::{CellChangeset, GridRowsChangeset, IndexRowOrder, Row, RowOrder, UpdatedRowOrder};
use crate::entities::{BlockRowInfo, CellChangeset, GridRowId, GridRowsChangeset, IndexRowOrder, Row, UpdatedRowOrder};
use crate::manager::GridUser;
use crate::services::block_revision_editor::GridBlockRevisionEditor;
use crate::services::persistence::block_index::BlockIndexCache;
@ -133,12 +133,18 @@ impl GridBlockManager {
let row_id = row_id.to_owned();
let block_id = self.persistence.get_block_id(&row_id)?;
let editor = self.get_editor(&block_id).await?;
match editor.get_row_order(&row_id).await? {
match editor.get_row_info(&row_id).await? {
None => {}
Some(row_order) => {
Some(row_info) => {
let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?;
let row_identifier = GridRowId {
grid_id: self.grid_id.clone(),
block_id: row_info.block_id,
row_id: row_info.row_id,
};
let _ = self
.notify_did_update_block(&block_id, GridRowsChangeset::delete(&block_id, vec![row_order]))
.notify_did_update_block(&block_id, GridRowsChangeset::delete(&block_id, vec![row_identifier]))
.await?;
}
}
@ -148,18 +154,18 @@ impl GridBlockManager {
pub(crate) async fn delete_rows(
&self,
row_orders: Vec<RowOrder>,
row_orders: Vec<BlockRowInfo>,
) -> FlowyResult<Vec<GridBlockMetaRevisionChangeset>> {
let mut changesets = vec![];
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
for grid_block in block_from_row_orders(row_orders) {
let editor = self.get_editor(&grid_block.id).await?;
let row_ids = grid_block
.row_infos
.into_iter()
.map(|row_order| Cow::Owned(row_order.row_id))
.map(|row_info| Cow::Owned(row_info.row_id().to_owned()))
.collect::<Vec<Cow<String>>>();
let row_count = editor.delete_rows(row_ids).await?;
let changeset = GridBlockMetaRevisionChangeset::from_row_count(&block_order.id, row_count);
let changeset = GridBlockMetaRevisionChangeset::from_row_count(&grid_block.id, row_count);
changesets.push(changeset);
}
@ -173,15 +179,21 @@ impl GridBlockManager {
match editor.get_row_revs(Some(vec![Cow::Borrowed(row_id)])).await?.pop() {
None => {}
Some(row_rev) => {
let row_order = RowOrder::from(&row_rev);
let row_info = BlockRowInfo::from(&row_rev);
let insert_row = IndexRowOrder {
row_order: row_order.clone(),
row_info: row_info.clone(),
index: Some(to as i32),
};
let deleted_row = GridRowId {
grid_id: self.grid_id.clone(),
block_id: row_info.block_id,
row_id: row_info.row_id,
};
let notified_changeset = GridRowsChangeset {
block_id: editor.block_id.clone(),
inserted_rows: vec![insert_row],
deleted_rows: vec![row_order],
deleted_rows: vec![deleted_row],
updated_rows: vec![],
};
@ -215,9 +227,9 @@ impl GridBlockManager {
}
}
pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<RowOrder>> {
pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<BlockRowInfo>> {
let editor = self.get_editor(block_id).await?;
editor.get_row_orders::<&str>(None).await
editor.get_row_infos::<&str>(None).await
}
pub(crate) async fn get_block_snapshots(

View File

@ -1,3 +1,4 @@
use crate::entities::BlockRowInfo;
use bytes::Bytes;
use flowy_error::{FlowyError, FlowyResult};
use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision};
@ -10,7 +11,6 @@ use lib_ot::core::PlainTextAttributes;
use std::borrow::Cow;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::entities::RowOrder;
pub struct GridBlockRevisionEditor {
user_id: String,
@ -123,24 +123,24 @@ impl GridBlockRevisionEditor {
Ok(cell_revs)
}
pub async fn get_row_order(&self, row_id: &str) -> FlowyResult<Option<RowOrder>> {
pub async fn get_row_info(&self, row_id: &str) -> FlowyResult<Option<BlockRowInfo>> {
let row_ids = Some(vec![Cow::Borrowed(row_id)]);
Ok(self.get_row_orders(row_ids).await?.pop())
Ok(self.get_row_infos(row_ids).await?.pop())
}
pub async fn get_row_orders<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<RowOrder>>
pub async fn get_row_infos<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<BlockRowInfo>>
where
T: AsRef<str> + ToOwned + ?Sized,
{
let row_orders = self
let row_infos = self
.pad
.read()
.await
.get_row_revs(row_ids)?
.iter()
.map(RowOrder::from)
.collect::<Vec<RowOrder>>();
Ok(row_orders)
.map(BlockRowInfo::from)
.collect::<Vec<BlockRowInfo>>();
Ok(row_infos)
}
async fn modify<F>(&self, f: F) -> FlowyResult<()>

View File

@ -14,6 +14,7 @@ use std::sync::Arc;
use tokio::sync::RwLock;
pub(crate) struct GridFilterService {
#[allow(dead_code)]
grid_id: String,
scheduler: Arc<dyn GridServiceTaskScheduler>,
grid_pad: Arc<RwLock<GridRevisionPad>>,
@ -50,15 +51,20 @@ impl GridFilterService {
.map(|field_rev| (field_rev.id.clone(), field_rev))
.collect::<HashMap<String, Arc<FieldRevision>>>();
let mut changes = vec![];
let mut show_rows = vec![];
let mut hide_rows = vec![];
for block in task_context.blocks {
block.row_revs.iter().for_each(|row_rev| {
if let Some(change) = filter_row(row_rev, &self.filter_cache, &self.filter_result_cache, &field_revs) {
changes.push(change);
let result = filter_row(row_rev, &self.filter_cache, &self.filter_result_cache, &field_revs);
if result.is_row_hidden() {
hide_rows.push(result.row_id);
} else {
show_rows.push(result.row_id);
}
});
}
self.notify(changes).await;
self.notify(hide_rows, show_rows).await;
Ok(())
}
@ -77,12 +83,9 @@ impl GridFilterService {
self.filter_cache.write().await.remove(filter_id);
}
match self.block_manager.get_block_snapshots(None).await {
Ok(blocks) => {
let task = self.gen_task(blocks).await;
let _ = self.scheduler.register_task(task).await;
}
Err(_) => {}
if let Ok(blocks) = self.block_manager.get_block_snapshots(None).await {
let task = self.gen_task(blocks).await;
let _ = self.scheduler.register_task(task).await;
}
}
@ -91,19 +94,17 @@ impl GridFilterService {
let handler_id = self.grid_pad.read().await.grid_id();
let context = FilterTaskContext { blocks };
let task = Task {
Task {
handler_id,
id: task_id,
content: TaskContent::Filter(context),
};
task
}
}
async fn notify(&self, _changes: Vec<FilterResult>) {
async fn notify(&self, _hide_rows: Vec<String>, _show_rows: Vec<String>) {
// let notification = GridNotification {};
// send_dart_notification(grid_id, GridNotification::DidUpdateGrid)
// .payload(updated_field)
// send_dart_notification(grid_id, GridNotification::DidUpdateGridBlock)
// .payload(notification)
// .send();
}
}
@ -113,12 +114,12 @@ fn filter_row(
_filter_cache: &Arc<RwLock<FilterCache>>,
_filter_result_cache: &Arc<RwLock<FilterResultCache>>,
_field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
) -> Option<FilterResult> {
let _filter_result = FilterResult::new(row_rev);
) -> FilterResult {
let filter_result = FilterResult::new(row_rev);
row_rev.cells.iter().for_each(|(_k, cell_rev)| {
let _cell_rev: &CellRevision = cell_rev;
});
todo!()
filter_result
}
pub struct GridFilterChangeset {
@ -152,10 +153,12 @@ impl std::convert::From<&GridSettingChangesetParams> for GridFilterChangeset {
#[derive(Default)]
struct FilterResultCache {
#[allow(dead_code)]
rows: HashMap<String, FilterResult>,
}
impl FilterResultCache {
#[allow(dead_code)]
fn insert(&mut self, row_id: &str, result: FilterResult) {
self.rows.insert(row_id.to_owned(), result);
}
@ -164,6 +167,7 @@ impl FilterResultCache {
#[derive(Default)]
struct FilterResult {
row_id: String,
#[allow(dead_code)]
cell_by_field_id: HashMap<String, bool>,
}
@ -175,9 +179,14 @@ impl FilterResult {
}
}
#[allow(dead_code)]
fn update_cell(&mut self, cell_id: &str, exist: bool) {
self.cell_by_field_id.insert(cell_id.to_owned(), exist);
}
fn is_row_hidden(&self) -> bool {
todo!()
}
}
#[derive(Default)]

View File

@ -265,14 +265,14 @@ impl GridRevisionEditor {
Ok(())
}
pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<RowOrder> {
pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<BlockRowInfo> {
let field_revs = self.grid_pad.read().await.get_field_revs(None)?;
let block_id = self.block_id().await?;
// insert empty row below the row whose id is upper_row_id
let row_rev_ctx = CreateRowRevisionBuilder::new(&field_revs).build();
let row_rev = make_row_rev_from_context(&block_id, row_rev_ctx);
let row_order = RowOrder::from(&row_rev);
let row_order = BlockRowInfo::from(&row_rev);
// insert the row
let row_count = self.block_manager.create_row(&block_id, row_rev, start_row_id).await?;
@ -283,13 +283,13 @@ impl GridRevisionEditor {
Ok(row_order)
}
pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<RowOrder>> {
pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<BlockRowInfo>> {
let block_id = self.block_id().await?;
let mut rows_by_block_id: HashMap<String, Vec<RowRevision>> = HashMap::new();
let mut row_orders = vec![];
for ctx in contexts {
let row_rev = make_row_rev_from_context(&block_id, ctx);
row_orders.push(RowOrder::from(&row_rev));
row_orders.push(BlockRowInfo::from(&row_rev));
rows_by_block_id
.entry(block_id.clone())
.or_insert_with(Vec::new)
@ -421,7 +421,7 @@ impl GridRevisionEditor {
Ok(block_meta_revs)
}
pub async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<()> {
pub async fn delete_rows(&self, row_orders: Vec<BlockRowInfo>) -> FlowyResult<()> {
let changesets = self.block_manager.delete_rows(row_orders).await?;
for changeset in changesets {
let _ = self.update_block(changeset).await?;
@ -441,7 +441,7 @@ impl GridRevisionEditor {
let row_orders = self.block_manager.get_row_orders(&block_rev.block_id).await?;
let block_order = GridBlock {
id: block_rev.block_id.clone(),
row_orders,
row_infos: row_orders,
};
block_orders.push(block_order);
}

View File

@ -1,6 +1,5 @@
mod cell_data_operation;
mod row_builder;
pub mod row_entities;
mod row_loader;
pub use cell_data_operation::*;

View File

@ -1,31 +0,0 @@
use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
#[derive(ProtoBuf, Default)]
pub struct RowIdentifierPayload {
#[pb(index = 1)]
pub grid_id: String,
#[pb(index = 3)]
pub row_id: String,
}
pub struct RowIdentifier {
pub grid_id: String,
pub row_id: String,
}
impl TryInto<RowIdentifier> for RowIdentifierPayload {
type Error = ErrorCode;
fn try_into(self) -> Result<RowIdentifier, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
Ok(RowIdentifier {
grid_id: grid_id.0,
row_id: row_id.0,
})
}
}

View File

@ -1,4 +1,4 @@
use crate::entities::{GridBlock, RepeatedGridBlock, Row, RowOrder};
use crate::entities::{BlockRowInfo, GridBlock, RepeatedGridBlock, Row};
use flowy_error::FlowyResult;
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
use std::collections::HashMap;
@ -9,15 +9,16 @@ pub struct GridBlockSnapshot {
pub row_revs: Vec<Arc<RowRevision>>,
}
pub(crate) fn block_from_row_orders(row_orders: Vec<RowOrder>) -> Vec<GridBlock> {
pub(crate) fn block_from_row_orders(row_orders: Vec<BlockRowInfo>) -> Vec<GridBlock> {
let mut map: HashMap<String, GridBlock> = HashMap::new();
row_orders.into_iter().for_each(|row_order| {
row_orders.into_iter().for_each(|row_info| {
// Memory Optimization: escape clone block_id
let block_id = row_order.block_id.clone();
let block_id = row_info.block_id().to_owned();
let cloned_block_id = block_id.clone();
map.entry(block_id)
.or_insert_with(|| GridBlock::new(&row_order.block_id, vec![]))
.row_orders
.push(row_order);
.or_insert_with(|| GridBlock::new(&cloned_block_id, vec![]))
.row_infos
.push(row_info);
});
map.into_values().collect::<Vec<_>>()
}
@ -34,8 +35,8 @@ pub(crate) fn block_from_row_orders(row_orders: Vec<RowOrder>) -> Vec<GridBlock>
// Some((field_id, cell))
// }
pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<RowOrder> {
row_revs.iter().map(RowOrder::from).collect::<Vec<_>>()
pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<BlockRowInfo> {
row_revs.iter().map(BlockRowInfo::from).collect::<Vec<_>>()
}
pub(crate) fn make_row_from_row_rev(fields: &[Arc<FieldRevision>], row_rev: Arc<RowRevision>) -> Option<Row> {

View File

@ -55,6 +55,7 @@ pub(crate) struct FilterTaskContext {
}
pub(crate) enum TaskContent {
#[allow(dead_code)]
Snapshot,
Filter(FilterTaskContext),
}

View File

@ -4,11 +4,11 @@ use flowy_grid::entities::CreateGridFilterPayload;
#[tokio::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()));
// let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }];
// GridEditorTest::new().await.run_scripts(scripts).await;
let test = GridEditorTest::new().await;
let field_rev = test.text_field();
let payload = CreateGridFilterPayload::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned()));
let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }];
GridEditorTest::new().await.run_scripts(scripts).await;
}
#[tokio::test]
@ -25,21 +25,21 @@ async fn grid_filter_invalid_condition_panic_test() {
#[tokio::test]
async fn grid_filter_delete_test() {
// let mut test = GridEditorTest::new().await;
// let field_rev = test.text_field().clone();
// let payload = CreateGridFilterPayload::new(&field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned()));
// let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }];
// test.run_scripts(scripts).await;
//
// let filter = test.grid_filters().await.pop().unwrap();
// test.run_scripts(vec![
// DeleteGridTableFilter {
// filter_id: filter.id,
// field_type: field_rev.field_type.clone(),
// },
// AssertTableFilterCount { count: 0 },
// ])
// .await;
let mut test = GridEditorTest::new().await;
let field_rev = test.text_field().clone();
let payload = CreateGridFilterPayload::new(&field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned()));
let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }];
test.run_scripts(scripts).await;
let filter = test.grid_filters().await.pop().unwrap();
test.run_scripts(vec![
DeleteGridTableFilter {
filter_id: filter.id,
field_type: field_rev.field_type.clone(),
},
AssertTableFilterCount { count: 0 },
])
.await;
}
#[tokio::test]

View File

@ -2,7 +2,7 @@ mod block_test;
mod cell_test;
mod field_test;
mod field_util;
mod filter_test;
// mod filter_test;
mod row_test;
mod row_util;
mod script;

View File

@ -1,4 +1,7 @@
#![cfg_attr(rustfmt, rustfmt::skip)]
#![allow(clippy::all)]
#![allow(dead_code)]
#![allow(unused_imports)]
use bytes::Bytes;
use flowy_grid::services::field::*;
use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor};
@ -96,7 +99,7 @@ pub struct GridEditorTest {
pub row_revs: Vec<Arc<RowRevision>>,
pub field_count: usize,
pub row_order_by_row_id: HashMap<String, RowOrder>,
pub row_order_by_row_id: HashMap<String, BlockRowInfo>,
}
impl GridEditorTest {
@ -200,14 +203,14 @@ impl GridEditorTest {
}
EditorScript::CreateEmptyRow => {
let row_order = self.editor.create_row(None).await.unwrap();
self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order);
self.row_order_by_row_id.insert(row_order.row_id().to_owned(), row_order);
self.row_revs = self.get_row_revs().await;
self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap();
}
EditorScript::CreateRow { payload: context } => {
let row_orders = self.editor.insert_rows(vec![context]).await.unwrap();
for row_order in row_orders {
self.row_order_by_row_id.insert(row_order.row_id.clone(), row_order);
self.row_order_by_row_id.insert(row_order.row_id().to_owned(), row_order);
}
self.row_revs = self.get_row_revs().await;
self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap();
@ -217,7 +220,7 @@ impl GridEditorTest {
let row_orders = row_ids
.into_iter()
.map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone())
.collect::<Vec<RowOrder>>();
.collect::<Vec<BlockRowInfo>>();
self.editor.delete_rows(row_orders).await.unwrap();
self.row_revs = self.get_row_revs().await;