From d9b2a5353b1f47fc04904c24aa3c086686c4f9ec Mon Sep 17 00:00:00 2001 From: eliovir Date: Sat, 26 Mar 2022 16:16:25 +0100 Subject: [PATCH 001/112] Typo --- frontend/app_flowy/assets/translations/fr-FR.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app_flowy/assets/translations/fr-FR.json b/frontend/app_flowy/assets/translations/fr-FR.json index c05c9aba27..ed1d56bce8 100644 --- a/frontend/app_flowy/assets/translations/fr-FR.json +++ b/frontend/app_flowy/assets/translations/fr-FR.json @@ -68,7 +68,7 @@ "help": "Aide et Support", "debug": { "name": "Informations de Débogage", - "success": "Informations de Débogage copiées dans le presse-papiers!", + "success": "Informations de Débogage copiées dans le presse-papiers !", "fail": "Impossible de copier les informations de Débogage dans le presse-papiers" } }, From ab63ce7bce2c50270a06e1bbf37d201491b10373 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 7 Jun 2022 14:22:20 +0800 Subject: [PATCH 002/112] chore: rename structs --- frontend/rust-lib/flowy-grid/src/manager.rs | 26 ++------- .../services/{ => block}/block_meta_editor.rs | 28 +++++----- .../{ => block}/block_meta_manager.rs | 45 ++++++++------- .../flowy-grid/src/services/block/mod.rs | 5 ++ .../{grid_editor.rs => grid_meta_editor.rs} | 55 +++++++++++-------- .../rust-lib/flowy-grid/src/services/mod.rs | 5 +- .../flowy-grid/tests/grid/grid_test.rs | 8 +-- .../rust-lib/flowy-grid/tests/grid/script.rs | 15 ++--- .../src/entities/meta.rs | 20 +++---- .../src/client_grid/grid_block_meta_pad.rs | 16 +++--- .../src/client_grid/grid_builder.rs | 10 ++-- .../src/client_grid/grid_meta_pad.rs | 16 +++--- 12 files changed, 125 insertions(+), 124 deletions(-) rename frontend/rust-lib/flowy-grid/src/services/{ => block}/block_meta_editor.rs (86%) rename frontend/rust-lib/flowy-grid/src/services/{ => block}/block_meta_manager.rs (88%) create mode 100644 frontend/rust-lib/flowy-grid/src/services/block/mod.rs rename frontend/rust-lib/flowy-grid/src/services/{grid_editor.rs => grid_meta_editor.rs} (93%) diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 2965cb5bd9..08d9559d41 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -1,4 +1,5 @@ -use crate::services::grid_editor::GridMetaEditor; +use crate::services::block::make_grid_block_meta_rev_manager; +use crate::services::grid_meta_editor::GridMetaEditor; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::persistence::kv::GridKVPersistence; use crate::services::persistence::GridDatabase; @@ -7,7 +8,7 @@ use dashmap::DashMap; use flowy_database::ConnectionPool; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{BuildGridContext, GridMeta}; -use flowy_revision::disk::{SQLiteGridBlockMetaRevisionPersistence, SQLiteGridRevisionPersistence}; +use flowy_revision::disk::SQLiteGridRevisionPersistence; use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket}; use flowy_sync::client_grid::{make_block_meta_delta, make_grid_delta}; use flowy_sync::entities::revision::{RepeatedRevision, Revision}; @@ -35,12 +36,12 @@ impl GridManager { ) -> Self { let grid_editors = Arc::new(DashMap::new()); let kv_persistence = Arc::new(GridKVPersistence::new(database.clone())); - let block_index_persistence = Arc::new(BlockIndexCache::new(database)); + let block_index_cache = Arc::new(BlockIndexCache::new(database)); Self { editor_map: grid_editors, grid_user, + block_index_cache, kv_persistence, - block_index_cache: block_index_persistence, } } @@ -59,9 +60,7 @@ impl GridManager { block_id: T, revisions: RepeatedRevision, ) -> FlowyResult<()> { - let block_id = block_id.as_ref(); - let db_pool = self.grid_user.db_pool()?; - let rev_manager = self.make_grid_block_meta_rev_manager(block_id, db_pool)?; + let rev_manager = make_grid_block_meta_rev_manager(&self.grid_user, block_id.as_ref())?; let _ = rev_manager.reset_object(revisions).await?; Ok(()) } @@ -134,18 +133,6 @@ impl GridManager { let rev_manager = RevisionManager::new(&user_id, grid_id, rev_persistence); Ok(rev_manager) } - - fn make_grid_block_meta_rev_manager( - &self, - block_d: &str, - pool: Arc, - ) -> FlowyResult { - let user_id = self.grid_user.user_id()?; - let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool)); - let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_d, disk_cache)); - let rev_manager = RevisionManager::new(&user_id, block_d, rev_persistence); - Ok(rev_manager) - } } pub async fn make_grid_view_data( @@ -166,7 +153,6 @@ pub async fn make_grid_view_data( let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, grid_delta_data.clone()).into(); let _ = grid_manager.create_grid(view_id, repeated_revision).await?; - for block_meta_data in build_context.blocks_meta_data { let block_id = block_meta_data.block_id.clone(); diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_editor.rs similarity index 86% rename from frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs rename to frontend/rust-lib/flowy-grid/src/services/block/block_meta_editor.rs index d37c869156..81c23f9c69 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_editor.rs @@ -1,8 +1,8 @@ use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::entities::{CellMeta, GridBlockMetaData, RowMeta, RowMetaChangeset, RowOrder}; +use flowy_grid_data_model::entities::{CellMeta, GridBlockMeta, RowMeta, RowMetaChangeset, RowOrder}; use flowy_revision::{RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder}; -use flowy_sync::client_grid::{GridBlockMetaChange, GridBlockMetaPad}; +use flowy_sync::client_grid::{GridBlockMetaDeltaChangeset, GridBlockMetaPad}; use flowy_sync::entities::revision::Revision; use flowy_sync::util::make_delta_from_revisions; use lib_infra::future::FutureResult; @@ -14,7 +14,7 @@ use tokio::sync::RwLock; pub struct GridBlockMetaEditor { user_id: String, pub block_id: String, - pad: Arc>, + block_meta: Arc>, rev_manager: Arc, } @@ -29,20 +29,20 @@ impl GridBlockMetaEditor { token: token.to_owned(), }); let block_meta_pad = rev_manager.load::(Some(cloud)).await?; - let pad = Arc::new(RwLock::new(block_meta_pad)); + let block_meta = Arc::new(RwLock::new(block_meta_pad)); let rev_manager = Arc::new(rev_manager); let user_id = user_id.to_owned(); let block_id = block_id.to_owned(); Ok(Self { user_id, block_id, - pad, + block_meta, rev_manager, }) } - pub async fn duplicate_block_meta_data(&self, duplicated_block_id: &str) -> GridBlockMetaData { - self.pad.read().await.duplicate_data(duplicated_block_id).await + pub async fn duplicate_block_meta(&self, duplicated_block_id: &str) -> GridBlockMeta { + self.block_meta.read().await.duplicate_data(duplicated_block_id).await } /// return current number of rows and the inserted index. The inserted index will be None if the start_row_id is None @@ -109,7 +109,7 @@ impl GridBlockMetaEditor { where T: AsRef + ToOwned + ?Sized, { - let row_metas = self.pad.read().await.get_row_metas(row_ids)?; + let row_metas = self.block_meta.read().await.get_row_metas(row_ids)?; Ok(row_metas) } @@ -118,7 +118,7 @@ impl GridBlockMetaEditor { field_id: &str, row_ids: Option>>, ) -> FlowyResult> { - let cell_metas = self.pad.read().await.get_cell_metas(field_id, row_ids)?; + let cell_metas = self.block_meta.read().await.get_cell_metas(field_id, row_ids)?; Ok(cell_metas) } @@ -132,7 +132,7 @@ impl GridBlockMetaEditor { T: AsRef + ToOwned + ?Sized, { let row_orders = self - .pad + .block_meta .read() .await .get_row_metas(row_ids)? @@ -144,9 +144,9 @@ impl GridBlockMetaEditor { async fn modify(&self, f: F) -> FlowyResult<()> where - F: for<'a> FnOnce(&'a mut GridBlockMetaPad) -> FlowyResult>, + F: for<'a> FnOnce(&'a mut GridBlockMetaPad) -> FlowyResult>, { - let mut write_guard = self.pad.write().await; + let mut write_guard = self.block_meta.write().await; match f(&mut *write_guard)? { None => {} Some(change) => { @@ -156,8 +156,8 @@ impl GridBlockMetaEditor { Ok(()) } - async fn apply_change(&self, change: GridBlockMetaChange) -> FlowyResult<()> { - let GridBlockMetaChange { delta, md5 } = change; + async fn apply_change(&self, change: GridBlockMetaDeltaChangeset) -> FlowyResult<()> { + let GridBlockMetaDeltaChangeset { delta, md5 } = change; let user_id = self.user_id.clone(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); let delta_data = delta.to_delta_bytes(); diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs similarity index 88% rename from frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs rename to frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs index ec7c47f069..a1d9e27f4a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs @@ -1,13 +1,13 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::manager::GridUser; -use crate::services::block_meta_editor::GridBlockMetaEditor; +use crate::services::block::GridBlockMetaEditor; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::row::{group_row_orders, GridBlockSnapshot}; use dashmap::DashMap; use flowy_error::FlowyResult; use flowy_grid_data_model::entities::{ - CellChangeset, CellMeta, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, IndexRowOrder, Row, RowMeta, - RowMetaChangeset, RowOrder, UpdatedRowOrder, + CellChangeset, CellMeta, GridBlockInfoChangeset, GridBlockMetaSnapshot, GridRowsChangeset, IndexRowOrder, Row, + RowMeta, RowMetaChangeset, RowOrder, UpdatedRowOrder, }; use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; use flowy_revision::{RevisionManager, RevisionPersistence}; @@ -16,19 +16,19 @@ use std::collections::HashMap; use std::sync::Arc; type BlockId = String; -pub(crate) struct GridBlockManager { +pub(crate) struct GridBlockMetaManager { grid_id: String, user: Arc, - persistence: Arc, + block_index_cache: Arc, block_editor_map: DashMap>, } -impl GridBlockManager { +impl GridBlockMetaManager { pub(crate) async fn new( grid_id: &str, user: &Arc, - blocks: Vec, - persistence: Arc, + blocks: Vec, + block_index_cache: Arc, ) -> FlowyResult { let editor_map = make_block_meta_editor_map(user, blocks).await?; let user = user.clone(); @@ -37,7 +37,7 @@ impl GridBlockManager { grid_id, user, block_editor_map: editor_map, - persistence, + block_index_cache, }; Ok(manager) } @@ -57,7 +57,7 @@ impl GridBlockManager { } async fn get_editor_from_row_id(&self, row_id: &str) -> FlowyResult> { - let block_id = self.persistence.get_block_id(row_id)?; + let block_id = self.block_index_cache.get_block_id(row_id)?; Ok(self.get_editor(&block_id).await?) } @@ -67,7 +67,7 @@ impl GridBlockManager { row_meta: RowMeta, start_row_id: Option, ) -> FlowyResult { - let _ = self.persistence.insert(&row_meta.block_id, &row_meta.id)?; + let _ = self.block_index_cache.insert(&row_meta.block_id, &row_meta.id)?; let editor = self.get_editor(&row_meta.block_id).await?; let mut index_row_order = IndexRowOrder::from(&row_meta); @@ -83,21 +83,21 @@ impl GridBlockManager { pub(crate) async fn insert_row( &self, rows_by_block_id: HashMap>, - ) -> FlowyResult> { + ) -> FlowyResult> { let mut changesets = vec![]; for (block_id, row_metas) in rows_by_block_id { let mut inserted_row_orders = vec![]; let editor = self.get_editor(&block_id).await?; let mut row_count = 0; for row in row_metas { - let _ = self.persistence.insert(&row.block_id, &row.id)?; + let _ = self.block_index_cache.insert(&row.block_id, &row.id)?; let mut row_order = IndexRowOrder::from(&row); let (count, index) = editor.create_row(row, None).await?; row_count = count; row_order.index = index; inserted_row_orders.push(row_order); } - changesets.push(GridBlockMetaChangeset::from_row_count(&block_id, row_count)); + changesets.push(GridBlockInfoChangeset::from_row_count(&block_id, row_count)); let _ = self .notify_did_update_block(GridRowsChangeset::insert(&block_id, inserted_row_orders)) @@ -128,7 +128,7 @@ impl GridBlockManager { pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> { let row_id = row_id.to_owned(); - let block_id = self.persistence.get_block_id(&row_id)?; + let block_id = self.block_index_cache.get_block_id(&row_id)?; let editor = self.get_editor(&block_id).await?; match editor.get_row_order(&row_id).await? { None => {} @@ -143,7 +143,7 @@ impl GridBlockManager { Ok(()) } - pub(crate) async fn delete_rows(&self, row_orders: Vec) -> FlowyResult> { + 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?; @@ -153,7 +153,7 @@ impl GridBlockManager { .map(|row_order| Cow::Owned(row_order.row_id)) .collect::>>(); let row_count = editor.delete_rows(row_ids).await?; - let changeset = GridBlockMetaChangeset::from_row_count(&block_order.block_id, row_count); + let changeset = GridBlockInfoChangeset::from_row_count(&block_order.block_id, row_count); changesets.push(changeset); } @@ -255,7 +255,7 @@ impl GridBlockManager { async fn make_block_meta_editor_map( user: &Arc, - blocks: Vec, + blocks: Vec, ) -> FlowyResult>> { let editor_map = DashMap::new(); for block in blocks { @@ -269,11 +269,16 @@ async fn make_block_meta_editor_map( async fn make_block_meta_editor(user: &Arc, block_id: &str) -> FlowyResult { tracing::trace!("Open block:{} meta editor", block_id); let token = user.token()?; + let user_id = user.user_id()?; + let rev_manager = make_grid_block_meta_rev_manager(user, block_id)?; + GridBlockMetaEditor::new(&user_id, &token, block_id, rev_manager).await +} + +pub fn make_grid_block_meta_rev_manager(user: &Arc, block_id: &str) -> FlowyResult { let user_id = user.user_id()?; let pool = user.db_pool()?; let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool)); let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_id, disk_cache)); - let rev_manager = RevisionManager::new(&user_id, block_id, rev_persistence); - GridBlockMetaEditor::new(&user_id, &token, block_id, rev_manager).await + Ok(RevisionManager::new(&user_id, block_id, rev_persistence)) } diff --git a/frontend/rust-lib/flowy-grid/src/services/block/mod.rs b/frontend/rust-lib/flowy-grid/src/services/block/mod.rs new file mode 100644 index 0000000000..f4a110cf63 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/block/mod.rs @@ -0,0 +1,5 @@ +mod block_meta_editor; +mod block_meta_manager; + +pub(crate) use block_meta_editor::*; +pub(crate) use block_meta_manager::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs similarity index 93% rename from frontend/rust-lib/flowy-grid/src/services/grid_editor.rs rename to frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs index 82db6aac1b..d584e1dc31 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs @@ -1,7 +1,7 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::entities::CellIdentifier; use crate::manager::GridUser; -use crate::services::block_meta_manager::GridBlockManager; +use crate::services::block::GridBlockMetaManager; use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder}; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::row::*; @@ -24,7 +24,7 @@ pub struct GridMetaEditor { user: Arc, grid_pad: Arc>, rev_manager: Arc, - block_manager: Arc, + block_meta_manager: Arc, } impl Drop for GridMetaEditor { @@ -47,13 +47,13 @@ impl GridMetaEditor { let grid_pad = Arc::new(RwLock::new(grid_pad)); let blocks = grid_pad.read().await.get_block_metas(); - let block_meta_manager = Arc::new(GridBlockManager::new(grid_id, &user, blocks, persistence).await?); + let block_meta_manager = Arc::new(GridBlockMetaManager::new(grid_id, &user, blocks, persistence).await?); Ok(Arc::new(Self { grid_id: grid_id.to_owned(), user, grid_pad, rev_manager, - block_manager: block_meta_manager, + block_meta_manager, })) } @@ -240,12 +240,12 @@ impl GridMetaEditor { Ok(field_metas) } - pub async fn create_block(&self, grid_block: GridBlockMeta) -> FlowyResult<()> { + pub async fn create_block(&self, grid_block: GridBlockMetaSnapshot) -> FlowyResult<()> { let _ = self.modify(|grid| Ok(grid.create_block_meta(grid_block)?)).await?; Ok(()) } - pub async fn update_block(&self, changeset: GridBlockMetaChangeset) -> FlowyResult<()> { + pub async fn update_block(&self, changeset: GridBlockInfoChangeset) -> FlowyResult<()> { let _ = self.modify(|grid| Ok(grid.update_block_meta(changeset)?)).await?; Ok(()) } @@ -260,10 +260,13 @@ impl GridMetaEditor { let row_order = RowOrder::from(&row_meta); // insert the row - let row_count = self.block_manager.create_row(&block_id, row_meta, start_row_id).await?; + let row_count = self + .block_meta_manager + .create_row(&block_id, row_meta, start_row_id) + .await?; // update block row count - let changeset = GridBlockMetaChangeset::from_row_count(&block_id, row_count); + let changeset = GridBlockInfoChangeset::from_row_count(&block_id, row_count); let _ = self.update_block(changeset).await?; Ok(row_order) } @@ -280,7 +283,7 @@ impl GridMetaEditor { .or_insert_with(Vec::new) .push(row_meta); } - let changesets = self.block_manager.insert_row(rows_by_block_id).await?; + let changesets = self.block_meta_manager.insert_row(rows_by_block_id).await?; for changeset in changesets { let _ = self.update_block(changeset).await?; } @@ -289,7 +292,7 @@ impl GridMetaEditor { pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { let field_metas = self.get_field_metas::(None).await?; - self.block_manager + self.block_meta_manager .update_row(changeset, |row_meta| make_row_from_row_meta(&field_metas, row_meta)) .await } @@ -312,7 +315,7 @@ impl GridMetaEditor { } pub async fn get_row(&self, row_id: &str) -> FlowyResult> { - match self.block_manager.get_row_meta(row_id).await? { + match self.block_meta_manager.get_row_meta(row_id).await? { None => Ok(None), Some(row_meta) => { let field_metas = self.get_field_metas::(None).await?; @@ -324,7 +327,7 @@ impl GridMetaEditor { } } pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> { - let _ = self.block_manager.delete_row(row_id).await?; + let _ = self.block_meta_manager.delete_row(row_id).await?; Ok(()) } @@ -334,12 +337,12 @@ impl GridMetaEditor { pub async fn get_cell(&self, params: &CellIdentifier) -> Option { let field_meta = self.get_field_meta(¶ms.field_id).await?; - let row_meta = self.block_manager.get_row_meta(¶ms.row_id).await.ok()??; + let row_meta = self.block_meta_manager.get_row_meta(¶ms.row_id).await.ok()??; make_cell(¶ms.field_id, &field_meta, &row_meta) } pub async fn get_cell_meta(&self, row_id: &str, field_id: &str) -> FlowyResult> { - let row_meta = self.block_manager.get_row_meta(row_id).await?; + let row_meta = self.block_meta_manager.get_row_meta(row_id).await?; match row_meta { None => Ok(None), Some(row_meta) => { @@ -385,7 +388,7 @@ impl GridMetaEditor { cell_content_changeset, }; let _ = self - .block_manager + .block_meta_manager .update_cell(cell_changeset, |row_meta| { make_row_from_row_meta(&field_metas, row_meta) }) @@ -400,13 +403,13 @@ impl GridMetaEditor { make_grid_blocks(block_ids, block_snapshots) } - pub async fn get_block_metas(&self) -> FlowyResult> { + pub async fn get_block_metas(&self) -> FlowyResult> { let grid_blocks = self.grid_pad.read().await.get_block_metas(); Ok(grid_blocks) } pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { - let changesets = self.block_manager.delete_rows(row_orders).await?; + let changesets = self.block_meta_manager.delete_rows(row_orders).await?; for changeset in changesets { let _ = self.update_block(changeset).await?; } @@ -418,7 +421,7 @@ impl GridMetaEditor { let field_orders = pad_read_guard.get_field_orders(); let mut block_orders = vec![]; for block_order in pad_read_guard.get_block_metas() { - let row_orders = self.block_manager.get_row_orders(&block_order.block_id).await?; + let row_orders = self.block_meta_manager.get_row_orders(&block_order.block_id).await?; let block_order = GridBlockOrder { block_id: block_order.block_id, row_orders, @@ -445,7 +448,7 @@ impl GridMetaEditor { .collect::>(), Some(block_ids) => block_ids, }; - let snapshots = self.block_manager.make_block_snapshots(block_ids).await?; + let snapshots = self.block_meta_manager.make_block_snapshots(block_ids).await?; Ok(snapshots) } @@ -479,7 +482,10 @@ impl GridMetaEditor { } pub async fn move_row(&self, row_id: &str, from: i32, to: i32) -> FlowyResult<()> { - let _ = self.block_manager.move_row(row_id, from as usize, to as usize).await?; + let _ = self + .block_meta_manager + .move_row(row_id, from as usize, to as usize) + .await?; Ok(()) } @@ -495,13 +501,14 @@ impl GridMetaEditor { let mut blocks_meta_data = vec![]; if original_blocks.len() == duplicated_blocks.len() { for (index, original_block_meta) in original_blocks.iter().enumerate() { - let grid_block_meta_editor = self.block_manager.get_editor(&original_block_meta.block_id).await?; + let grid_block_meta_editor = self + .block_meta_manager + .get_editor(&original_block_meta.block_id) + .await?; let duplicated_block_id = &duplicated_blocks[index].block_id; tracing::trace!("Duplicate block:{} meta data", duplicated_block_id); - let duplicated_block_meta_data = grid_block_meta_editor - .duplicate_block_meta_data(duplicated_block_id) - .await; + let duplicated_block_meta_data = grid_block_meta_editor.duplicate_block_meta(duplicated_block_id).await; blocks_meta_data.push(duplicated_block_meta_data); } } else { diff --git a/frontend/rust-lib/flowy-grid/src/services/mod.rs b/frontend/rust-lib/flowy-grid/src/services/mod.rs index c9a8217bd8..69622827bf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/mod.rs @@ -1,8 +1,7 @@ mod util; -pub mod block_meta_editor; -mod block_meta_manager; +pub mod block; pub mod field; -pub mod grid_editor; +pub mod grid_meta_editor; pub mod persistence; pub mod row; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs index 7b210d4f95..63bea4cc3d 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs @@ -7,7 +7,7 @@ use flowy_grid::services::field::{ }; use flowy_grid::services::row::{decode_cell_data_from_type_option_cell_data, CreateRowMetaBuilder}; use flowy_grid_data_model::entities::{ - CellChangeset, FieldChangesetParams, FieldType, GridBlockMeta, GridBlockMetaChangeset, RowMetaChangeset, + CellChangeset, FieldChangesetParams, FieldType, GridBlockInfoChangeset, GridBlockMetaSnapshot, RowMetaChangeset, TypeOptionDataEntry, }; @@ -123,7 +123,7 @@ async fn grid_delete_field() { #[tokio::test] async fn grid_create_block() { - let grid_block = GridBlockMeta::new(); + let grid_block = GridBlockMetaSnapshot::new(); let scripts = vec![ AssertBlockCount(1), CreateBlock { block: grid_block }, @@ -134,9 +134,9 @@ async fn grid_create_block() { #[tokio::test] async fn grid_update_block() { - let grid_block = GridBlockMeta::new(); + let grid_block = GridBlockMetaSnapshot::new(); let mut cloned_grid_block = grid_block.clone(); - let changeset = GridBlockMetaChangeset { + let changeset = GridBlockInfoChangeset { block_id: grid_block.block_id.clone(), start_row_index: Some(2), row_count: Some(10), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs index 37c3b736d4..c1fa47c7a9 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/script.rs @@ -1,10 +1,11 @@ use bytes::Bytes; use flowy_grid::services::field::*; -use flowy_grid::services::grid_editor::{GridMetaEditor, GridPadBuilder}; +use flowy_grid::services::grid_meta_editor::{GridMetaEditor, GridPadBuilder}; use flowy_grid::services::row::CreateRowMetaPayload; use flowy_grid_data_model::entities::{ - BuildGridContext, CellChangeset, Field, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, - GridBlockMetaChangeset, InsertFieldParams, RowMeta, RowMetaChangeset, RowOrder, TypeOptionDataEntry, + BuildGridContext, CellChangeset, Field, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, + GridBlockInfoChangeset, GridBlockMetaSnapshot, InsertFieldParams, RowMeta, RowMetaChangeset, RowOrder, + TypeOptionDataEntry, }; use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; use flowy_sync::client_grid::GridBuilder; @@ -32,10 +33,10 @@ pub enum EditorScript { field_meta: FieldMeta, }, CreateBlock { - block: GridBlockMeta, + block: GridBlockMetaSnapshot, }, UpdateBlock { - changeset: GridBlockMetaChangeset, + changeset: GridBlockInfoChangeset, }, AssertBlockCount(usize), AssertBlock { @@ -45,7 +46,7 @@ pub enum EditorScript { }, AssertBlockEqual { block_index: usize, - block: GridBlockMeta, + block: GridBlockMetaSnapshot, }, CreateEmptyRow, CreateRow { @@ -74,7 +75,7 @@ pub struct GridEditorTest { pub grid_id: String, pub editor: Arc, pub field_metas: Vec, - pub grid_blocks: Vec, + pub grid_blocks: Vec, pub row_metas: Vec>, pub field_count: usize, diff --git a/shared-lib/flowy-grid-data-model/src/entities/meta.rs b/shared-lib/flowy-grid-data-model/src/entities/meta.rs index d62965245b..c48f9864d5 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/meta.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/meta.rs @@ -28,17 +28,17 @@ pub fn gen_field_id() -> String { pub struct GridMeta { pub grid_id: String, pub fields: Vec, - pub blocks: Vec, + pub blocks: Vec, } #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] -pub struct GridBlockMeta { +pub struct GridBlockMetaSnapshot { pub block_id: String, pub start_row_index: i32, pub row_count: i32, } -impl GridBlockMeta { +impl GridBlockMetaSnapshot { pub fn len(&self) -> i32 { self.row_count } @@ -48,22 +48,22 @@ impl GridBlockMeta { } } -impl GridBlockMeta { +impl GridBlockMetaSnapshot { pub fn new() -> Self { - GridBlockMeta { + GridBlockMetaSnapshot { block_id: gen_block_id(), ..Default::default() } } } -pub struct GridBlockMetaChangeset { +pub struct GridBlockInfoChangeset { pub block_id: String, pub start_row_index: Option, pub row_count: Option, } -impl GridBlockMetaChangeset { +impl GridBlockInfoChangeset { pub fn from_row_count(block_id: &str, row_count: i32) -> Self { Self { block_id: block_id.to_string(), @@ -74,7 +74,7 @@ impl GridBlockMetaChangeset { } #[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct GridBlockMetaData { +pub struct GridBlockMeta { pub block_id: String, pub rows: Vec, } @@ -206,8 +206,8 @@ impl CellMeta { #[derive(Clone, Default, Deserialize, Serialize)] pub struct BuildGridContext { pub field_metas: Vec, - pub blocks: Vec, - pub blocks_meta_data: Vec, + pub blocks: Vec, + pub blocks_meta_data: Vec, } impl BuildGridContext { diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs index 175890ad01..25ee1f5471 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs @@ -1,9 +1,7 @@ use crate::entities::revision::{md5, RepeatedRevision, Revision}; use crate::errors::{CollaborateError, CollaborateResult}; use crate::util::{cal_diff, make_delta_from_revisions}; -use flowy_grid_data_model::entities::{ - gen_block_id, gen_row_id, CellMeta, GridBlockMetaData, RowMeta, RowMetaChangeset, -}; +use flowy_grid_data_model::entities::{gen_block_id, gen_row_id, CellMeta, GridBlockMeta, RowMeta, RowMetaChangeset}; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use serde::{Deserialize, Serialize}; use std::borrow::Cow; @@ -24,7 +22,7 @@ pub struct GridBlockMetaPad { } impl GridBlockMetaPad { - pub async fn duplicate_data(&self, duplicated_block_id: &str) -> GridBlockMetaData { + pub async fn duplicate_data(&self, duplicated_block_id: &str) -> GridBlockMeta { let duplicated_rows = self .rows .iter() @@ -35,7 +33,7 @@ impl GridBlockMetaPad { duplicated_row }) .collect::>(); - GridBlockMetaData { + GridBlockMeta { block_id: duplicated_block_id.to_string(), rows: duplicated_rows, } @@ -43,7 +41,7 @@ impl GridBlockMetaPad { pub fn from_delta(delta: GridBlockMetaDelta) -> CollaborateResult { let s = delta.to_str()?; - let meta_data: GridBlockMetaData = serde_json::from_str(&s).map_err(|e| { + let meta_data: GridBlockMeta = serde_json::from_str(&s).map_err(|e| { let msg = format!("Deserialize delta to block meta failed: {}", e); tracing::error!("{}", s); CollaborateError::internal().context(msg) @@ -241,12 +239,12 @@ pub struct GridBlockMetaChange { pub md5: String, } -pub fn make_block_meta_delta(grid_block_meta_data: &GridBlockMetaData) -> GridBlockMetaDelta { +pub fn make_block_meta_delta(grid_block_meta_data: &GridBlockMeta) -> GridBlockMetaDelta { let json = serde_json::to_string(&grid_block_meta_data).unwrap(); PlainTextDeltaBuilder::new().insert(&json).build() } -pub fn make_block_meta_revisions(user_id: &str, grid_block_meta_data: &GridBlockMetaData) -> RepeatedRevision { +pub fn make_block_meta_revisions(user_id: &str, grid_block_meta_data: &GridBlockMeta) -> RepeatedRevision { let delta = make_block_meta_delta(grid_block_meta_data); let bytes = delta.to_delta_bytes(); let revision = Revision::initial_revision(user_id, &grid_block_meta_data.block_id, bytes); @@ -255,7 +253,7 @@ pub fn make_block_meta_revisions(user_id: &str, grid_block_meta_data: &GridBlock impl std::default::Default for GridBlockMetaPad { fn default() -> Self { - let block_meta_data = GridBlockMetaData { + let block_meta_data = GridBlockMeta { block_id: gen_block_id(), rows: vec![], }; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs index 95e707a287..d0da45dc81 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -1,5 +1,5 @@ use crate::errors::{CollaborateError, CollaborateResult}; -use flowy_grid_data_model::entities::{BuildGridContext, FieldMeta, GridBlockMeta, GridBlockMetaData, RowMeta}; +use flowy_grid_data_model::entities::{BuildGridContext, FieldMeta, GridBlockMeta, GridBlockMetaSnapshot, RowMeta}; pub struct GridBuilder { build_context: BuildGridContext, @@ -9,8 +9,8 @@ impl std::default::Default for GridBuilder { fn default() -> Self { let mut build_context = BuildGridContext::new(); - let block_meta = GridBlockMeta::new(); - let block_meta_data = GridBlockMetaData { + let block_meta = GridBlockMetaSnapshot::new(); + let block_meta_data = GridBlockMeta { block_id: block_meta.block_id.clone(), rows: vec![], }; @@ -59,7 +59,7 @@ fn check_rows(fields: &[FieldMeta], rows: &[RowMeta]) -> CollaborateResult<()> { mod tests { use crate::client_grid::{make_block_meta_delta, make_grid_delta, GridBuilder}; - use flowy_grid_data_model::entities::{FieldMeta, FieldType, GridBlockMetaData, GridMeta}; + use flowy_grid_data_model::entities::{FieldMeta, FieldType, GridBlockMeta, GridMeta}; #[test] fn create_default_grid_test() { @@ -82,6 +82,6 @@ mod tests { let _: GridMeta = serde_json::from_str(&grid_meta_delta.to_str().unwrap()).unwrap(); let grid_block_meta_delta = make_block_meta_delta(build_context.blocks_meta_data.first().unwrap()); - let _: GridBlockMetaData = serde_json::from_str(&grid_block_meta_delta.to_str().unwrap()).unwrap(); + let _: GridBlockMeta = serde_json::from_str(&grid_block_meta_delta.to_str().unwrap()).unwrap(); } } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index 0e255f0f12..1d800961e3 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -3,8 +3,8 @@ use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::util::{cal_diff, make_delta_from_revisions}; use bytes::Bytes; use flowy_grid_data_model::entities::{ - gen_block_id, gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, - GridBlockMetaChangeset, GridMeta, + gen_block_id, gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockInfoChangeset, + GridBlockMetaSnapshot, GridMeta, }; use lib_infra::util::move_vec_element; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; @@ -24,7 +24,7 @@ pub trait JsonDeserializer { } impl GridMetaPad { - pub async fn duplicate_grid_meta(&self) -> (Vec, Vec) { + pub async fn duplicate_grid_meta(&self) -> (Vec, Vec) { let fields = self .grid_meta .fields @@ -41,7 +41,7 @@ impl GridMetaPad { duplicated_block.block_id = gen_block_id(); duplicated_block }) - .collect::>(); + .collect::>(); (fields, blocks) } @@ -283,7 +283,7 @@ impl GridMetaPad { } } - pub fn create_block_meta(&mut self, block: GridBlockMeta) -> CollaborateResult> { + pub fn create_block_meta(&mut self, block: GridBlockMetaSnapshot) -> CollaborateResult> { self.modify_grid(|grid_meta| { if grid_meta.blocks.iter().any(|b| b.block_id == block.block_id) { tracing::warn!("Duplicate grid block"); @@ -306,11 +306,11 @@ impl GridMetaPad { }) } - pub fn get_block_metas(&self) -> Vec { + pub fn get_block_metas(&self) -> Vec { self.grid_meta.blocks.clone() } - pub fn update_block_meta(&mut self, changeset: GridBlockMetaChangeset) -> CollaborateResult> { + pub fn update_block_meta(&mut self, changeset: GridBlockInfoChangeset) -> CollaborateResult> { let block_id = changeset.block_id.clone(); self.modify_block(&block_id, |block| { let mut is_changed = None; @@ -368,7 +368,7 @@ impl GridMetaPad { pub fn modify_block(&mut self, block_id: &str, f: F) -> CollaborateResult> where - F: FnOnce(&mut GridBlockMeta) -> CollaborateResult>, + F: FnOnce(&mut GridBlockMetaSnapshot) -> CollaborateResult>, { self.modify_grid( |grid_meta| match grid_meta.blocks.iter().position(|block| block.block_id == block_id) { From f6ade11eb2a4fc00b20fbd609fdb963218a7a403 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 7 Jun 2022 16:38:00 +0800 Subject: [PATCH 003/112] chore: config revision history --- .../down.sql | 2 + .../2022-06-07-071750_revision-history/up.sql | 8 ++ .../rust-lib/flowy-database/src/schema.rs | 11 +++ .../flowy-revision/src/history/mod.rs | 4 + .../flowy-revision/src/history/persistence.rs | 22 ++++++ .../flowy-revision/src/history/rev_history.rs | 78 +++++++++++++++++++ frontend/rust-lib/flowy-revision/src/lib.rs | 1 + .../flowy-revision/src/rev_manager.rs | 6 +- .../src/client_grid/grid_block_meta_pad.rs | 27 +++++-- 9 files changed, 150 insertions(+), 9 deletions(-) create mode 100644 frontend/rust-lib/flowy-database/migrations/2022-06-07-071750_revision-history/down.sql create mode 100644 frontend/rust-lib/flowy-database/migrations/2022-06-07-071750_revision-history/up.sql create mode 100644 frontend/rust-lib/flowy-revision/src/history/mod.rs create mode 100644 frontend/rust-lib/flowy-revision/src/history/persistence.rs create mode 100644 frontend/rust-lib/flowy-revision/src/history/rev_history.rs diff --git a/frontend/rust-lib/flowy-database/migrations/2022-06-07-071750_revision-history/down.sql b/frontend/rust-lib/flowy-database/migrations/2022-06-07-071750_revision-history/down.sql new file mode 100644 index 0000000000..8d9f64d2a7 --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-06-07-071750_revision-history/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE rev_history; \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/migrations/2022-06-07-071750_revision-history/up.sql b/frontend/rust-lib/flowy-database/migrations/2022-06-07-071750_revision-history/up.sql new file mode 100644 index 0000000000..23ada9a2e8 --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-06-07-071750_revision-history/up.sql @@ -0,0 +1,8 @@ +-- Your SQL goes here +CREATE TABLE rev_history ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + object_id TEXT NOT NULL DEFAULT '', + start_rev_id BIGINT NOT NULL DEFAULT 0, + end_rev_id BIGINT NOT NULL DEFAULT 0, + data BLOB NOT NULL DEFAULT (x'') +); \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/src/schema.rs b/frontend/rust-lib/flowy-database/src/schema.rs index 8fddd037e0..b57ff46875 100644 --- a/frontend/rust-lib/flowy-database/src/schema.rs +++ b/frontend/rust-lib/flowy-database/src/schema.rs @@ -57,6 +57,16 @@ table! { } } +table! { + rev_history (id) { + id -> Integer, + object_id -> Text, + start_rev_id -> BigInt, + end_rev_id -> BigInt, + data -> Binary, + } +} + table! { rev_table (id) { id -> Integer, @@ -124,6 +134,7 @@ allow_tables_to_appear_in_same_query!( grid_meta_rev_table, grid_rev_table, kv_table, + rev_history, rev_table, trash_table, user_table, diff --git a/frontend/rust-lib/flowy-revision/src/history/mod.rs b/frontend/rust-lib/flowy-revision/src/history/mod.rs new file mode 100644 index 0000000000..be42f6f9be --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/history/mod.rs @@ -0,0 +1,4 @@ +mod persistence; +mod rev_history; + +pub use rev_history::*; diff --git a/frontend/rust-lib/flowy-revision/src/history/persistence.rs b/frontend/rust-lib/flowy-revision/src/history/persistence.rs new file mode 100644 index 0000000000..c548e04940 --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/history/persistence.rs @@ -0,0 +1,22 @@ +use crate::history::RevisionHistoryDiskCache; +use flowy_error::FlowyError; +use flowy_sync::entities::revision::Revision; + +pub struct SQLiteRevisionHistoryPersistence {} + +impl SQLiteRevisionHistoryPersistence { + pub fn new() -> Self { + Self {} + } +} + +impl RevisionHistoryDiskCache for SQLiteRevisionHistoryPersistence { + type Error = FlowyError; + + fn save_revision(&self, revision: Revision) -> Result<(), Self::Error> { + todo!() + } +} + +struct RevisionHistorySql(); +impl RevisionHistorySql {} diff --git a/frontend/rust-lib/flowy-revision/src/history/rev_history.rs b/frontend/rust-lib/flowy-revision/src/history/rev_history.rs new file mode 100644 index 0000000000..8c0b10e071 --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/history/rev_history.rs @@ -0,0 +1,78 @@ +use crate::history::persistence::SQLiteRevisionHistoryPersistence; +use flowy_error::FlowyError; +use flowy_sync::entities::revision::Revision; +use std::fmt::Debug; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub trait RevisionHistoryDiskCache: Send + Sync { + type Error: Debug; + + fn save_revision(&self, revision: Revision) -> Result<(), Self::Error>; +} + +pub struct RevisionHistory { + config: RevisionHistoryConfig, + checkpoint: Arc>, + disk_cache: Arc>, +} + +impl RevisionHistory { + pub fn new(config: RevisionHistoryConfig) -> Self { + let disk_cache = Arc::new(SQLiteRevisionHistoryPersistence::new()); + let cloned_disk_cache = disk_cache.clone(); + let checkpoint = HistoryCheckpoint::from_config(&config, move |revision| { + let _ = cloned_disk_cache.save_revision(revision); + }); + let checkpoint = Arc::new(RwLock::new(checkpoint)); + + Self { + config, + checkpoint, + disk_cache, + } + } + + pub async fn save_revision(&self, revision: &Revision) { + self.checkpoint.write().await.add_revision(revision); + } +} + +pub struct RevisionHistoryConfig { + check_when_close: bool, + check_interval: i64, +} + +impl std::default::Default for RevisionHistoryConfig { + fn default() -> Self { + Self { + check_when_close: true, + check_interval: 19, + } + } +} + +struct HistoryCheckpoint { + interval: i64, + revisions: Vec, + on_check: Box, +} + +impl HistoryCheckpoint { + fn from_config(config: &RevisionHistoryConfig, on_check: F) -> Self + where + F: Fn(Revision) + Send + Sync + 'static, + { + Self { + interval: config.check_interval, + revisions: vec![], + on_check: Box::new(on_check), + } + } + + fn check(&mut self) -> Revision { + todo!() + } + + fn add_revision(&mut self, revision: &Revision) {} +} diff --git a/frontend/rust-lib/flowy-revision/src/lib.rs b/frontend/rust-lib/flowy-revision/src/lib.rs index 05e60c00e0..6c708afab2 100644 --- a/frontend/rust-lib/flowy-revision/src/lib.rs +++ b/frontend/rust-lib/flowy-revision/src/lib.rs @@ -1,5 +1,6 @@ mod cache; mod conflict_resolve; +mod history; mod rev_manager; mod rev_persistence; mod ws_manager; diff --git a/frontend/rust-lib/flowy-revision/src/rev_manager.rs b/frontend/rust-lib/flowy-revision/src/rev_manager.rs index 68d8db6f27..15f37af456 100644 --- a/frontend/rust-lib/flowy-revision/src/rev_manager.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_manager.rs @@ -1,4 +1,5 @@ use crate::disk::RevisionState; +use crate::history::{RevisionHistory, RevisionHistoryConfig}; use crate::{RevisionPersistence, WSDataProviderDataSource}; use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; @@ -45,7 +46,7 @@ pub struct RevisionManager { user_id: String, rev_id_counter: RevIdCounter, rev_persistence: Arc, - + rev_history: Arc, #[cfg(feature = "flowy_unit_test")] rev_ack_notifier: tokio::sync::broadcast::Sender, } @@ -53,6 +54,8 @@ pub struct RevisionManager { impl RevisionManager { pub fn new(user_id: &str, object_id: &str, rev_persistence: Arc) -> Self { let rev_id_counter = RevIdCounter::new(0); + let rev_history_config = RevisionHistoryConfig::default(); + let rev_history = Arc::new(RevisionHistory::new(rev_history_config)); #[cfg(feature = "flowy_unit_test")] let (revision_ack_notifier, _) = tokio::sync::broadcast::channel(1); @@ -61,6 +64,7 @@ impl RevisionManager { user_id: user_id.to_owned(), rev_id_counter, rev_persistence, + rev_history, #[cfg(feature = "flowy_unit_test")] rev_ack_notifier: revision_ack_notifier, diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs index 25ee1f5471..68c182bcc0 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs @@ -61,7 +61,7 @@ impl GridBlockMetaPad { &mut self, row: RowMeta, start_row_id: Option, - ) -> CollaborateResult> { + ) -> CollaborateResult> { self.modify(|rows| { if let Some(start_row_id) = start_row_id { if !start_row_id.is_empty() { @@ -77,7 +77,10 @@ impl GridBlockMetaPad { }) } - pub fn delete_rows(&mut self, row_ids: Vec>) -> CollaborateResult> { + pub fn delete_rows( + &mut self, + row_ids: Vec>, + ) -> CollaborateResult> { self.modify(|rows| { rows.retain(|row| !row_ids.contains(&Cow::Borrowed(&row.id))); Ok(Some(())) @@ -141,7 +144,10 @@ impl GridBlockMetaPad { .map(|index| index as i32) } - pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult> { + pub fn update_row( + &mut self, + changeset: RowMetaChangeset, + ) -> CollaborateResult> { let row_id = changeset.row_id.clone(); self.modify_row(&row_id, |row| { let mut is_changed = None; @@ -166,7 +172,12 @@ impl GridBlockMetaPad { }) } - pub fn move_row(&mut self, row_id: &str, from: usize, to: usize) -> CollaborateResult> { + pub fn move_row( + &mut self, + row_id: &str, + from: usize, + to: usize, + ) -> CollaborateResult> { self.modify(|row_metas| { if let Some(position) = row_metas.iter().position(|row_meta| row_meta.id == row_id) { debug_assert_eq!(from, position); @@ -179,7 +190,7 @@ impl GridBlockMetaPad { }) } - pub fn modify(&mut self, f: F) -> CollaborateResult> + pub fn modify(&mut self, f: F) -> CollaborateResult> where F: for<'a> FnOnce(&'a mut Vec>) -> CollaborateResult>, { @@ -198,14 +209,14 @@ impl GridBlockMetaPad { // self.delta.to_str().unwrap_or_else(|_| "".to_string()) // ); self.delta = self.delta.compose(&delta)?; - Ok(Some(GridBlockMetaChange { delta, md5: self.md5() })) + Ok(Some(GridBlockMetaDeltaChangeset { delta, md5: self.md5() })) } } } } } - fn modify_row(&mut self, row_id: &str, f: F) -> CollaborateResult> + fn modify_row(&mut self, row_id: &str, f: F) -> CollaborateResult> where F: FnOnce(&mut RowMeta) -> CollaborateResult>, { @@ -233,7 +244,7 @@ impl GridBlockMetaPad { } } -pub struct GridBlockMetaChange { +pub struct GridBlockMetaDeltaChangeset { pub delta: GridBlockMetaDelta, /// md5: the md5 of the grid after applying the change. pub md5: String, From aeb69f307c09f8d98f01544270d4b40a785a12f6 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 9 Jun 2022 20:58:56 +0800 Subject: [PATCH 004/112] chore: write checkpoint in fixed duration --- frontend/rust-lib/flowy-folder/src/manager.rs | 17 +- .../src/services/folder_editor.rs | 8 +- .../src/services/persistence/migration.rs | 2 +- frontend/rust-lib/flowy-grid/src/manager.rs | 12 +- .../src/services/block/block_meta_editor.rs | 7 +- .../src/services/block/block_meta_manager.rs | 19 +- .../src/services/grid_meta_editor.rs | 9 +- ...ev_impl.rs => grid_block_meta_rev_impl.rs} | 1 - .../flowy-revision/src/cache/disk/mod.rs | 4 +- .../flowy-revision/src/history/mod.rs | 1 + .../flowy-revision/src/history/persistence.rs | 51 ++++- .../flowy-revision/src/history/rev_history.rs | 187 ++++++++++++++---- frontend/rust-lib/flowy-revision/src/lib.rs | 1 + .../flowy-revision/src/rev_manager.rs | 43 +++- .../flowy-revision/src/rev_persistence.rs | 12 +- .../rust-lib/flowy-revision/src/ws_manager.rs | 1 - .../rust-lib/flowy-text-block/src/manager.rs | 20 +- .../rust-lib/flowy-text-block/src/queue.rs | 5 +- .../src/client_grid/grid_meta_pad.rs | 7 +- 19 files changed, 299 insertions(+), 108 deletions(-) rename frontend/rust-lib/flowy-revision/src/cache/disk/{grid_meta_rev_impl.rs => grid_block_meta_rev_impl.rs} (99%) diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 3181c14625..035555576a 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -11,11 +11,12 @@ use crate::{ use bytes::Bytes; use flowy_sync::client_document::default::{initial_quill_delta_string, initial_read_me}; +use crate::services::folder_editor::FolderRevisionCompactor; use flowy_error::FlowyError; use flowy_folder_data_model::entities::view::ViewDataType; use flowy_folder_data_model::user_default; use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; -use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket}; +use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionHistoryPersistence}; use flowy_sync::{client_folder::FolderPad, entities::ws_data::ServerRevisionWSData}; use lazy_static::lazy_static; use lib_infra::future::FutureResult; @@ -162,9 +163,17 @@ impl FolderManager { let _ = self.persistence.initialize(user_id, &folder_id).await?; let pool = self.persistence.db_pool()?; - let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool)); - let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache)); - let rev_manager = RevisionManager::new(user_id, folder_id.as_ref(), rev_persistence); + let disk_cache = SQLiteTextBlockRevisionPersistence::new(user_id, pool.clone()); + let rev_persistence = RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache); + let rev_compactor = FolderRevisionCompactor(); + let history_persistence = SQLiteRevisionHistoryPersistence::new(pool); + let rev_manager = RevisionManager::new( + user_id, + folder_id.as_ref(), + rev_persistence, + rev_compactor, + history_persistence, + ); let folder_editor = FolderEditor::new(user_id, &folder_id, token, rev_manager, self.web_socket.clone()).await?; *self.folder_editor.write().await = Some(Arc::new(folder_editor)); diff --git a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs index ef94c1d316..6661530213 100644 --- a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs +++ b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs @@ -91,11 +91,7 @@ impl FolderEditor { &self.user_id, md5, ); - let _ = futures::executor::block_on(async { - self.rev_manager - .add_local_revision(&revision, Box::new(FolderRevisionCompactor())) - .await - })?; + let _ = futures::executor::block_on(async { self.rev_manager.add_local_revision(&revision).await })?; Ok(()) } @@ -135,7 +131,7 @@ impl FolderEditor { } } -struct FolderRevisionCompactor(); +pub struct FolderRevisionCompactor(); impl RevisionCompactor for FolderRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs index bc8838059a..ee8731c870 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/migration.rs @@ -88,7 +88,7 @@ impl FolderMigration { return Ok(None); } let pool = self.database.db_pool()?; - let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool)); + let disk_cache = SQLiteTextBlockRevisionPersistence::new(user_id, pool); let rev_persistence = Arc::new(RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache)); let (revisions, _) = RevisionLoader { object_id: folder_id.as_ref().to_owned(), diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 08d9559d41..8d8171ee02 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -1,5 +1,5 @@ use crate::services::block::make_grid_block_meta_rev_manager; -use crate::services::grid_meta_editor::GridMetaEditor; +use crate::services::grid_meta_editor::{GridMetaEditor, GridMetaRevisionCompactor}; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::persistence::kv::GridKVPersistence; use crate::services::persistence::GridDatabase; @@ -9,7 +9,7 @@ use flowy_database::ConnectionPool; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{BuildGridContext, GridMeta}; use flowy_revision::disk::SQLiteGridRevisionPersistence; -use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket}; +use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionHistoryPersistence}; use flowy_sync::client_grid::{make_block_meta_delta, make_grid_delta}; use flowy_sync::entities::revision::{RepeatedRevision, Revision}; use std::sync::Arc; @@ -128,9 +128,11 @@ impl GridManager { pub fn make_grid_rev_manager(&self, grid_id: &str, pool: Arc) -> FlowyResult { let user_id = self.grid_user.user_id()?; - let disk_cache = Arc::new(SQLiteGridRevisionPersistence::new(&user_id, pool)); - let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, grid_id, disk_cache)); - let rev_manager = RevisionManager::new(&user_id, grid_id, rev_persistence); + let disk_cache = SQLiteGridRevisionPersistence::new(&user_id, pool.clone()); + let rev_persistence = RevisionPersistence::new(&user_id, grid_id, disk_cache); + let history_persistence = SQLiteRevisionHistoryPersistence::new(pool); + let rev_compactor = GridMetaRevisionCompactor(); + let rev_manager = RevisionManager::new(&user_id, grid_id, rev_persistence, rev_compactor, history_persistence); Ok(rev_manager) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/block/block_meta_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_editor.rs index 81c23f9c69..ee43aebf10 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block/block_meta_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_editor.rs @@ -169,10 +169,7 @@ impl GridBlockMetaEditor { &user_id, md5, ); - let _ = self - .rev_manager - .add_local_revision(&revision, Box::new(GridBlockMetaRevisionCompactor())) - .await?; + let _ = self.rev_manager.add_local_revision(&revision).await?; Ok(()) } } @@ -199,7 +196,7 @@ impl RevisionObjectBuilder for GridBlockMetaPadBuilder { } } -struct GridBlockMetaRevisionCompactor(); +pub struct GridBlockMetaRevisionCompactor(); impl RevisionCompactor for GridBlockMetaRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; diff --git a/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs index a1d9e27f4a..417c158cff 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs @@ -1,6 +1,6 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::manager::GridUser; -use crate::services::block::GridBlockMetaEditor; +use crate::services::block::{GridBlockMetaEditor, GridBlockMetaRevisionCompactor}; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::row::{group_row_orders, GridBlockSnapshot}; use dashmap::DashMap; @@ -10,7 +10,7 @@ use flowy_grid_data_model::entities::{ RowMeta, RowMetaChangeset, RowOrder, UpdatedRowOrder, }; use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; -use flowy_revision::{RevisionManager, RevisionPersistence}; +use flowy_revision::{RevisionManager, RevisionPersistence, SQLiteRevisionHistoryPersistence}; use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; @@ -278,7 +278,16 @@ pub fn make_grid_block_meta_rev_manager(user: &Arc, block_id: &str let user_id = user.user_id()?; let pool = user.db_pool()?; - let disk_cache = Arc::new(SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool)); - let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, block_id, disk_cache)); - Ok(RevisionManager::new(&user_id, block_id, rev_persistence)) + let disk_cache = SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool.clone()); + let rev_persistence = RevisionPersistence::new(&user_id, block_id, disk_cache); + let rev_compactor = GridBlockMetaRevisionCompactor(); + let history_persistence = SQLiteRevisionHistoryPersistence::new(pool); + + Ok(RevisionManager::new( + &user_id, + block_id, + rev_persistence, + rev_compactor, + history_persistence, + )) } diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs index d584e1dc31..4f4b21ad4c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_meta_editor.rs @@ -547,10 +547,7 @@ impl GridMetaEditor { &user_id, md5, ); - let _ = self - .rev_manager - .add_local_revision(&revision, Box::new(GridRevisionCompactor())) - .await?; + let _ = self.rev_manager.add_local_revision(&revision).await?; Ok(()) } @@ -629,8 +626,8 @@ impl RevisionCloudService for GridRevisionCloudService { } } -struct GridRevisionCompactor(); -impl RevisionCompactor for GridRevisionCompactor { +pub struct GridMetaRevisionCompactor(); +impl RevisionCompactor for GridMetaRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; Ok(delta.to_delta_bytes()) diff --git a/frontend/rust-lib/flowy-revision/src/cache/disk/grid_meta_rev_impl.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/grid_block_meta_rev_impl.rs similarity index 99% rename from frontend/rust-lib/flowy-revision/src/cache/disk/grid_meta_rev_impl.rs rename to frontend/rust-lib/flowy-revision/src/cache/disk/grid_block_meta_rev_impl.rs index e850119c30..93af25e7ca 100644 --- a/frontend/rust-lib/flowy-revision/src/cache/disk/grid_meta_rev_impl.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/grid_block_meta_rev_impl.rs @@ -1,6 +1,5 @@ use crate::cache::disk::RevisionDiskCache; use crate::disk::{RevisionChangeset, RevisionRecord, RevisionState}; - use bytes::Bytes; use diesel::{sql_types::Integer, update, SqliteConnection}; use flowy_database::{ diff --git a/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs index 945c6d707f..814b591f15 100644 --- a/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs @@ -1,10 +1,10 @@ mod folder_rev_impl; -mod grid_meta_rev_impl; +mod grid_block_meta_rev_impl; mod grid_rev_impl; mod text_rev_impl; pub use folder_rev_impl::*; -pub use grid_meta_rev_impl::*; +pub use grid_block_meta_rev_impl::*; pub use grid_rev_impl::*; pub use text_rev_impl::*; diff --git a/frontend/rust-lib/flowy-revision/src/history/mod.rs b/frontend/rust-lib/flowy-revision/src/history/mod.rs index be42f6f9be..9de42831ed 100644 --- a/frontend/rust-lib/flowy-revision/src/history/mod.rs +++ b/frontend/rust-lib/flowy-revision/src/history/mod.rs @@ -1,4 +1,5 @@ mod persistence; mod rev_history; +pub use persistence::*; pub use rev_history::*; diff --git a/frontend/rust-lib/flowy-revision/src/history/persistence.rs b/frontend/rust-lib/flowy-revision/src/history/persistence.rs index c548e04940..01d22fe6a4 100644 --- a/frontend/rust-lib/flowy-revision/src/history/persistence.rs +++ b/frontend/rust-lib/flowy-revision/src/history/persistence.rs @@ -1,22 +1,59 @@ use crate::history::RevisionHistoryDiskCache; -use flowy_error::FlowyError; +use diesel::{sql_types::Integer, update, SqliteConnection}; +use flowy_database::{ + prelude::*, + schema::{rev_history, rev_history::dsl}, + ConnectionPool, +}; +use flowy_error::{FlowyError, FlowyResult}; use flowy_sync::entities::revision::Revision; +use std::sync::Arc; -pub struct SQLiteRevisionHistoryPersistence {} +pub struct SQLiteRevisionHistoryPersistence { + pool: Arc, +} impl SQLiteRevisionHistoryPersistence { - pub fn new() -> Self { - Self {} + pub fn new(pool: Arc) -> Self { + Self { pool } } } impl RevisionHistoryDiskCache for SQLiteRevisionHistoryPersistence { - type Error = FlowyError; + fn save_revision(&self, revision: Revision) -> FlowyResult<()> { + todo!() + } - fn save_revision(&self, revision: Revision) -> Result<(), Self::Error> { + fn read_revision(&self, rev_id: i64) -> FlowyResult { + todo!() + } + + fn clear(&self) -> FlowyResult<()> { todo!() } } struct RevisionHistorySql(); -impl RevisionHistorySql {} +impl RevisionHistorySql { + fn read_revision(object_id: &str, rev_id: i64, conn: &SqliteConnection) -> Result { + let records: Vec = dsl::rev_history + .filter(dsl::start_rev_id.lt(rev_id)) + .filter(dsl::end_rev_id.ge(rev_id)) + .filter(dsl::object_id.eq(object_id)) + .load::(conn)?; + + debug_assert_eq!(records.len(), 1); + + todo!() + } +} + +#[derive(PartialEq, Clone, Debug, Queryable, Identifiable, Insertable, Associations)] +#[table_name = "rev_history"] +struct RevisionRecord { + id: i32, + object_id: String, + start_rev_id: i64, + end_rev_id: i64, + data: Vec, +} diff --git a/frontend/rust-lib/flowy-revision/src/history/rev_history.rs b/frontend/rust-lib/flowy-revision/src/history/rev_history.rs index 8c0b10e071..faa35a9ede 100644 --- a/frontend/rust-lib/flowy-revision/src/history/rev_history.rs +++ b/frontend/rust-lib/flowy-revision/src/history/rev_history.rs @@ -1,78 +1,195 @@ use crate::history::persistence::SQLiteRevisionHistoryPersistence; -use flowy_error::FlowyError; +use crate::RevisionCompactor; +use async_stream::stream; +use flowy_database::ConnectionPool; +use flowy_error::{FlowyError, FlowyResult}; use flowy_sync::entities::revision::Revision; +use futures_util::future::BoxFuture; +use futures_util::stream::StreamExt; +use futures_util::FutureExt; use std::fmt::Debug; use std::sync::Arc; -use tokio::sync::RwLock; +use std::time::Duration; +use tokio::sync::mpsc::error::SendError; +use tokio::sync::mpsc::Sender; +use tokio::sync::{mpsc, oneshot, RwLock}; +use tokio::time::interval; pub trait RevisionHistoryDiskCache: Send + Sync { - type Error: Debug; + fn save_revision(&self, revision: Revision) -> FlowyResult<()>; - fn save_revision(&self, revision: Revision) -> Result<(), Self::Error>; + fn read_revision(&self, rev_id: i64) -> FlowyResult; + + fn clear(&self) -> FlowyResult<()>; } pub struct RevisionHistory { + stop_timer: mpsc::Sender<()>, config: RevisionHistoryConfig, - checkpoint: Arc>, - disk_cache: Arc>, + revisions: Arc>>, + disk_cache: Arc, } impl RevisionHistory { - pub fn new(config: RevisionHistoryConfig) -> Self { - let disk_cache = Arc::new(SQLiteRevisionHistoryPersistence::new()); + pub fn new( + user_id: &str, + object_id: &str, + config: RevisionHistoryConfig, + disk_cache: Arc, + rev_compactor: Arc, + ) -> Self { + let user_id = user_id.to_string(); + let object_id = object_id.to_string(); let cloned_disk_cache = disk_cache.clone(); - let checkpoint = HistoryCheckpoint::from_config(&config, move |revision| { - let _ = cloned_disk_cache.save_revision(revision); - }); - let checkpoint = Arc::new(RwLock::new(checkpoint)); + let (stop_timer, stop_rx) = mpsc::channel(1); + let (checkpoint_tx, checkpoint_rx) = mpsc::channel(1); + let revisions = Arc::new(RwLock::new(vec![])); + let fix_duration_checkpoint_tx = FixedDurationCheckpointSender { + user_id, + object_id, + checkpoint_tx, + disk_cache: cloned_disk_cache, + revisions: revisions.clone(), + rev_compactor, + duration: config.check_duration, + }; + + tokio::spawn(CheckpointRunner::new(stop_rx, checkpoint_rx).run()); + tokio::spawn(fix_duration_checkpoint_tx.run()); Self { + stop_timer, config, - checkpoint, + revisions, disk_cache, } } - pub async fn save_revision(&self, revision: &Revision) { - self.checkpoint.write().await.add_revision(revision); + pub async fn add_revision(&self, revision: &Revision) { + self.revisions.write().await.push(revision.clone()); + } + + pub async fn reset_history(&self) { + self.revisions.write().await.clear(); + match self.disk_cache.clear() { + Ok(_) => {} + Err(e) => tracing::error!("Clear history failed: {:?}", e), + } } } pub struct RevisionHistoryConfig { - check_when_close: bool, - check_interval: i64, + check_duration: Duration, } impl std::default::Default for RevisionHistoryConfig { fn default() -> Self { Self { - check_when_close: true, - check_interval: 19, + check_duration: Duration::from_secs(5), } } } +struct CheckpointRunner { + stop_rx: Option>, + checkpoint_rx: Option>, +} + +impl CheckpointRunner { + fn new(stop_rx: mpsc::Receiver<()>, checkpoint_rx: mpsc::Receiver) -> Self { + Self { + stop_rx: Some(stop_rx), + checkpoint_rx: Some(checkpoint_rx), + } + } + + async fn run(mut self) { + let mut stop_rx = self.stop_rx.take().expect("It should only run once"); + let mut checkpoint_rx = self.checkpoint_rx.take().expect("It should only run once"); + let stream = stream! { + loop { + tokio::select! { + result = checkpoint_rx.recv() => { + match result { + Some(checkpoint) => yield checkpoint, + None => {}, + } + }, + _ = stop_rx.recv() => { + tracing::trace!("Checkpoint runner exit"); + break + }, + }; + } + }; + + stream + .for_each(|checkpoint| async move { + checkpoint.write().await; + }) + .await; + } +} + struct HistoryCheckpoint { - interval: i64, + user_id: String, + object_id: String, revisions: Vec, - on_check: Box, + disk_cache: Arc, + rev_compactor: Arc, } impl HistoryCheckpoint { - fn from_config(config: &RevisionHistoryConfig, on_check: F) -> Self - where - F: Fn(Revision) + Send + Sync + 'static, - { - Self { - interval: config.check_interval, - revisions: vec![], - on_check: Box::new(on_check), + async fn write(self) { + if self.revisions.is_empty() { + return; + } + + let result = || { + let revision = self + .rev_compactor + .compact(&self.user_id, &self.object_id, self.revisions)?; + let _ = self.disk_cache.save_revision(revision)?; + Ok::<(), FlowyError>(()) + }; + + match result() { + Ok(_) => {} + Err(e) => tracing::error!("Write history checkout failed: {:?}", e), } } - - fn check(&mut self) -> Revision { - todo!() - } - - fn add_revision(&mut self, revision: &Revision) {} +} + +struct FixedDurationCheckpointSender { + user_id: String, + object_id: String, + checkpoint_tx: mpsc::Sender, + disk_cache: Arc, + revisions: Arc>>, + rev_compactor: Arc, + duration: Duration, +} + +impl FixedDurationCheckpointSender { + fn run(self) -> BoxFuture<'static, ()> { + async move { + let mut interval = interval(self.duration); + let checkpoint_revisions: Vec = revisions.write().await.drain(..).collect(); + let checkpoint = HistoryCheckpoint { + user_id: self.user_id.clone(), + object_id: self.object_id.clone(), + revisions: checkpoint_revisions, + disk_cache: self.disk_cache.clone(), + rev_compactor: self.rev_compactor.clone(), + }; + match checkpoint_tx.send(checkpoint).await { + Ok(_) => { + interval.tick().await; + self.run(); + } + Err(_) => {} + } + } + .boxed() + } } diff --git a/frontend/rust-lib/flowy-revision/src/lib.rs b/frontend/rust-lib/flowy-revision/src/lib.rs index 6c708afab2..14f00568f2 100644 --- a/frontend/rust-lib/flowy-revision/src/lib.rs +++ b/frontend/rust-lib/flowy-revision/src/lib.rs @@ -7,6 +7,7 @@ mod ws_manager; pub use cache::*; pub use conflict_resolve::*; +pub use history::*; pub use rev_manager::*; pub use rev_persistence::*; pub use ws_manager::*; diff --git a/frontend/rust-lib/flowy-revision/src/rev_manager.rs b/frontend/rust-lib/flowy-revision/src/rev_manager.rs index 15f37af456..bed942b7b4 100644 --- a/frontend/rust-lib/flowy-revision/src/rev_manager.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_manager.rs @@ -1,5 +1,5 @@ use crate::disk::RevisionState; -use crate::history::{RevisionHistory, RevisionHistoryConfig}; +use crate::history::{RevisionHistory, RevisionHistoryConfig, RevisionHistoryDiskCache}; use crate::{RevisionPersistence, WSDataProviderDataSource}; use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; @@ -47,15 +47,36 @@ pub struct RevisionManager { rev_id_counter: RevIdCounter, rev_persistence: Arc, rev_history: Arc, + rev_compactor: Arc, #[cfg(feature = "flowy_unit_test")] rev_ack_notifier: tokio::sync::broadcast::Sender, } impl RevisionManager { - pub fn new(user_id: &str, object_id: &str, rev_persistence: Arc) -> Self { + pub fn new( + user_id: &str, + object_id: &str, + rev_persistence: RevisionPersistence, + rev_compactor: C, + history_persistence: P, + ) -> Self + where + P: 'static + RevisionHistoryDiskCache, + C: 'static + RevisionCompactor, + { let rev_id_counter = RevIdCounter::new(0); + let rev_compactor = Arc::new(rev_compactor); + let history_persistence = Arc::new(history_persistence); let rev_history_config = RevisionHistoryConfig::default(); - let rev_history = Arc::new(RevisionHistory::new(rev_history_config)); + let rev_persistence = Arc::new(rev_persistence); + + let rev_history = Arc::new(RevisionHistory::new( + user_id, + object_id, + rev_history_config, + history_persistence, + rev_compactor.clone(), + )); #[cfg(feature = "flowy_unit_test")] let (revision_ack_notifier, _) = tokio::sync::broadcast::channel(1); @@ -65,7 +86,7 @@ impl RevisionManager { rev_id_counter, rev_persistence, rev_history, - + rev_compactor, #[cfg(feature = "flowy_unit_test")] rev_ack_notifier: revision_ack_notifier, } @@ -93,6 +114,7 @@ impl RevisionManager { pub async fn reset_object(&self, revisions: RepeatedRevision) -> FlowyResult<()> { let rev_id = pair_rev_id_from_revisions(&revisions).1; let _ = self.rev_persistence.reset(revisions.into_inner()).await?; + self.rev_history.reset_history().await; self.rev_id_counter.set(rev_id); Ok(()) } @@ -104,20 +126,21 @@ impl RevisionManager { } let _ = self.rev_persistence.add_ack_revision(revision).await?; + self.rev_history.add_revision(revision).await; self.rev_id_counter.set(revision.rev_id); Ok(()) } #[tracing::instrument(level = "debug", skip_all, err)] - pub async fn add_local_revision<'a>( - &'a self, - revision: &Revision, - compactor: Box, - ) -> Result<(), FlowyError> { + pub async fn add_local_revision(&self, revision: &Revision) -> Result<(), FlowyError> { if revision.delta_data.is_empty() { return Err(FlowyError::internal().context("Delta data should be empty")); } - let rev_id = self.rev_persistence.add_sync_revision(revision, compactor).await?; + let rev_id = self + .rev_persistence + .add_sync_revision(revision, &self.rev_compactor) + .await?; + self.rev_history.add_revision(revision).await; self.rev_id_counter.set(rev_id); Ok(()) } diff --git a/frontend/rust-lib/flowy-revision/src/rev_persistence.rs b/frontend/rust-lib/flowy-revision/src/rev_persistence.rs index 6412b26ec6..98bc89ba24 100644 --- a/frontend/rust-lib/flowy-revision/src/rev_persistence.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_persistence.rs @@ -24,13 +24,13 @@ pub struct RevisionPersistence { } impl RevisionPersistence { - pub fn new( - user_id: &str, - object_id: &str, - disk_cache: Arc>, - ) -> RevisionPersistence { + pub fn new(user_id: &str, object_id: &str, disk_cache: C) -> RevisionPersistence + where + C: 'static + RevisionDiskCache, + { let object_id = object_id.to_owned(); let user_id = user_id.to_owned(); + let disk_cache = Arc::new(disk_cache) as Arc>; let sync_seq = RwLock::new(RevisionSyncSequence::new()); let memory_cache = Arc::new(RevisionMemoryCache::new(&object_id, Arc::new(disk_cache.clone()))); Self { @@ -63,7 +63,7 @@ impl RevisionPersistence { pub(crate) async fn add_sync_revision<'a>( &'a self, revision: &'a Revision, - compactor: Box, + compactor: &Arc, ) -> FlowyResult { let result = self.sync_seq.read().await.compact(); match result { diff --git a/frontend/rust-lib/flowy-revision/src/ws_manager.rs b/frontend/rust-lib/flowy-revision/src/ws_manager.rs index 42ad39c617..eb7539c380 100644 --- a/frontend/rust-lib/flowy-revision/src/ws_manager.rs +++ b/frontend/rust-lib/flowy-revision/src/ws_manager.rs @@ -1,6 +1,5 @@ use crate::ConflictRevisionSink; use async_stream::stream; - use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; use flowy_sync::entities::{ diff --git a/frontend/rust-lib/flowy-text-block/src/manager.rs b/frontend/rust-lib/flowy-text-block/src/manager.rs index 9325fe6001..a6cdda1220 100644 --- a/frontend/rust-lib/flowy-text-block/src/manager.rs +++ b/frontend/rust-lib/flowy-text-block/src/manager.rs @@ -1,10 +1,13 @@ +use crate::queue::TextBlockRevisionCompactor; use crate::{editor::TextBlockEditor, errors::FlowyError, BlockCloudService}; use bytes::Bytes; use dashmap::DashMap; use flowy_database::ConnectionPool; use flowy_error::FlowyResult; use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; -use flowy_revision::{RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket}; +use flowy_revision::{ + RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionHistoryPersistence, +}; use flowy_sync::entities::{ revision::{md5, RepeatedRevision, Revision}, text_block_info::{TextBlockDelta, TextBlockId}, @@ -139,9 +142,18 @@ impl TextBlockManager { fn make_rev_manager(&self, doc_id: &str, pool: Arc) -> Result { let user_id = self.user.user_id()?; - let disk_cache = Arc::new(SQLiteTextBlockRevisionPersistence::new(&user_id, pool)); - let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, doc_id, disk_cache)); - Ok(RevisionManager::new(&user_id, doc_id, rev_persistence)) + let disk_cache = SQLiteTextBlockRevisionPersistence::new(&user_id, pool.clone()); + let rev_persistence = RevisionPersistence::new(&user_id, doc_id, disk_cache); + let history_persistence = SQLiteRevisionHistoryPersistence::new(pool); + let rev_compactor = TextBlockRevisionCompactor(); + + Ok(RevisionManager::new( + &user_id, + doc_id, + rev_persistence, + rev_compactor, + history_persistence, + )) } } diff --git a/frontend/rust-lib/flowy-text-block/src/queue.rs b/frontend/rust-lib/flowy-text-block/src/queue.rs index 7c11afd0ff..343ad11e7b 100644 --- a/frontend/rust-lib/flowy-text-block/src/queue.rs +++ b/frontend/rust-lib/flowy-text-block/src/queue.rs @@ -186,10 +186,7 @@ impl EditBlockQueue { &user_id, md5, ); - let _ = self - .rev_manager - .add_local_revision(&revision, Box::new(TextBlockRevisionCompactor())) - .await?; + let _ = self.rev_manager.add_local_revision(&revision).await?; Ok(rev_id.into()) } } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index 1d800961e3..3ef9251e4a 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -25,12 +25,7 @@ pub trait JsonDeserializer { impl GridMetaPad { pub async fn duplicate_grid_meta(&self) -> (Vec, Vec) { - let fields = self - .grid_meta - .fields - .iter() - .map(|field| field.clone()) - .collect::>(); + let fields = self.grid_meta.fields.to_vec(); let blocks = self .grid_meta From d5eabe4ea3ac74aa033c2721664ae3ab882a7906 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 10 Jun 2022 22:27:19 +0800 Subject: [PATCH 005/112] chore: add snapshot --- .../down.sql | 2 + .../up.sql | 7 ++ .../rust-lib/flowy-database/src/schema.rs | 10 ++ frontend/rust-lib/flowy-folder/src/manager.rs | 12 ++- frontend/rust-lib/flowy-grid/src/manager.rs | 17 +++- .../src/services/block/block_meta_manager.rs | 9 +- .../src/cache/disk/grid_rev_impl.rs | 1 - .../flowy-revision/src/history/persistence.rs | 69 +++++++++----- .../flowy-revision/src/history/rev_history.rs | 94 ++++++++++--------- frontend/rust-lib/flowy-revision/src/lib.rs | 2 + .../flowy-revision/src/rev_manager.rs | 22 +++-- .../flowy-revision/src/snapshot/mod.rs | 5 + .../src/snapshot/persistence.rs | 28 ++++++ .../src/snapshot/rev_snapshot.rs | 29 ++++++ .../rust-lib/flowy-text-block/src/manager.rs | 5 +- 15 files changed, 225 insertions(+), 87 deletions(-) create mode 100644 frontend/rust-lib/flowy-database/migrations/2022-06-10-140131_revision-snapshot/down.sql create mode 100644 frontend/rust-lib/flowy-database/migrations/2022-06-10-140131_revision-snapshot/up.sql create mode 100644 frontend/rust-lib/flowy-revision/src/snapshot/mod.rs create mode 100644 frontend/rust-lib/flowy-revision/src/snapshot/persistence.rs create mode 100644 frontend/rust-lib/flowy-revision/src/snapshot/rev_snapshot.rs diff --git a/frontend/rust-lib/flowy-database/migrations/2022-06-10-140131_revision-snapshot/down.sql b/frontend/rust-lib/flowy-database/migrations/2022-06-10-140131_revision-snapshot/down.sql new file mode 100644 index 0000000000..01a87a1e99 --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-06-10-140131_revision-snapshot/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE rev_snapshot; \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/migrations/2022-06-10-140131_revision-snapshot/up.sql b/frontend/rust-lib/flowy-database/migrations/2022-06-10-140131_revision-snapshot/up.sql new file mode 100644 index 0000000000..9656dabc3c --- /dev/null +++ b/frontend/rust-lib/flowy-database/migrations/2022-06-10-140131_revision-snapshot/up.sql @@ -0,0 +1,7 @@ +-- Your SQL goes here +CREATE TABLE rev_snapshot ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + object_id TEXT NOT NULL DEFAULT '', + rev_id BIGINT NOT NULL DEFAULT 0, + data BLOB NOT NULL DEFAULT (x'') +); \ No newline at end of file diff --git a/frontend/rust-lib/flowy-database/src/schema.rs b/frontend/rust-lib/flowy-database/src/schema.rs index b57ff46875..ee81806ccf 100644 --- a/frontend/rust-lib/flowy-database/src/schema.rs +++ b/frontend/rust-lib/flowy-database/src/schema.rs @@ -67,6 +67,15 @@ table! { } } +table! { + rev_snapshot (id) { + id -> Integer, + object_id -> Text, + rev_id -> BigInt, + data -> Binary, + } +} + table! { rev_table (id) { id -> Integer, @@ -135,6 +144,7 @@ allow_tables_to_appear_in_same_query!( grid_rev_table, kv_table, rev_history, + rev_snapshot, rev_table, trash_table, user_table, diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 035555576a..557f0e7cf6 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -16,7 +16,10 @@ use flowy_error::FlowyError; use flowy_folder_data_model::entities::view::ViewDataType; use flowy_folder_data_model::user_default; use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; -use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionHistoryPersistence}; +use flowy_revision::{ + RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionHistoryPersistence, + SQLiteRevisionSnapshotPersistence, +}; use flowy_sync::{client_folder::FolderPad, entities::ws_data::ServerRevisionWSData}; use lazy_static::lazy_static; use lib_infra::future::FutureResult; @@ -163,16 +166,19 @@ impl FolderManager { let _ = self.persistence.initialize(user_id, &folder_id).await?; let pool = self.persistence.db_pool()?; + let object_id = folder_id.as_ref(); let disk_cache = SQLiteTextBlockRevisionPersistence::new(user_id, pool.clone()); - let rev_persistence = RevisionPersistence::new(user_id, folder_id.as_ref(), disk_cache); + let rev_persistence = RevisionPersistence::new(user_id, object_id, disk_cache); let rev_compactor = FolderRevisionCompactor(); - let history_persistence = SQLiteRevisionHistoryPersistence::new(pool); + let history_persistence = SQLiteRevisionHistoryPersistence::new(object_id, pool.clone()); + let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(object_id, pool); let rev_manager = RevisionManager::new( user_id, folder_id.as_ref(), rev_persistence, rev_compactor, history_persistence, + snapshot_persistence, ); let folder_editor = FolderEditor::new(user_id, &folder_id, token, rev_manager, self.web_socket.clone()).await?; diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 8d8171ee02..1a1d6ff91e 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -9,7 +9,10 @@ use flowy_database::ConnectionPool; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{BuildGridContext, GridMeta}; use flowy_revision::disk::SQLiteGridRevisionPersistence; -use flowy_revision::{RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionHistoryPersistence}; +use flowy_revision::{ + RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionHistoryPersistence, + SQLiteRevisionSnapshotPersistence, +}; use flowy_sync::client_grid::{make_block_meta_delta, make_grid_delta}; use flowy_sync::entities::revision::{RepeatedRevision, Revision}; use std::sync::Arc; @@ -130,9 +133,17 @@ impl GridManager { let disk_cache = SQLiteGridRevisionPersistence::new(&user_id, pool.clone()); let rev_persistence = RevisionPersistence::new(&user_id, grid_id, disk_cache); - let history_persistence = SQLiteRevisionHistoryPersistence::new(pool); + let history_persistence = SQLiteRevisionHistoryPersistence::new(grid_id, pool.clone()); + let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(grid_id, pool); let rev_compactor = GridMetaRevisionCompactor(); - let rev_manager = RevisionManager::new(&user_id, grid_id, rev_persistence, rev_compactor, history_persistence); + let rev_manager = RevisionManager::new( + &user_id, + grid_id, + rev_persistence, + rev_compactor, + history_persistence, + snapshot_persistence, + ); Ok(rev_manager) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs index 417c158cff..232b342367 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block/block_meta_manager.rs @@ -10,7 +10,9 @@ use flowy_grid_data_model::entities::{ RowMeta, RowMetaChangeset, RowOrder, UpdatedRowOrder, }; use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; -use flowy_revision::{RevisionManager, RevisionPersistence, SQLiteRevisionHistoryPersistence}; +use flowy_revision::{ + RevisionManager, RevisionPersistence, SQLiteRevisionHistoryPersistence, SQLiteRevisionSnapshotPersistence, +}; use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; @@ -280,8 +282,10 @@ pub fn make_grid_block_meta_rev_manager(user: &Arc, block_id: &str let disk_cache = SQLiteGridBlockMetaRevisionPersistence::new(&user_id, pool.clone()); let rev_persistence = RevisionPersistence::new(&user_id, block_id, disk_cache); + let rev_compactor = GridBlockMetaRevisionCompactor(); - let history_persistence = SQLiteRevisionHistoryPersistence::new(pool); + let history_persistence = SQLiteRevisionHistoryPersistence::new(block_id, pool.clone()); + let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(block_id, pool); Ok(RevisionManager::new( &user_id, @@ -289,5 +293,6 @@ pub fn make_grid_block_meta_rev_manager(user: &Arc, block_id: &str rev_persistence, rev_compactor, history_persistence, + snapshot_persistence, )) } diff --git a/frontend/rust-lib/flowy-revision/src/cache/disk/grid_rev_impl.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/grid_rev_impl.rs index d51ea8e48c..9ddb21bc8c 100644 --- a/frontend/rust-lib/flowy-revision/src/cache/disk/grid_rev_impl.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/grid_rev_impl.rs @@ -95,7 +95,6 @@ struct GridRevisionSql(); impl GridRevisionSql { fn create(revision_records: Vec, conn: &SqliteConnection) -> Result<(), FlowyError> { // Batch insert: https://diesel.rs/guides/all-about-inserts.html - let records = revision_records .into_iter() .map(|record| { diff --git a/frontend/rust-lib/flowy-revision/src/history/persistence.rs b/frontend/rust-lib/flowy-revision/src/history/persistence.rs index 01d22fe6a4..9c1bdacc9e 100644 --- a/frontend/rust-lib/flowy-revision/src/history/persistence.rs +++ b/frontend/rust-lib/flowy-revision/src/history/persistence.rs @@ -1,50 +1,51 @@ use crate::history::RevisionHistoryDiskCache; -use diesel::{sql_types::Integer, update, SqliteConnection}; use flowy_database::{ prelude::*, schema::{rev_history, rev_history::dsl}, ConnectionPool, }; -use flowy_error::{FlowyError, FlowyResult}; +use flowy_error::{internal_error, FlowyResult}; use flowy_sync::entities::revision::Revision; use std::sync::Arc; pub struct SQLiteRevisionHistoryPersistence { + object_id: String, pool: Arc, } impl SQLiteRevisionHistoryPersistence { - pub fn new(pool: Arc) -> Self { - Self { pool } + pub fn new(object_id: &str, pool: Arc) -> Self { + let object_id = object_id.to_owned(); + Self { object_id, pool } } } impl RevisionHistoryDiskCache for SQLiteRevisionHistoryPersistence { - fn save_revision(&self, revision: Revision) -> FlowyResult<()> { - todo!() + fn write_history(&self, revision: Revision) -> FlowyResult<()> { + let record = ( + dsl::object_id.eq(revision.object_id), + dsl::start_rev_id.eq(revision.base_rev_id), + dsl::end_rev_id.eq(revision.rev_id), + dsl::data.eq(revision.delta_data), + ); + let conn = self.pool.get().map_err(internal_error)?; + + let _ = insert_or_ignore_into(dsl::rev_history) + .values(vec![record]) + .execute(&*conn)?; + Ok(()) } - fn read_revision(&self, rev_id: i64) -> FlowyResult { - todo!() - } - - fn clear(&self) -> FlowyResult<()> { - todo!() - } -} - -struct RevisionHistorySql(); -impl RevisionHistorySql { - fn read_revision(object_id: &str, rev_id: i64, conn: &SqliteConnection) -> Result { + fn read_histories(&self) -> FlowyResult> { + let conn = self.pool.get().map_err(internal_error)?; let records: Vec = dsl::rev_history - .filter(dsl::start_rev_id.lt(rev_id)) - .filter(dsl::end_rev_id.ge(rev_id)) - .filter(dsl::object_id.eq(object_id)) - .load::(conn)?; + .filter(dsl::object_id.eq(&self.object_id)) + .load::(&*conn)?; - debug_assert_eq!(records.len(), 1); - - todo!() + Ok(records + .into_iter() + .map(|record| record.into()) + .collect::>()) } } @@ -57,3 +58,21 @@ struct RevisionRecord { end_rev_id: i64, data: Vec, } + +pub struct RevisionHistory { + pub object_id: String, + pub start_rev_id: i64, + pub end_rev_id: i64, + pub data: Vec, +} + +impl std::convert::From for RevisionHistory { + fn from(record: RevisionRecord) -> Self { + RevisionHistory { + object_id: record.object_id, + start_rev_id: record.start_rev_id, + end_rev_id: record.end_rev_id, + data: record.data, + } + } +} diff --git a/frontend/rust-lib/flowy-revision/src/history/rev_history.rs b/frontend/rust-lib/flowy-revision/src/history/rev_history.rs index faa35a9ede..71bdc0c333 100644 --- a/frontend/rust-lib/flowy-revision/src/history/rev_history.rs +++ b/frontend/rust-lib/flowy-revision/src/history/rev_history.rs @@ -1,36 +1,31 @@ -use crate::history::persistence::SQLiteRevisionHistoryPersistence; -use crate::RevisionCompactor; +use crate::{RevisionCompactor, RevisionHistory}; use async_stream::stream; -use flowy_database::ConnectionPool; + use flowy_error::{FlowyError, FlowyResult}; use flowy_sync::entities::revision::Revision; use futures_util::future::BoxFuture; use futures_util::stream::StreamExt; use futures_util::FutureExt; -use std::fmt::Debug; use std::sync::Arc; use std::time::Duration; -use tokio::sync::mpsc::error::SendError; -use tokio::sync::mpsc::Sender; -use tokio::sync::{mpsc, oneshot, RwLock}; +use tokio::sync::{mpsc, RwLock}; use tokio::time::interval; pub trait RevisionHistoryDiskCache: Send + Sync { - fn save_revision(&self, revision: Revision) -> FlowyResult<()>; + fn write_history(&self, revision: Revision) -> FlowyResult<()>; - fn read_revision(&self, rev_id: i64) -> FlowyResult; - - fn clear(&self) -> FlowyResult<()>; + fn read_histories(&self) -> FlowyResult>; } -pub struct RevisionHistory { - stop_timer: mpsc::Sender<()>, +pub struct RevisionHistoryManager { + user_id: String, + stop_tx: mpsc::Sender<()>, config: RevisionHistoryConfig, revisions: Arc>>, disk_cache: Arc, } -impl RevisionHistory { +impl RevisionHistoryManager { pub fn new( user_id: &str, object_id: &str, @@ -38,27 +33,13 @@ impl RevisionHistory { disk_cache: Arc, rev_compactor: Arc, ) -> Self { - let user_id = user_id.to_string(); - let object_id = object_id.to_string(); - let cloned_disk_cache = disk_cache.clone(); - let (stop_timer, stop_rx) = mpsc::channel(1); - let (checkpoint_tx, checkpoint_rx) = mpsc::channel(1); let revisions = Arc::new(RwLock::new(vec![])); - let fix_duration_checkpoint_tx = FixedDurationCheckpointSender { - user_id, - object_id, - checkpoint_tx, - disk_cache: cloned_disk_cache, - revisions: revisions.clone(), - rev_compactor, - duration: config.check_duration, - }; - - tokio::spawn(CheckpointRunner::new(stop_rx, checkpoint_rx).run()); - tokio::spawn(fix_duration_checkpoint_tx.run()); - + let stop_tx = + spawn_history_checkpoint_runner(user_id, object_id, &disk_cache, &revisions, rev_compactor, &config); + let user_id = user_id.to_owned(); Self { - stop_timer, + user_id, + stop_tx, config, revisions, disk_cache, @@ -69,12 +50,8 @@ impl RevisionHistory { self.revisions.write().await.push(revision.clone()); } - pub async fn reset_history(&self) { - self.revisions.write().await.clear(); - match self.disk_cache.clear() { - Ok(_) => {} - Err(e) => tracing::error!("Clear history failed: {:?}", e), - } + pub async fn read_revision_histories(&self) -> FlowyResult> { + self.disk_cache.read_histories() } } @@ -90,12 +67,41 @@ impl std::default::Default for RevisionHistoryConfig { } } -struct CheckpointRunner { +fn spawn_history_checkpoint_runner( + user_id: &str, + object_id: &str, + disk_cache: &Arc, + revisions: &Arc>>, + rev_compactor: Arc, + config: &RevisionHistoryConfig, +) -> mpsc::Sender<()> { + let user_id = user_id.to_string(); + let object_id = object_id.to_string(); + let disk_cache = disk_cache.clone(); + let revisions = revisions.clone(); + + let (checkpoint_tx, checkpoint_rx) = mpsc::channel(1); + let (stop_tx, stop_rx) = mpsc::channel(1); + let checkpoint_sender = FixedDurationCheckpointSender { + user_id, + object_id, + checkpoint_tx, + disk_cache, + revisions, + rev_compactor, + duration: config.check_duration, + }; + tokio::spawn(HistoryCheckpointRunner::new(stop_rx, checkpoint_rx).run()); + tokio::spawn(checkpoint_sender.run()); + stop_tx +} + +struct HistoryCheckpointRunner { stop_rx: Option>, checkpoint_rx: Option>, } -impl CheckpointRunner { +impl HistoryCheckpointRunner { fn new(stop_rx: mpsc::Receiver<()>, checkpoint_rx: mpsc::Receiver) -> Self { Self { stop_rx: Some(stop_rx), @@ -149,7 +155,7 @@ impl HistoryCheckpoint { let revision = self .rev_compactor .compact(&self.user_id, &self.object_id, self.revisions)?; - let _ = self.disk_cache.save_revision(revision)?; + let _ = self.disk_cache.write_history(revision)?; Ok::<(), FlowyError>(()) }; @@ -174,7 +180,7 @@ impl FixedDurationCheckpointSender { fn run(self) -> BoxFuture<'static, ()> { async move { let mut interval = interval(self.duration); - let checkpoint_revisions: Vec = revisions.write().await.drain(..).collect(); + let checkpoint_revisions: Vec = self.revisions.write().await.drain(..).collect(); let checkpoint = HistoryCheckpoint { user_id: self.user_id.clone(), object_id: self.object_id.clone(), @@ -182,7 +188,7 @@ impl FixedDurationCheckpointSender { disk_cache: self.disk_cache.clone(), rev_compactor: self.rev_compactor.clone(), }; - match checkpoint_tx.send(checkpoint).await { + match self.checkpoint_tx.send(checkpoint).await { Ok(_) => { interval.tick().await; self.run(); diff --git a/frontend/rust-lib/flowy-revision/src/lib.rs b/frontend/rust-lib/flowy-revision/src/lib.rs index 14f00568f2..8631ddf14d 100644 --- a/frontend/rust-lib/flowy-revision/src/lib.rs +++ b/frontend/rust-lib/flowy-revision/src/lib.rs @@ -3,6 +3,7 @@ mod conflict_resolve; mod history; mod rev_manager; mod rev_persistence; +mod snapshot; mod ws_manager; pub use cache::*; @@ -10,6 +11,7 @@ pub use conflict_resolve::*; pub use history::*; pub use rev_manager::*; pub use rev_persistence::*; +pub use snapshot::*; pub use ws_manager::*; #[macro_use] diff --git a/frontend/rust-lib/flowy-revision/src/rev_manager.rs b/frontend/rust-lib/flowy-revision/src/rev_manager.rs index bed942b7b4..5d10185dc9 100644 --- a/frontend/rust-lib/flowy-revision/src/rev_manager.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_manager.rs @@ -1,6 +1,6 @@ use crate::disk::RevisionState; -use crate::history::{RevisionHistory, RevisionHistoryConfig, RevisionHistoryDiskCache}; -use crate::{RevisionPersistence, WSDataProviderDataSource}; +use crate::history::{RevisionHistoryConfig, RevisionHistoryDiskCache, RevisionHistoryManager}; +use crate::{RevisionPersistence, RevisionSnapshotDiskCache, RevisionSnapshotManager, WSDataProviderDataSource}; use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; use flowy_sync::{ @@ -46,37 +46,43 @@ pub struct RevisionManager { user_id: String, rev_id_counter: RevIdCounter, rev_persistence: Arc, - rev_history: Arc, + rev_history: Arc, + rev_snapshot: Arc, rev_compactor: Arc, #[cfg(feature = "flowy_unit_test")] rev_ack_notifier: tokio::sync::broadcast::Sender, } impl RevisionManager { - pub fn new( + pub fn new( user_id: &str, object_id: &str, rev_persistence: RevisionPersistence, rev_compactor: C, - history_persistence: P, + history_persistence: HP, + snapshot_persistence: SP, ) -> Self where - P: 'static + RevisionHistoryDiskCache, + HP: 'static + RevisionHistoryDiskCache, + SP: 'static + RevisionSnapshotDiskCache, C: 'static + RevisionCompactor, { let rev_id_counter = RevIdCounter::new(0); let rev_compactor = Arc::new(rev_compactor); let history_persistence = Arc::new(history_persistence); + let rev_history_config = RevisionHistoryConfig::default(); let rev_persistence = Arc::new(rev_persistence); - let rev_history = Arc::new(RevisionHistory::new( + let rev_history = Arc::new(RevisionHistoryManager::new( user_id, object_id, rev_history_config, history_persistence, rev_compactor.clone(), )); + + let rev_snapshot = Arc::new(RevisionSnapshotManager::new(user_id, object_id, snapshot_persistence)); #[cfg(feature = "flowy_unit_test")] let (revision_ack_notifier, _) = tokio::sync::broadcast::channel(1); @@ -86,6 +92,7 @@ impl RevisionManager { rev_id_counter, rev_persistence, rev_history, + rev_snapshot, rev_compactor, #[cfg(feature = "flowy_unit_test")] rev_ack_notifier: revision_ack_notifier, @@ -114,7 +121,6 @@ impl RevisionManager { pub async fn reset_object(&self, revisions: RepeatedRevision) -> FlowyResult<()> { let rev_id = pair_rev_id_from_revisions(&revisions).1; let _ = self.rev_persistence.reset(revisions.into_inner()).await?; - self.rev_history.reset_history().await; self.rev_id_counter.set(rev_id); Ok(()) } diff --git a/frontend/rust-lib/flowy-revision/src/snapshot/mod.rs b/frontend/rust-lib/flowy-revision/src/snapshot/mod.rs new file mode 100644 index 0000000000..adc4ee2ccc --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/snapshot/mod.rs @@ -0,0 +1,5 @@ +mod persistence; +mod rev_snapshot; + +pub use persistence::*; +pub use rev_snapshot::*; diff --git a/frontend/rust-lib/flowy-revision/src/snapshot/persistence.rs b/frontend/rust-lib/flowy-revision/src/snapshot/persistence.rs new file mode 100644 index 0000000000..e07c541b12 --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/snapshot/persistence.rs @@ -0,0 +1,28 @@ +use crate::{RevisionSnapshotDiskCache, RevisionSnapshotInfo}; +use flowy_database::ConnectionPool; +use flowy_error::FlowyResult; +use std::sync::Arc; + +pub struct SQLiteRevisionSnapshotPersistence { + object_id: String, + pool: Arc, +} + +impl SQLiteRevisionSnapshotPersistence { + pub fn new(object_id: &str, pool: Arc) -> Self { + Self { + object_id: object_id.to_string(), + pool, + } + } +} + +impl RevisionSnapshotDiskCache for SQLiteRevisionSnapshotPersistence { + fn write_snapshot(&self, object_id: &str, rev_id: i64, data: Vec) -> FlowyResult<()> { + todo!() + } + + fn read_snapshot(&self, object_id: &str, rev_id: i64) -> FlowyResult { + todo!() + } +} diff --git a/frontend/rust-lib/flowy-revision/src/snapshot/rev_snapshot.rs b/frontend/rust-lib/flowy-revision/src/snapshot/rev_snapshot.rs new file mode 100644 index 0000000000..71e2e270ec --- /dev/null +++ b/frontend/rust-lib/flowy-revision/src/snapshot/rev_snapshot.rs @@ -0,0 +1,29 @@ +use flowy_error::FlowyResult; +use std::sync::Arc; + +pub trait RevisionSnapshotDiskCache: Send + Sync { + fn write_snapshot(&self, object_id: &str, rev_id: i64, data: Vec) -> FlowyResult<()>; + fn read_snapshot(&self, object_id: &str, rev_id: i64) -> FlowyResult; +} + +pub struct RevisionSnapshotManager { + user_id: String, + object_id: String, + disk_cache: Arc, +} + +impl RevisionSnapshotManager { + pub fn new(user_id: &str, object_id: &str, disk_cache: D) -> Self + where + D: RevisionSnapshotDiskCache + 'static, + { + let disk_cache = Arc::new(disk_cache); + Self { + user_id: user_id.to_string(), + object_id: object_id.to_string(), + disk_cache, + } + } +} + +pub struct RevisionSnapshotInfo {} diff --git a/frontend/rust-lib/flowy-text-block/src/manager.rs b/frontend/rust-lib/flowy-text-block/src/manager.rs index a6cdda1220..9b0dc18a94 100644 --- a/frontend/rust-lib/flowy-text-block/src/manager.rs +++ b/frontend/rust-lib/flowy-text-block/src/manager.rs @@ -7,6 +7,7 @@ use flowy_error::FlowyResult; use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; use flowy_revision::{ RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket, SQLiteRevisionHistoryPersistence, + SQLiteRevisionSnapshotPersistence, }; use flowy_sync::entities::{ revision::{md5, RepeatedRevision, Revision}, @@ -144,7 +145,8 @@ impl TextBlockManager { let user_id = self.user.user_id()?; let disk_cache = SQLiteTextBlockRevisionPersistence::new(&user_id, pool.clone()); let rev_persistence = RevisionPersistence::new(&user_id, doc_id, disk_cache); - let history_persistence = SQLiteRevisionHistoryPersistence::new(pool); + let history_persistence = SQLiteRevisionHistoryPersistence::new(doc_id, pool.clone()); + let snapshot_persistence = SQLiteRevisionSnapshotPersistence::new(doc_id, pool); let rev_compactor = TextBlockRevisionCompactor(); Ok(RevisionManager::new( @@ -153,6 +155,7 @@ impl TextBlockManager { rev_persistence, rev_compactor, history_persistence, + snapshot_persistence, )) } } From 51ab1b6798f0aa10de413e27b44404fa3e49df84 Mon Sep 17 00:00:00 2001 From: Ian Su Date: Tue, 5 Jul 2022 10:12:09 +0800 Subject: [PATCH 006/112] feat: add widget to update username --- .../app_flowy/assets/translations/en.json | 1 + .../presentation/home/menu/menu_user.dart | 2 +- .../settings/settings_dialog.dart | 19 +++++--- .../settings/widgets/settings_menu.dart | 10 ++++ .../widgets/settings_settings_view.dart | 48 +++++++++++++++++++ 5 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_settings_view.dart diff --git a/frontend/app_flowy/assets/translations/en.json b/frontend/app_flowy/assets/translations/en.json index a6f9b4d3ae..de2f8f7039 100644 --- a/frontend/app_flowy/assets/translations/en.json +++ b/frontend/app_flowy/assets/translations/en.json @@ -141,6 +141,7 @@ "menu": { "appearance": "Appearance", "language": "Language", + "settings": "Settings", "open": "Open Settings" }, "appearance": { diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart index 6b75c9ef3f..e819a0ed40 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart @@ -74,7 +74,7 @@ class MenuUser extends StatelessWidget { showDialog( context: context, builder: (context) { - return const SettingsDialog(); + return SettingsDialog(user); }, ); }, diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart b/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart index 8c7bb8f494..3d0f59bdd8 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart @@ -2,13 +2,16 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_appearance_view.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_language_view.dart'; +import 'package:app_flowy/workspace/presentation/settings/widgets/settings_settings_view.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_menu.dart'; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class SettingsDialog extends StatefulWidget { - const SettingsDialog({Key? key}) : super(key: key); + final UserProfile user; + SettingsDialog(this.user, {Key? key}) : super(key: ValueKey(user.id)); @override State createState() => _SettingsDialogState(); @@ -17,10 +20,14 @@ class SettingsDialog extends StatefulWidget { class _SettingsDialogState extends State { int _selectedViewIndex = 0; - final List settingsViews = const [ - SettingsAppearanceView(), - SettingsLanguageView(), - ]; + Widget getSettingsView(int index, UserProfile user) { + final List settingsViews = [ + const SettingsAppearanceView(), + const SettingsLanguageView(), + SettingsSettingsView(user), + ]; + return settingsViews[index]; + } @override Widget build(BuildContext context) { @@ -59,7 +66,7 @@ class _SettingsDialogState extends State { const VerticalDivider(), const SizedBox(width: 10), Expanded( - child: settingsViews[_selectedViewIndex], + child: getSettingsView(_selectedViewIndex, widget.user), ) ], ), diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_menu.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_menu.dart index 241c337705..6900328f60 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_menu.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_menu.dart @@ -34,6 +34,16 @@ class SettingsMenu extends StatelessWidget { icon: Icons.translate, changeSelectedIndex: changeSelectedIndex, ), + const SizedBox( + height: 10, + ), + SettingsMenuElement( + index: 2, + currentIndex: currentIndex, + label: LocaleKeys.settings_menu_settings.tr(), + icon: Icons.account_box_outlined, + changeSelectedIndex: changeSelectedIndex, + ), ], ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_settings_view.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_settings_view.dart new file mode 100644 index 0000000000..6b33022577 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_settings_view.dart @@ -0,0 +1,48 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:flutter/material.dart'; +import 'package:app_flowy/workspace/application/menu/menu_user_bloc.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; + +class SettingsSettingsView extends StatelessWidget { + final UserProfile user; + SettingsSettingsView(this.user, {Key? key}) : super(key: ValueKey(user.id)); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(param1: user)..add(const MenuUserEvent.initial()), + child: BlocBuilder( + builder: (context, state) => SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: const [UserNameInput()], + ), + ), + ), + ); + } +} + +class UserNameInput extends StatefulWidget { + const UserNameInput({ + Key? key, + }) : super(key: key); + + @override + State createState() => _UserNameInputState(); +} + +class _UserNameInputState extends State { + @override + Widget build(BuildContext context) { + return TextField( + decoration: const InputDecoration( + labelText: 'Name', + ), + onSubmitted: (val) { + context.read().add(MenuUserEvent.updateUserName(val)); + debugPrint("Value $val submitted"); + }); + } +} From f24e154b4fb5cb4776040c945c9fc5e89ef4d085 Mon Sep 17 00:00:00 2001 From: Ian Su Date: Sat, 9 Jul 2022 22:00:17 +0800 Subject: [PATCH 007/112] refactor: create SettingsUserViewBloc --- .../app_flowy/assets/translations/en.json | 2 +- .../app_flowy/lib/startup/deps_resolver.dart | 6 ++ .../workspace/application/user/prelude.dart | 1 + .../application/user/settings_user_bloc.dart | 79 +++++++++++++++++++ .../settings/settings_dialog.dart | 4 +- .../settings/widgets/settings_menu.dart | 2 +- ...ings_view.dart => settings_user_view.dart} | 25 +++--- 7 files changed, 100 insertions(+), 19 deletions(-) create mode 100644 frontend/app_flowy/lib/workspace/application/user/prelude.dart create mode 100644 frontend/app_flowy/lib/workspace/application/user/settings_user_bloc.dart rename frontend/app_flowy/lib/workspace/presentation/settings/widgets/{settings_settings_view.dart => settings_user_view.dart} (51%) diff --git a/frontend/app_flowy/assets/translations/en.json b/frontend/app_flowy/assets/translations/en.json index de2f8f7039..656c28be2e 100644 --- a/frontend/app_flowy/assets/translations/en.json +++ b/frontend/app_flowy/assets/translations/en.json @@ -141,7 +141,7 @@ "menu": { "appearance": "Appearance", "language": "Language", - "settings": "Settings", + "user": "User", "open": "Open Settings" }, "appearance": { diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 0cf248e7e4..ed382f9b83 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -5,6 +5,7 @@ import 'package:app_flowy/workspace/application/app/prelude.dart'; import 'package:app_flowy/workspace/application/doc/prelude.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/application/trash/prelude.dart'; +import 'package:app_flowy/workspace/application/user/prelude.dart'; import 'package:app_flowy/workspace/application/workspace/prelude.dart'; import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dart'; import 'package:app_flowy/workspace/application/view/prelude.dart'; @@ -101,6 +102,11 @@ void _resolveFolderDeps(GetIt getIt) { (user, _) => MenuUserBloc(user), ); + //User + getIt.registerFactoryParam( + (user, _) => SettingsUserViewBloc(user), + ); + // App getIt.registerFactoryParam( (app, _) => AppBloc( diff --git a/frontend/app_flowy/lib/workspace/application/user/prelude.dart b/frontend/app_flowy/lib/workspace/application/user/prelude.dart new file mode 100644 index 0000000000..f698497db9 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/user/prelude.dart @@ -0,0 +1 @@ +export 'settings_user_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/user/settings_user_bloc.dart b/frontend/app_flowy/lib/workspace/application/user/settings_user_bloc.dart new file mode 100644 index 0000000000..5a4954c068 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/user/settings_user_bloc.dart @@ -0,0 +1,79 @@ +import 'package:app_flowy/user/application/user_listener.dart'; +import 'package:app_flowy/user/application/user_service.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:dartz/dartz.dart'; + +part 'settings_user_bloc.freezed.dart'; + +class SettingsUserViewBloc extends Bloc { + final UserService _userService; + final UserListener _userListener; + final UserProfile userProfile; + + SettingsUserViewBloc(this.userProfile) + : _userListener = UserListener(userProfile: userProfile), + _userService = UserService(userId: userProfile.id), + super(SettingsUserState.initial(userProfile)) { + on((event, emit) async { + await event.when( + initial: () async { + _userListener.start(onProfileUpdated: _profileUpdated); + await _initUser(); + }, + didReceiveUserProfile: (UserProfile newUserProfile) { + emit(state.copyWith(userProfile: newUserProfile)); + }, + updateUserName: (String name) { + _userService.updateUserProfile(name: name).then((result) { + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }); + }, + ); + }); + } + + @override + Future close() async { + await _userListener.stop(); + super.close(); + } + + Future _initUser() async { + final result = await _userService.initUser(); + result.fold((l) => null, (error) => Log.error(error)); + } + + void _profileUpdated(Either userProfileOrFailed) { + userProfileOrFailed.fold( + (newUserProfile) => add(SettingsUserEvent.didReceiveUserProfile(newUserProfile)), + (err) => Log.error(err), + ); + } +} + +@freezed +class SettingsUserEvent with _$SettingsUserEvent { + const factory SettingsUserEvent.initial() = _Initial; + const factory SettingsUserEvent.updateUserName(String name) = _UpdateUserName; + const factory SettingsUserEvent.didReceiveUserProfile(UserProfile newUserProfile) = _DidReceiveUserProfile; +} + +@freezed +class SettingsUserState with _$SettingsUserState { + const factory SettingsUserState({ + required UserProfile userProfile, + required Either successOrFailure, + }) = _SettingsUserState; + + factory SettingsUserState.initial(UserProfile userProfile) => SettingsUserState( + userProfile: userProfile, + successOrFailure: left(unit), + ); +} diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart b/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart index 3d0f59bdd8..72bb0bf7ac 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart @@ -2,7 +2,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_appearance_view.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_language_view.dart'; -import 'package:app_flowy/workspace/presentation/settings/widgets/settings_settings_view.dart'; +import 'package:app_flowy/workspace/presentation/settings/widgets/settings_user_view.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_menu.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; import 'package:easy_localization/easy_localization.dart'; @@ -24,7 +24,7 @@ class _SettingsDialogState extends State { final List settingsViews = [ const SettingsAppearanceView(), const SettingsLanguageView(), - SettingsSettingsView(user), + SettingsUserView(user), ]; return settingsViews[index]; } diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_menu.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_menu.dart index 6900328f60..a27d9861c4 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_menu.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_menu.dart @@ -40,7 +40,7 @@ class SettingsMenu extends StatelessWidget { SettingsMenuElement( index: 2, currentIndex: currentIndex, - label: LocaleKeys.settings_menu_settings.tr(), + label: LocaleKeys.settings_menu_user.tr(), icon: Icons.account_box_outlined, changeSelectedIndex: changeSelectedIndex, ), diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_settings_view.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart similarity index 51% rename from frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_settings_view.dart rename to frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart index 6b33022577..b72df8f272 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_settings_view.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -1,22 +1,22 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:flutter/material.dart'; -import 'package:app_flowy/workspace/application/menu/menu_user_bloc.dart'; +import 'package:app_flowy/workspace/application/user/settings_user_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; -class SettingsSettingsView extends StatelessWidget { +class SettingsUserView extends StatelessWidget { final UserProfile user; - SettingsSettingsView(this.user, {Key? key}) : super(key: ValueKey(user.id)); + SettingsUserView(this.user, {Key? key}) : super(key: ValueKey(user.id)); @override Widget build(BuildContext context) { - return BlocProvider( - create: (context) => getIt(param1: user)..add(const MenuUserEvent.initial()), - child: BlocBuilder( + return BlocProvider( + create: (context) => getIt(param1: user)..add(const SettingsUserEvent.initial()), + child: BlocBuilder( builder: (context, state) => SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: const [UserNameInput()], + children: const [_UserNameInput()], ), ), ), @@ -24,16 +24,11 @@ class SettingsSettingsView extends StatelessWidget { } } -class UserNameInput extends StatefulWidget { - const UserNameInput({ +class _UserNameInput extends StatelessWidget { + const _UserNameInput({ Key? key, }) : super(key: key); - @override - State createState() => _UserNameInputState(); -} - -class _UserNameInputState extends State { @override Widget build(BuildContext context) { return TextField( @@ -41,7 +36,7 @@ class _UserNameInputState extends State { labelText: 'Name', ), onSubmitted: (val) { - context.read().add(MenuUserEvent.updateUserName(val)); + context.read().add(SettingsUserEvent.updateUserName(val)); debugPrint("Value $val submitted"); }); } From db165f70061433f291170f4d4cd406593cd0a285 Mon Sep 17 00:00:00 2001 From: Ian Su Date: Sat, 9 Jul 2022 23:32:29 +0800 Subject: [PATCH 008/112] refactor: remove updateUserName from MenuUserBloc --- .../lib/workspace/application/menu/menu_user_bloc.dart | 9 --------- 1 file changed, 9 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart b/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart index 7433c758b0..d590621e2d 100644 --- a/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart @@ -34,14 +34,6 @@ class MenuUserBloc extends Bloc { didReceiveUserProfile: (UserProfile newUserProfile) { emit(state.copyWith(userProfile: newUserProfile)); }, - updateUserName: (String name) { - _userService.updateUserProfile(name: name).then((result) { - result.fold( - (l) => null, - (err) => Log.error(err), - ); - }); - }, ); }); } @@ -74,7 +66,6 @@ class MenuUserBloc extends Bloc { class MenuUserEvent with _$MenuUserEvent { const factory MenuUserEvent.initial() = _Initial; const factory MenuUserEvent.fetchWorkspaces() = _FetchWorkspaces; - const factory MenuUserEvent.updateUserName(String name) = _UpdateUserName; const factory MenuUserEvent.didReceiveUserProfile(UserProfile newUserProfile) = _DidReceiveUserProfile; } From 29ce17178375e3f19b5ca65d8313aa5bc6fbf059 Mon Sep 17 00:00:00 2001 From: Ian Su Date: Sun, 10 Jul 2022 11:31:26 +0800 Subject: [PATCH 009/112] feat: show name on _UserNameInput --- .../settings/widgets/settings_user_view.dart | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart index b72df8f272..f347dbed7b 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -16,28 +16,36 @@ class SettingsUserView extends StatelessWidget { builder: (context, state) => SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, - children: const [_UserNameInput()], + children: [_renderUserNameInput(context)], ), ), ), ); } + + Widget _renderUserNameInput(BuildContext context) { + String name = context.read().state.userProfile.name; + debugPrint(name); + return _UserNameInput(name); + } } class _UserNameInput extends StatelessWidget { - const _UserNameInput({ + final String name; + const _UserNameInput( + this.name, { Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return TextField( + controller: TextEditingController()..text = name, decoration: const InputDecoration( labelText: 'Name', ), onSubmitted: (val) { context.read().add(SettingsUserEvent.updateUserName(val)); - debugPrint("Value $val submitted"); }); } } From 7d39e90a9a674f871d2d4c85d0017e4ba48f1574 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 11 Jul 2022 17:15:16 +0800 Subject: [PATCH 010/112] chore: separate RowScript from EditorScropt --- .../rust-lib/flowy-grid/src/event_handler.rs | 2 +- .../tests/grid/{ => block_test}/block_test.rs | 9 +- .../flowy-grid/tests/grid/block_test/mod.rs | 5 + .../tests/grid/{ => block_test}/row_test.rs | 34 +- .../tests/grid/block_test/script.rs | 150 +++++++ .../grid/{row_util.rs => block_test/util.rs} | 13 +- .../flowy-grid/tests/grid/cell_test/mod.rs | 2 + .../flowy-grid/tests/grid/cell_test/script.rs | 61 +++ .../grid/{cell_test.rs => cell_test/test.rs} | 8 +- .../flowy-grid/tests/grid/field_test/mod.rs | 3 + .../tests/grid/field_test/script.rs | 94 +++++ .../{field_test.rs => field_test/test.rs} | 44 +- .../{field_util.rs => field_test/util.rs} | 0 .../tests/grid/filter_test/script.rs | 16 +- .../flowy-grid/tests/grid/grid_editor.rs | 164 ++++++++ .../rust-lib/flowy-grid/tests/grid/mod.rs | 5 +- .../rust-lib/flowy-grid/tests/grid/script.rs | 380 ------------------ 17 files changed, 547 insertions(+), 443 deletions(-) rename frontend/rust-lib/flowy-grid/tests/grid/{ => block_test}/block_test.rs (82%) create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/block_test/mod.rs rename frontend/rust-lib/flowy-grid/tests/grid/{ => block_test}/row_test.rs (84%) create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs rename frontend/rust-lib/flowy-grid/tests/grid/{row_util.rs => block_test/util.rs} (88%) create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/cell_test/mod.rs create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs rename frontend/rust-lib/flowy-grid/tests/grid/{cell_test.rs => cell_test/test.rs} (90%) create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/field_test/mod.rs create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs rename frontend/rust-lib/flowy-grid/tests/grid/{field_test.rs => field_test/test.rs} (75%) rename frontend/rust-lib/flowy-grid/tests/grid/{field_util.rs => field_test/util.rs} (100%) create mode 100644 frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs delete mode 100644 frontend/rust-lib/flowy-grid/tests/grid/script.rs diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 7d470bdfb9..a3b1471a4e 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -369,7 +369,7 @@ pub(crate) async fn get_select_option_handler( let any_cell_data: AnyCellData = match cell_rev { None => AnyCellData { data: "".to_string(), - field_type: field_rev.field_type_rev.clone().into(), + field_type: field_rev.field_type_rev.into(), }, Some(cell_rev) => cell_rev.try_into()?, }; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/block_test.rs similarity index 82% rename from frontend/rust-lib/flowy-grid/tests/grid/block_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/block_test/block_test.rs index 51094e2b3f..6ded1f7060 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/block_test.rs @@ -1,5 +1,6 @@ -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; +use crate::grid::block_test::script::GridRowTest; +use crate::grid::block_test::script::RowScript::*; + use flowy_grid_data_model::revision::{GridBlockMetaRevision, GridBlockMetaRevisionChangeset}; #[tokio::test] @@ -10,7 +11,7 @@ async fn grid_create_block() { CreateBlock { block: block_meta_rev }, AssertBlockCount(2), ]; - GridEditorTest::new().await.run_scripts(scripts).await; + GridRowTest::new().await.run_scripts(scripts).await; } #[tokio::test] @@ -36,5 +37,5 @@ async fn grid_update_block() { block: cloned_grid_block, }, ]; - GridEditorTest::new().await.run_scripts(scripts).await; + GridRowTest::new().await.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/mod.rs new file mode 100644 index 0000000000..c982869655 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/mod.rs @@ -0,0 +1,5 @@ +#![allow(clippy::module_inception)] +mod block_test; +mod row_test; +mod script; +pub mod util; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs similarity index 84% rename from frontend/rust-lib/flowy-grid/tests/grid/row_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index 73b24f9afd..96c23611b0 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -1,18 +1,18 @@ -use crate::grid::field_util::*; -use crate::grid::row_util::GridRowTestBuilder; -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; +use crate::grid::block_test::script::GridRowTest; +use crate::grid::block_test::script::RowScript::*; +use crate::grid::block_test::util::GridRowTestBuilder; use chrono::NaiveDateTime; use flowy_grid::entities::FieldType; use flowy_grid::services::cell::decode_any_cell_data; use flowy_grid::services::field::select_option::SELECTION_IDS_SEPARATOR; use flowy_grid::services::field::{DateCellData, MultiSelectTypeOption, SingleSelectTypeOption}; -use flowy_grid::services::row::CreateRowRevisionBuilder; + +use crate::grid::field_test::util::make_date_cell_string; use flowy_grid_data_model::revision::RowMetaChangeset; #[tokio::test] async fn grid_create_row_count_test() { - let test = GridEditorTest::new().await; + let mut test = GridRowTest::new().await; let scripts = vec![ AssertRowCount(3), CreateEmptyRow, @@ -22,12 +22,12 @@ async fn grid_create_row_count_test() { }, AssertRowCount(6), ]; - GridEditorTest::new().await.run_scripts(scripts).await; + test.run_scripts(scripts).await; } #[tokio::test] async fn grid_update_row() { - let mut test = GridEditorTest::new().await; + let mut test = GridRowTest::new().await; let payload = GridRowTestBuilder::new(&test).build(); let changeset = RowMetaChangeset { row_id: payload.row_id.clone(), @@ -39,14 +39,14 @@ async fn grid_update_row() { let scripts = vec![AssertRowCount(3), CreateRow { payload }, UpdateRow { changeset }]; test.run_scripts(scripts).await; - let expected_row = (&*test.row_revs.last().cloned().unwrap()).clone(); + let expected_row = test.last_row().unwrap(); let scripts = vec![AssertRow { expected_row }, AssertRowCount(4)]; test.run_scripts(scripts).await; } #[tokio::test] async fn grid_delete_row() { - let mut test = GridEditorTest::new().await; + let mut test = GridRowTest::new().await; let payload1 = GridRowTestBuilder::new(&test).build(); let payload2 = GridRowTestBuilder::new(&test).build(); let row_ids = vec![payload1.row_id.clone(), payload2.row_id.clone()]; @@ -72,9 +72,9 @@ async fn grid_delete_row() { #[tokio::test] async fn grid_row_add_cells_test() { - let mut test = GridEditorTest::new().await; - let mut builder = CreateRowRevisionBuilder::new(&test.field_revs); - for field in &test.field_revs { + let mut test = GridRowTest::new().await; + let mut builder = test.builder(); + for field in test.field_revs() { let field_type: FieldType = field.field_type_rev.into(); match field_type { FieldType::RichText => { @@ -112,17 +112,17 @@ async fn grid_row_add_cells_test() { } } let context = builder.build(); - let scripts = vec![CreateRow { payload: context }, AssertGridRevisionPad]; + let scripts = vec![CreateRow { payload: context }]; test.run_scripts(scripts).await; } #[tokio::test] async fn grid_row_add_date_cell_test() { - let mut test = GridEditorTest::new().await; - let mut builder = CreateRowRevisionBuilder::new(&test.field_revs); + let mut test = GridRowTest::new().await; + let mut builder = test.builder(); let mut date_field = None; let timestamp = 1647390674; - for field in &test.field_revs { + for field in test.field_revs() { let field_type: FieldType = field.field_type_rev.into(); if field_type == FieldType::DateTime { date_field = Some(field.clone()); diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs new file mode 100644 index 0000000000..288133958b --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -0,0 +1,150 @@ +use crate::grid::grid_editor::GridEditorTest; +use flowy_grid::entities::RowInfo; +use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; +use flowy_grid_data_model::revision::{ + FieldRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, +}; +use std::sync::Arc; + +pub enum RowScript { + CreateEmptyRow, + CreateRow { + payload: CreateRowRevisionPayload, + }, + UpdateRow { + changeset: RowMetaChangeset, + }, + AssertRow { + expected_row: RowRevision, + }, + DeleteRows { + row_ids: Vec, + }, + AssertRowCount(usize), + CreateBlock { + block: GridBlockMetaRevision, + }, + UpdateBlock { + changeset: GridBlockMetaRevisionChangeset, + }, + AssertBlockCount(usize), + AssertBlock { + block_index: usize, + row_count: i32, + start_row_index: i32, + }, + AssertBlockEqual { + block_index: usize, + block: GridBlockMetaRevision, + }, +} + +pub struct GridRowTest { + inner: GridEditorTest, +} + +impl GridRowTest { + pub async fn new() -> Self { + let editor_test = GridEditorTest::new().await; + Self { inner: editor_test } + } + + pub fn field_revs(&self) -> &Vec> { + &self.field_revs + } + + pub fn last_row(&self) -> Option { + self.row_revs.last().map(|a| a.clone().as_ref().clone()) + } + + pub async fn run_scripts(&mut self, scripts: Vec) { + for script in scripts { + self.run_script(script).await; + } + } + + pub fn builder(&self) -> CreateRowRevisionBuilder { + CreateRowRevisionBuilder::new(&self.field_revs) + } + + pub async fn run_script(&mut self, script: RowScript) { + match script { + RowScript::CreateEmptyRow => { + let row_order = self.editor.create_row(None).await.unwrap(); + 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(); + } + RowScript::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().to_owned(), row_order); + } + self.row_revs = self.get_row_revs().await; + self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); + } + RowScript::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(), + RowScript::DeleteRows { row_ids } => { + let row_orders = row_ids + .into_iter() + .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) + .collect::>(); + + self.editor.delete_rows(row_orders).await.unwrap(); + self.row_revs = self.get_row_revs().await; + self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); + } + RowScript::AssertRow { expected_row } => { + let row = &*self + .row_revs + .iter() + .find(|row| row.id == expected_row.id) + .cloned() + .unwrap(); + assert_eq!(&expected_row, row); + } + RowScript::AssertRowCount(expected_row_count) => { + assert_eq!(expected_row_count, self.row_revs.len()); + } + RowScript::CreateBlock { block } => { + self.editor.create_block(block).await.unwrap(); + self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); + } + RowScript::UpdateBlock { changeset: change } => { + self.editor.update_block(change).await.unwrap(); + } + RowScript::AssertBlockCount(count) => { + assert_eq!(self.editor.get_block_meta_revs().await.unwrap().len(), count); + } + RowScript::AssertBlock { + block_index, + row_count, + start_row_index, + } => { + assert_eq!(self.block_meta_revs[block_index].row_count, row_count); + assert_eq!(self.block_meta_revs[block_index].start_row_index, start_row_index); + } + RowScript::AssertBlockEqual { block_index, block } => { + let blocks = self.editor.get_block_meta_revs().await.unwrap(); + let compared_block = blocks[block_index].clone(); + assert_eq!(compared_block, Arc::new(block)); + } + } + } +} + +impl std::ops::Deref for GridRowTest { + type Target = GridEditorTest; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for GridRowTest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs similarity index 88% rename from frontend/rust-lib/flowy-grid/tests/grid/row_util.rs rename to frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs index bdd6dd86dc..49b8383fee 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/row_util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs @@ -1,4 +1,5 @@ -use crate::grid::script::GridEditorTest; +use crate::grid::block_test::script::GridRowTest; + use flowy_grid::entities::FieldType; use flowy_grid::services::field::DateCellChangeset; use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; @@ -6,15 +7,15 @@ use flowy_grid_data_model::revision::FieldRevision; use strum::EnumCount; pub struct GridRowTestBuilder<'a> { - test: &'a GridEditorTest, + test: &'a GridRowTest, inner_builder: CreateRowRevisionBuilder<'a>, } impl<'a> GridRowTestBuilder<'a> { - pub fn new(test: &'a GridEditorTest) -> Self { - assert_eq!(test.field_revs.len(), FieldType::COUNT); + pub fn new(test: &'a GridRowTest) -> Self { + assert_eq!(test.field_revs().len(), FieldType::COUNT); - let inner_builder = CreateRowRevisionBuilder::new(&test.field_revs); + let inner_builder = CreateRowRevisionBuilder::new(test.field_revs()); Self { test, inner_builder } } #[allow(dead_code)] @@ -59,7 +60,7 @@ impl<'a> GridRowTestBuilder<'a> { pub fn field_rev_with_type(&self, field_type: &FieldType) -> FieldRevision { self.test - .field_revs + .field_revs() .iter() .find(|field_rev| { let t_field_type: FieldType = field_rev.field_type_rev.into(); diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/mod.rs new file mode 100644 index 0000000000..63d424afaf --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/mod.rs @@ -0,0 +1,2 @@ +mod script; +mod test; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs new file mode 100644 index 0000000000..a6c88ef1c9 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs @@ -0,0 +1,61 @@ +use crate::grid::grid_editor::GridEditorTest; +use flowy_grid::entities::CellChangeset; + +pub enum CellScript { + UpdateCell { changeset: CellChangeset, is_err: bool }, +} + +pub struct GridCellTest { + inner: GridEditorTest, +} + +impl GridCellTest { + pub async fn new() -> Self { + let inner = GridEditorTest::new().await; + Self { inner } + } + + pub async fn run_scripts(&mut self, scripts: Vec) { + for script in scripts { + self.run_script(script).await; + } + } + + pub async fn run_script(&mut self, script: CellScript) { + // let grid_manager = self.sdk.grid_manager.clone(); + // let pool = self.sdk.user_session.db_pool().unwrap(); + let rev_manager = self.editor.rev_manager(); + let _cache = rev_manager.revision_cache().await; + + match script { + CellScript::UpdateCell { changeset, is_err } => { + let result = self.editor.update_cell(changeset).await; + if is_err { + assert!(result.is_err()) + } else { + let _ = result.unwrap(); + self.row_revs = self.get_row_revs().await; + } + } // CellScript::AssertGridRevisionPad => { + // sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; + // let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap(); + // let grid_pad = grid_rev_manager.load::(None).await.unwrap(); + // println!("{}", grid_pad.delta_str()); + // } + } + } +} + +impl std::ops::Deref for GridCellTest { + type Target = GridEditorTest; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for GridCellTest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs similarity index 90% rename from frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs index 01d2310278..844a230036 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs @@ -1,13 +1,13 @@ -use crate::grid::field_util::make_date_cell_string; -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; +use crate::grid::cell_test::script::CellScript::*; +use crate::grid::cell_test::script::GridCellTest; +use crate::grid::field_test::util::make_date_cell_string; use flowy_grid::entities::{CellChangeset, FieldType}; use flowy_grid::services::field::select_option::SelectOptionCellChangeset; use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; #[tokio::test] async fn grid_cell_update() { - let mut test = GridEditorTest::new().await; + let mut test = GridCellTest::new().await; let field_revs = &test.field_revs; let row_revs = &test.row_revs; let grid_blocks = &test.block_meta_revs; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/mod.rs new file mode 100644 index 0000000000..5ac4da9f24 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/mod.rs @@ -0,0 +1,3 @@ +mod script; +mod test; +pub mod util; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs new file mode 100644 index 0000000000..6d910f3516 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/script.rs @@ -0,0 +1,94 @@ +use crate::grid::grid_editor::GridEditorTest; +use flowy_grid::entities::InsertFieldParams; +use flowy_grid_data_model::revision::FieldRevision; +use flowy_sync::entities::grid::FieldChangesetParams; + +pub enum FieldScript { + CreateField { + params: InsertFieldParams, + }, + UpdateField { + changeset: FieldChangesetParams, + }, + DeleteField { + field_rev: FieldRevision, + }, + AssertFieldCount(usize), + AssertFieldEqual { + field_index: usize, + field_rev: FieldRevision, + }, +} + +pub struct GridFieldTest { + inner: GridEditorTest, +} + +impl GridFieldTest { + pub async fn new() -> Self { + let editor_test = GridEditorTest::new().await; + Self { inner: editor_test } + } + + pub fn grid_id(&self) -> String { + self.grid_id.clone() + } + + pub fn field_count(&self) -> usize { + self.field_count + } + + pub async fn run_scripts(&mut self, scripts: Vec) { + for script in scripts { + self.run_script(script).await; + } + } + + pub async fn run_script(&mut self, script: FieldScript) { + match script { + FieldScript::CreateField { params } => { + if !self.editor.contain_field(¶ms.field.id).await { + self.field_count += 1; + } + + self.editor.insert_field(params).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); + assert_eq!(self.field_count, self.field_revs.len()); + } + FieldScript::UpdateField { changeset: change } => { + self.editor.update_field(change).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); + } + FieldScript::DeleteField { field_rev } => { + if self.editor.contain_field(&field_rev.id).await { + self.field_count -= 1; + } + + self.editor.delete_field(&field_rev.id).await.unwrap(); + self.field_revs = self.editor.get_field_revs(None).await.unwrap(); + assert_eq!(self.field_count, self.field_revs.len()); + } + FieldScript::AssertFieldCount(count) => { + assert_eq!(self.editor.get_field_revs(None).await.unwrap().len(), count); + } + FieldScript::AssertFieldEqual { field_index, field_rev } => { + let field_revs = self.editor.get_field_revs(None).await.unwrap(); + assert_eq!(field_revs[field_index].as_ref(), &field_rev); + } + } + } +} + +impl std::ops::Deref for GridFieldTest { + type Target = GridEditorTest; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl std::ops::DerefMut for GridFieldTest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs similarity index 75% rename from frontend/rust-lib/flowy-grid/tests/grid/field_test.rs rename to frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs index 00428a8fc4..624979e940 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs @@ -1,6 +1,6 @@ -use crate::grid::field_util::*; -use crate::grid::script::EditorScript::*; -use crate::grid::script::*; +use crate::grid::field_test::script::FieldScript::*; +use crate::grid::field_test::script::GridFieldTest; +use crate::grid::field_test::util::*; use flowy_grid::services::field::select_option::SelectOption; use flowy_grid::services::field::SingleSelectTypeOption; use flowy_grid_data_model::revision::TypeOptionDataEntry; @@ -8,23 +8,23 @@ use flowy_sync::entities::grid::FieldChangesetParams; #[tokio::test] async fn grid_create_field() { - let mut test = GridEditorTest::new().await; - let (params, field_rev) = create_text_field(&test.grid_id); + let mut test = GridFieldTest::new().await; + let (params, field_rev) = create_text_field(&test.grid_id()); let scripts = vec![ CreateField { params }, AssertFieldEqual { - field_index: test.field_count, + field_index: test.field_count(), field_rev, }, ]; test.run_scripts(scripts).await; - let (params, field_rev) = create_single_select_field(&test.grid_id); + let (params, field_rev) = create_single_select_field(&test.grid_id()); let scripts = vec![ CreateField { params }, AssertFieldEqual { - field_index: test.field_count, + field_index: test.field_count(), field_rev, }, ]; @@ -33,9 +33,9 @@ async fn grid_create_field() { #[tokio::test] async fn grid_create_duplicate_field() { - let mut test = GridEditorTest::new().await; - let (params, _) = create_text_field(&test.grid_id); - let field_count = test.field_count; + let mut test = GridFieldTest::new().await; + let (params, _) = create_text_field(&test.grid_id()); + let field_count = test.field_count(); let expected_field_count = field_count + 1; let scripts = vec![ CreateField { params: params.clone() }, @@ -47,11 +47,11 @@ async fn grid_create_duplicate_field() { #[tokio::test] async fn grid_update_field_with_empty_change() { - let mut test = GridEditorTest::new().await; - let (params, field_rev) = create_single_select_field(&test.grid_id); + let mut test = GridFieldTest::new().await; + let (params, field_rev) = create_single_select_field(&test.grid_id()); let changeset = FieldChangesetParams { field_id: field_rev.id.clone(), - grid_id: test.grid_id.clone(), + grid_id: test.grid_id(), ..Default::default() }; @@ -59,7 +59,7 @@ async fn grid_update_field_with_empty_change() { CreateField { params }, UpdateField { changeset }, AssertFieldEqual { - field_index: test.field_count, + field_index: test.field_count(), field_rev, }, ]; @@ -68,14 +68,14 @@ async fn grid_update_field_with_empty_change() { #[tokio::test] async fn grid_update_field() { - let mut test = GridEditorTest::new().await; - let (params, single_select_field) = create_single_select_field(&test.grid_id); + let mut test = GridFieldTest::new().await; + let (params, single_select_field) = create_single_select_field(&test.grid_id()); let mut single_select_type_option = SingleSelectTypeOption::from(&single_select_field); single_select_type_option.options.push(SelectOption::new("Unknown")); let changeset = FieldChangesetParams { field_id: single_select_field.id.clone(), - grid_id: test.grid_id.clone(), + grid_id: test.grid_id(), frozen: Some(true), width: Some(1000), type_option_data: Some(single_select_type_option.protobuf_bytes().to_vec()), @@ -92,7 +92,7 @@ async fn grid_update_field() { CreateField { params }, UpdateField { changeset }, AssertFieldEqual { - field_index: test.field_count, + field_index: test.field_count(), field_rev: expected_field_rev, }, ]; @@ -101,9 +101,9 @@ async fn grid_update_field() { #[tokio::test] async fn grid_delete_field() { - let mut test = GridEditorTest::new().await; - let original_field_count = test.field_count; - let (params, text_field_rev) = create_text_field(&test.grid_id); + let mut test = GridFieldTest::new().await; + let original_field_count = test.field_count(); + let (params, text_field_rev) = create_text_field(&test.grid_id()); let scripts = vec![ CreateField { params }, DeleteField { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/tests/grid/field_util.rs rename to frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs index d89b6a66a1..4a1ef3af83 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs @@ -7,7 +7,7 @@ use flowy_grid::entities::{CreateGridFilterPayload, GridLayoutType, GridSetting} use flowy_grid::services::setting::GridSettingChangesetBuilder; use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision}; use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; -use crate::grid::script::GridEditorTest; +use crate::grid::grid_editor::GridEditorTest; pub enum FilterScript { #[allow(dead_code)] @@ -31,14 +31,14 @@ pub enum FilterScript { } pub struct GridFilterTest { - pub editor_test: GridEditorTest, + inner: GridEditorTest, } impl GridFilterTest { pub async fn new() -> Self { let editor_test = GridEditorTest::new().await; Self { - editor_test + inner: editor_test } } @@ -49,7 +49,6 @@ impl GridFilterTest { } pub async fn run_script(&mut self, script: FilterScript) { - match script { FilterScript::UpdateGridSetting { params } => { let _ = self.editor.update_grid_setting(params).await.unwrap(); @@ -82,10 +81,17 @@ impl GridFilterTest { } } + impl std::ops::Deref for GridFilterTest { type Target = GridEditorTest; fn deref(&self) -> &Self::Target { - &self.editor_test + &self.inner + } +} + +impl std::ops::DerefMut for GridFilterTest { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner } } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs new file mode 100644 index 0000000000..d944aac6c5 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -0,0 +1,164 @@ +#![allow(clippy::all)] +#![allow(dead_code)] +#![allow(unused_imports)] +use bytes::Bytes; +use flowy_grid::entities::*; +use flowy_grid::services::field::select_option::SelectOption; +use flowy_grid::services::field::*; +use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; +use flowy_grid::services::row::CreateRowRevisionPayload; +use flowy_grid::services::setting::GridSettingChangesetBuilder; +use flowy_grid_data_model::revision::*; +use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; +use flowy_sync::client_grid::GridBuilder; +use flowy_sync::entities::grid::{ + CreateGridFilterParams, DeleteFilterParams, FieldChangesetParams, GridSettingChangesetParams, +}; +use flowy_test::helper::ViewTest; +use flowy_test::FlowySDKTest; +use std::collections::HashMap; +use std::sync::Arc; +use std::time::Duration; +use strum::EnumCount; +use tokio::time::sleep; + +pub struct GridEditorTest { + pub sdk: FlowySDKTest, + pub grid_id: String, + pub editor: Arc, + pub field_revs: Vec>, + pub block_meta_revs: Vec>, + pub row_revs: Vec>, + pub field_count: usize, + pub row_order_by_row_id: HashMap, +} + +impl GridEditorTest { + pub async fn new() -> Self { + let sdk = FlowySDKTest::default(); + let _ = sdk.init_user().await; + let build_context = make_all_field_test_grid(); + let view_data: Bytes = build_context.into(); + let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; + let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); + let field_revs = editor.get_field_revs(None).await.unwrap(); + let block_meta_revs = editor.get_block_meta_revs().await.unwrap(); + let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs; + assert_eq!(row_revs.len(), 3); + assert_eq!(block_meta_revs.len(), 1); + + // It seems like you should add the field in the make_test_grid() function. + // Because we assert the initialize count of the fields is equal to FieldType::COUNT. + assert_eq!(field_revs.len(), FieldType::COUNT); + + let grid_id = test.view.id; + Self { + sdk, + grid_id, + editor, + field_revs, + block_meta_revs, + row_revs, + field_count: FieldType::COUNT, + row_order_by_row_id: HashMap::default(), + } + } + + pub(crate) async fn get_row_revs(&self) -> Vec> { + self.editor + .grid_block_snapshots(None) + .await + .unwrap() + .pop() + .unwrap() + .row_revs + } + + pub async fn grid_filters(&self) -> Vec { + let layout_type = GridLayoutType::Table; + self.editor.get_grid_filter(&layout_type).await.unwrap() + } + + pub fn text_field(&self) -> &FieldRevision { + self.field_revs + .iter() + .filter(|field_rev| { + let t_field_type: FieldType = field_rev.field_type_rev.into(); + t_field_type == FieldType::RichText + }) + .collect::>() + .pop() + .unwrap() + } +} + +fn make_all_field_test_grid() -> BuildGridContext { + let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) + .name("Name") + .visibility(true) + .build(); + + // Single Select + let single_select = SingleSelectTypeOptionBuilder::default() + .option(SelectOption::new("Live")) + .option(SelectOption::new("Completed")) + .option(SelectOption::new("Planned")) + .option(SelectOption::new("Paused")); + let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); + + // MultiSelect + let multi_select = MultiSelectTypeOptionBuilder::default() + .option(SelectOption::new("Google")) + .option(SelectOption::new("Facebook")) + .option(SelectOption::new("Twitter")); + let multi_select_field = FieldBuilder::new(multi_select) + .name("Platform") + .visibility(true) + .build(); + + // Number + let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); + let number_field = FieldBuilder::new(number).name("Price").visibility(true).build(); + + // Date + let date = DateTypeOptionBuilder::default() + .date_format(DateFormat::US) + .time_format(TimeFormat::TwentyFourHour); + let date_field = FieldBuilder::new(date).name("Time").visibility(true).build(); + + // Checkbox + let checkbox = CheckboxTypeOptionBuilder::default(); + let checkbox_field = FieldBuilder::new(checkbox).name("is done").visibility(true).build(); + + // URL + let url = URLTypeOptionBuilder::default(); + let url_field = FieldBuilder::new(url).name("link").visibility(true).build(); + + // for i in 0..3 { + // for field_type in FieldType::iter() { + // let field_type: FieldType = field_type; + // match field_type { + // FieldType::RichText => {} + // FieldType::Number => {} + // FieldType::DateTime => {} + // FieldType::SingleSelect => {} + // FieldType::MultiSelect => {} + // FieldType::Checkbox => {} + // FieldType::URL => {} + // } + // } + // } + + GridBuilder::default() + .add_field(text_field) + .add_field(single_select_field) + .add_field(multi_select_field) + .add_field(number_field) + .add_field(date_field) + .add_field(checkbox_field) + .add_field(url_field) + .add_empty_row() + .add_empty_row() + .add_empty_row() + .build() +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs index 4d746661eb..8865bf01c2 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/mod.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/mod.rs @@ -1,8 +1,5 @@ mod block_test; mod cell_test; mod field_test; -mod field_util; mod filter_test; -mod row_test; -mod row_util; -mod script; +mod grid_editor; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/script.rs deleted file mode 100644 index 915749fb0e..0000000000 --- a/frontend/rust-lib/flowy-grid/tests/grid/script.rs +++ /dev/null @@ -1,380 +0,0 @@ -#![allow(clippy::all)] -#![allow(dead_code)] -#![allow(unused_imports)] -use bytes::Bytes; -use flowy_grid::entities::*; -use flowy_grid::services::field::select_option::SelectOption; -use flowy_grid::services::field::*; -use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; -use flowy_grid::services::row::CreateRowRevisionPayload; -use flowy_grid::services::setting::GridSettingChangesetBuilder; -use flowy_grid_data_model::revision::*; -use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; -use flowy_sync::client_grid::GridBuilder; -use flowy_sync::entities::grid::{ - CreateGridFilterParams, DeleteFilterParams, FieldChangesetParams, GridSettingChangesetParams, -}; -use flowy_test::helper::ViewTest; -use flowy_test::FlowySDKTest; -use std::collections::HashMap; -use std::sync::Arc; -use std::time::Duration; -use strum::EnumCount; -use tokio::time::sleep; - -pub enum EditorScript { - CreateField { - params: InsertFieldParams, - }, - UpdateField { - changeset: FieldChangesetParams, - }, - DeleteField { - field_rev: FieldRevision, - }, - AssertFieldCount(usize), - AssertFieldEqual { - field_index: usize, - field_rev: FieldRevision, - }, - CreateBlock { - block: GridBlockMetaRevision, - }, - UpdateBlock { - changeset: GridBlockMetaRevisionChangeset, - }, - AssertBlockCount(usize), - AssertBlock { - block_index: usize, - row_count: i32, - start_row_index: i32, - }, - AssertBlockEqual { - block_index: usize, - block: GridBlockMetaRevision, - }, - CreateEmptyRow, - CreateRow { - payload: CreateRowRevisionPayload, - }, - UpdateRow { - changeset: RowMetaChangeset, - }, - AssertRow { - expected_row: RowRevision, - }, - DeleteRows { - row_ids: Vec, - }, - UpdateCell { - changeset: CellChangeset, - is_err: bool, - }, - AssertRowCount(usize), - #[allow(dead_code)] - UpdateGridSetting { - params: GridSettingChangesetParams, - }, - InsertGridTableFilter { - payload: CreateGridFilterPayload, - }, - AssertTableFilterCount { - count: i32, - }, - DeleteGridTableFilter { - filter_id: String, - field_rev: FieldRevision, - }, - #[allow(dead_code)] - AssertGridSetting { - expected_setting: GridSetting, - }, - AssertGridRevisionPad, -} - -pub struct GridEditorTest { - pub sdk: FlowySDKTest, - pub grid_id: String, - pub editor: Arc, - pub field_revs: Vec>, - pub block_meta_revs: Vec>, - pub row_revs: Vec>, - pub field_count: usize, - - pub row_order_by_row_id: HashMap, -} - -impl GridEditorTest { - pub async fn new() -> Self { - let sdk = FlowySDKTest::default(); - let _ = sdk.init_user().await; - let build_context = make_all_field_test_grid(); - let view_data: Bytes = build_context.into(); - let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; - let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); - let field_revs = editor.get_field_revs(None).await.unwrap(); - let block_meta_revs = editor.get_block_meta_revs().await.unwrap(); - let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs; - assert_eq!(row_revs.len(), 3); - assert_eq!(block_meta_revs.len(), 1); - - // It seems like you should add the field in the make_test_grid() function. - // Because we assert the initialize count of the fields is equal to FieldType::COUNT. - assert_eq!(field_revs.len(), FieldType::COUNT); - - let grid_id = test.view.id; - Self { - sdk, - grid_id, - editor, - field_revs, - block_meta_revs, - row_revs, - field_count: FieldType::COUNT, - row_order_by_row_id: HashMap::default(), - } - } - - pub async fn run_scripts(&mut self, scripts: Vec) { - for script in scripts { - self.run_script(script).await; - } - } - - pub async fn run_script(&mut self, script: EditorScript) { - let grid_manager = self.sdk.grid_manager.clone(); - let pool = self.sdk.user_session.db_pool().unwrap(); - let rev_manager = self.editor.rev_manager(); - let _cache = rev_manager.revision_cache().await; - - match script { - EditorScript::CreateField { params } => { - if !self.editor.contain_field(¶ms.field.id).await { - self.field_count += 1; - } - - self.editor.insert_field(params).await.unwrap(); - self.field_revs = self.editor.get_field_revs(None).await.unwrap(); - assert_eq!(self.field_count, self.field_revs.len()); - } - EditorScript::UpdateField { changeset: change } => { - self.editor.update_field(change).await.unwrap(); - self.field_revs = self.editor.get_field_revs(None).await.unwrap(); - } - EditorScript::DeleteField { field_rev } => { - if self.editor.contain_field(&field_rev.id).await { - self.field_count -= 1; - } - - self.editor.delete_field(&field_rev.id).await.unwrap(); - self.field_revs = self.editor.get_field_revs(None).await.unwrap(); - assert_eq!(self.field_count, self.field_revs.len()); - } - EditorScript::AssertFieldCount(count) => { - assert_eq!(self.editor.get_field_revs(None).await.unwrap().len(), count); - } - EditorScript::AssertFieldEqual { field_index, field_rev } => { - let field_revs = self.editor.get_field_revs(None).await.unwrap(); - assert_eq!(field_revs[field_index].as_ref(), &field_rev); - } - EditorScript::CreateBlock { block } => { - self.editor.create_block(block).await.unwrap(); - self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); - } - EditorScript::UpdateBlock { changeset: change } => { - self.editor.update_block(change).await.unwrap(); - } - EditorScript::AssertBlockCount(count) => { - assert_eq!(self.editor.get_block_meta_revs().await.unwrap().len(), count); - } - EditorScript::AssertBlock { - block_index, - row_count, - start_row_index, - } => { - assert_eq!(self.block_meta_revs[block_index].row_count, row_count); - assert_eq!(self.block_meta_revs[block_index].start_row_index, start_row_index); - } - EditorScript::AssertBlockEqual { block_index, block } => { - let blocks = self.editor.get_block_meta_revs().await.unwrap(); - let compared_block = blocks[block_index].clone(); - assert_eq!(compared_block, Arc::new(block)); - } - EditorScript::CreateEmptyRow => { - let row_order = self.editor.create_row(None).await.unwrap(); - 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().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::UpdateRow { changeset: change } => self.editor.update_row(change).await.unwrap(), - EditorScript::DeleteRows { row_ids } => { - let row_orders = row_ids - .into_iter() - .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) - .collect::>(); - - self.editor.delete_rows(row_orders).await.unwrap(); - self.row_revs = self.get_row_revs().await; - self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); - } - EditorScript::AssertRow { expected_row } => { - let row = &*self - .row_revs - .iter() - .find(|row| row.id == expected_row.id) - .cloned() - .unwrap(); - assert_eq!(&expected_row, row); - // if let Some(visibility) = changeset.visibility { - // assert_eq!(row.visibility, visibility); - // } - // - // if let Some(height) = changeset.height { - // assert_eq!(row.height, height); - // } - } - EditorScript::UpdateCell { changeset, is_err } => { - let result = self.editor.update_cell(changeset).await; - if is_err { - assert!(result.is_err()) - } else { - let _ = result.unwrap(); - self.row_revs = self.get_row_revs().await; - } - } - EditorScript::AssertRowCount(expected_row_count) => { - assert_eq!(expected_row_count, self.row_revs.len()); - } - EditorScript::UpdateGridSetting { params } => { - let _ = self.editor.update_grid_setting(params).await.unwrap(); - } - EditorScript::InsertGridTableFilter { payload } => { - let params: CreateGridFilterParams = payload.try_into().unwrap(); - let layout_type = GridLayoutType::Table; - let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) - .insert_filter(params) - .build(); - let _ = self.editor.update_grid_setting(params).await.unwrap(); - } - EditorScript::AssertTableFilterCount { count } => { - let layout_type = GridLayoutType::Table; - let filters = self.editor.get_grid_filter(&layout_type).await.unwrap(); - assert_eq!(count as usize, filters.len()); - } - EditorScript::DeleteGridTableFilter { filter_id, field_rev } => { - let layout_type = GridLayoutType::Table; - let params = GridSettingChangesetBuilder::new(&self.grid_id, &layout_type) - .delete_filter(DeleteFilterParams { - field_id: field_rev.id, - filter_id, - field_type_rev: field_rev.field_type_rev, - }) - .build(); - let _ = self.editor.update_grid_setting(params).await.unwrap(); - } - EditorScript::AssertGridSetting { expected_setting } => { - let setting = self.editor.get_grid_setting().await.unwrap(); - assert_eq!(expected_setting, setting); - } - EditorScript::AssertGridRevisionPad => { - sleep(Duration::from_millis(2 * REVISION_WRITE_INTERVAL_IN_MILLIS)).await; - let mut grid_rev_manager = grid_manager.make_grid_rev_manager(&self.grid_id, pool.clone()).unwrap(); - let grid_pad = grid_rev_manager.load::(None).await.unwrap(); - println!("{}", grid_pad.delta_str()); - } - } - } - - async fn get_row_revs(&self) -> Vec> { - self.editor - .grid_block_snapshots(None) - .await - .unwrap() - .pop() - .unwrap() - .row_revs - } - - pub async fn grid_filters(&self) -> Vec { - let layout_type = GridLayoutType::Table; - self.editor.get_grid_filter(&layout_type).await.unwrap() - } - - pub fn text_field(&self) -> &FieldRevision { - self.field_revs - .iter() - .filter(|field_rev| { - let t_field_type: FieldType = field_rev.field_type_rev.into(); - t_field_type == FieldType::RichText - }) - .collect::>() - .pop() - .unwrap() - } -} - -fn make_all_field_test_grid() -> BuildGridContext { - let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) - .name("Name") - .visibility(true) - .build(); - - // Single Select - let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Live")) - .option(SelectOption::new("Completed")) - .option(SelectOption::new("Planned")) - .option(SelectOption::new("Paused")); - let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); - - // MultiSelect - let multi_select = MultiSelectTypeOptionBuilder::default() - .option(SelectOption::new("Google")) - .option(SelectOption::new("Facebook")) - .option(SelectOption::new("Twitter")); - let multi_select_field = FieldBuilder::new(multi_select) - .name("Platform") - .visibility(true) - .build(); - - // Number - let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); - let number_field = FieldBuilder::new(number).name("Price").visibility(true).build(); - - // Date - let date = DateTypeOptionBuilder::default() - .date_format(DateFormat::US) - .time_format(TimeFormat::TwentyFourHour); - let date_field = FieldBuilder::new(date).name("Time").visibility(true).build(); - - // Checkbox - let checkbox = CheckboxTypeOptionBuilder::default(); - let checkbox_field = FieldBuilder::new(checkbox).name("is done").visibility(true).build(); - - // URL - let url = URLTypeOptionBuilder::default(); - let url_field = FieldBuilder::new(url).name("link").visibility(true).build(); - - GridBuilder::default() - .add_field(text_field) - .add_field(single_select_field) - .add_field(multi_select_field) - .add_field(number_field) - .add_field(date_field) - .add_field(checkbox_field) - .add_field(url_field) - .add_empty_row() - .add_empty_row() - .add_empty_row() - .build() -} From 284755eccf4f65b95d6b1a511831f0b6609d4b52 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 12 Jul 2022 15:49:14 +0800 Subject: [PATCH 011/112] refactor: row builder --- .../rust-lib/flowy-grid/src/event_handler.rs | 11 +- .../src/services/cell/cell_operation.rs | 15 +- .../flowy-grid/src/services/grid_editor.rs | 37 ++-- .../src/services/row/row_builder.rs | 30 ++-- .../flowy-grid/src/services/row/row_loader.rs | 28 +-- frontend/rust-lib/flowy-grid/src/util.rs | 16 +- .../tests/grid/block_test/row_test.rs | 109 +++--------- .../tests/grid/block_test/script.rs | 44 +++-- .../flowy-grid/tests/grid/block_test/util.rs | 113 +++++++----- .../flowy-grid/tests/grid/grid_editor.rs | 163 ++++++++++-------- .../src/client_grid/grid_builder.rs | 17 +- 11 files changed, 288 insertions(+), 295 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index a3b1471a4e..c2faceb9b5 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -5,6 +5,7 @@ use crate::services::field::select_option::*; use crate::services::field::{ default_type_option_builder_from_type, type_option_builder_from_json_str, DateChangesetParams, DateChangesetPayload, }; +use crate::services::row::make_row_from_row_rev; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::FieldRevision; use flowy_sync::entities::grid::{FieldChangesetParams, GridSettingChangesetParams}; @@ -229,10 +230,12 @@ pub(crate) async fn get_row_handler( ) -> DataResult { let params: GridRowId = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; - let row = OptionalRow { - row: editor.get_row(¶ms.row_id).await?, - }; - data_result(row) + let row = editor + .get_row_rev(¶ms.row_id) + .await? + .and_then(make_row_from_row_rev); + + data_result(OptionalRow { row }) } #[tracing::instrument(level = "debug", skip(data, manager), err)] diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs index 5b74c26aa4..05c331bda8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -26,8 +26,12 @@ pub trait CellDataOperation { /// SelectOptionCellChangeset,DateCellChangeset. etc. fn apply_changeset(&self, changeset: CellDataChangeset, cell_rev: Option) -> FlowyResult; } -/// The changeset will be deserialized into specific data base on the FieldType. -/// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect +/// changeset: It will be deserialized into specific data base on the FieldType. +/// For example, +/// FieldType::RichText => String +/// FieldType::SingleSelect => SelectOptionChangeset +/// +/// cell_rev: It will be None if the cell does not contain any data. pub fn apply_cell_data_changeset>( changeset: C, cell_rev: Option, @@ -114,14 +118,16 @@ pub fn try_decode_cell_data( } } +/// If the cell data is not String type, it should impl this trait. +/// Deserialize the String into cell specific data type. pub trait FromCellString { fn from_cell_str(s: &str) -> FlowyResult where Self: Sized; } +/// CellData is a helper struct. String will be parser into Option only if the T impl the FromCellString trait. pub struct CellData(pub Option); - impl CellData { pub fn try_into_inner(self) -> FlowyResult { match self.0 { @@ -158,7 +164,8 @@ impl std::convert::From> for String { } } -// CellChangeset +/// If the changeset applying to the cell is not String type, it should impl this trait. +/// Deserialize the string into cell specific changeset. pub trait FromCellChangeset { fn from_changeset(changeset: String) -> FlowyResult where 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 1d63b6dd69..93d9317565 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -8,8 +8,7 @@ use crate::services::field::{default_type_option_builder_from_type, type_option_ use crate::services::filter::{GridFilterChangeset, GridFilterService}; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::row::{ - make_grid_blocks, make_row_from_row_rev, make_row_rev_from_context, make_rows_from_row_revs, - CreateRowRevisionBuilder, CreateRowRevisionPayload, GridBlockSnapshot, + make_grid_blocks, make_row_from_row_rev, make_rows_from_row_revs, GridBlockSnapshot, RowRevisionBuilder, }; use crate::services::setting::make_grid_setting; use bytes::Bytes; @@ -274,8 +273,7 @@ impl GridRevisionEditor { 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_rev = RowRevisionBuilder::new(&field_revs).build(&block_id); let row_order = RowInfo::from(&row_rev); // insert the row @@ -287,12 +285,11 @@ impl GridRevisionEditor { Ok(row_order) } - pub async fn insert_rows(&self, contexts: Vec) -> FlowyResult> { + pub async fn insert_rows(&self, row_revs: Vec) -> FlowyResult> { let block_id = self.block_id().await?; let mut rows_by_block_id: HashMap> = HashMap::new(); let mut row_orders = vec![]; - for ctx in contexts { - let row_rev = make_row_rev_from_context(&block_id, ctx); + for row_rev in row_revs { row_orders.push(RowInfo::from(&row_rev)); rows_by_block_id .entry(block_id.clone()) @@ -307,10 +304,7 @@ impl GridRevisionEditor { } pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { - let field_revs = self.get_field_revs(None).await?; - self.block_manager - .update_row(changeset, |row_rev| make_row_from_row_rev(&field_revs, row_rev)) - .await + self.block_manager.update_row(changeset, make_row_from_row_rev).await } pub async fn get_rows(&self, block_id: &str) -> FlowyResult { @@ -322,26 +316,20 @@ impl GridRevisionEditor { debug_assert_eq!(grid_block_snapshot.len(), 1); if grid_block_snapshot.len() == 1 { let snapshot = grid_block_snapshot.pop().unwrap(); - let field_revs = self.get_field_revs(None).await?; - let rows = make_rows_from_row_revs(&field_revs, &snapshot.row_revs); + let rows = make_rows_from_row_revs(&snapshot.row_revs); Ok(rows.into()) } else { Ok(vec![].into()) } } - pub async fn get_row(&self, row_id: &str) -> FlowyResult> { + pub async fn get_row_rev(&self, row_id: &str) -> FlowyResult>> { match self.block_manager.get_row_rev(row_id).await? { None => Ok(None), - Some(row_rev) => { - let field_revs = self.get_field_revs(None).await?; - let row_revs = vec![row_rev]; - let mut rows = make_rows_from_row_revs(&field_revs, &row_revs); - debug_assert!(rows.len() == 1); - Ok(rows.pop()) - } + Some(row_rev) => Ok(Some(row_rev)), } } + pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> { let _ = self.block_manager.delete_row(row_id).await?; Ok(()) @@ -360,6 +348,10 @@ impl GridRevisionEditor { Some(Cell::new(¶ms.field_id, data)) } + pub async fn get_cell_display(&self, _params: &CellIdentifier) -> Option { + todo!() + } + pub async fn get_cell_rev(&self, row_id: &str, field_id: &str) -> FlowyResult> { let row_rev = self.block_manager.get_row_rev(row_id).await?; match row_rev { @@ -395,7 +387,6 @@ impl GridRevisionEditor { let cell_rev = self.get_cell_rev(&row_id, &field_id).await?; // Update the changeset.data property with the return value. content = Some(apply_cell_data_changeset(content.unwrap(), cell_rev, field_rev)?); - let field_revs = self.get_field_revs(None).await?; let cell_changeset = CellChangeset { grid_id, row_id, @@ -404,7 +395,7 @@ impl GridRevisionEditor { }; let _ = self .block_manager - .update_cell(cell_changeset, |row_rev| make_row_from_row_rev(&field_revs, row_rev)) + .update_cell(cell_changeset, make_row_from_row_rev) .await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs index 3302276cd8..cc86fa3d9d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs @@ -6,12 +6,12 @@ use indexmap::IndexMap; use std::collections::HashMap; use std::sync::Arc; -pub struct CreateRowRevisionBuilder<'a> { +pub struct RowRevisionBuilder<'a> { field_rev_map: HashMap<&'a String, &'a Arc>, payload: CreateRowRevisionPayload, } -impl<'a> CreateRowRevisionBuilder<'a> { +impl<'a> RowRevisionBuilder<'a> { pub fn new(fields: &'a [Arc]) -> Self { let field_rev_map = fields .iter() @@ -28,10 +28,10 @@ impl<'a> CreateRowRevisionBuilder<'a> { Self { field_rev_map, payload } } - pub fn add_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> { + pub fn insert_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> { match self.field_rev_map.get(&field_id.to_owned()) { None => { - let msg = format!("Invalid field_id: {}", field_id); + let msg = format!("Can't find the field with id: {}", field_id); Err(FlowyError::internal().context(msg)) } Some(field_rev) => { @@ -43,7 +43,7 @@ impl<'a> CreateRowRevisionBuilder<'a> { } } - pub fn add_select_option_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> { + pub fn insert_select_option_cell(&mut self, field_id: &str, data: String) -> FlowyResult<()> { match self.field_rev_map.get(&field_id.to_owned()) { None => { let msg = format!("Invalid field_id: {}", field_id); @@ -71,18 +71,14 @@ impl<'a> CreateRowRevisionBuilder<'a> { self } - pub fn build(self) -> CreateRowRevisionPayload { - self.payload - } -} - -pub fn make_row_rev_from_context(block_id: &str, payload: CreateRowRevisionPayload) -> RowRevision { - RowRevision { - id: payload.row_id, - block_id: block_id.to_owned(), - cells: payload.cell_by_field_id, - height: payload.height, - visibility: payload.visibility, + pub fn build(self, block_id: &str) -> RowRevision { + RowRevision { + id: self.payload.row_id, + block_id: block_id.to_owned(), + cells: self.payload.cell_by_field_id, + height: self.payload.height, + visibility: self.payload.visibility, + } } } 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 1b9ce80101..81d9420d88 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::entities::{GridBlock, RepeatedGridBlock, Row, RowInfo}; use flowy_error::FlowyResult; -use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; +use flowy_grid_data_model::revision::RowRevision; use std::collections::HashMap; use std::sync::Arc; @@ -39,28 +39,14 @@ pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc]) -> Ve row_revs.iter().map(RowInfo::from).collect::>() } -pub(crate) fn make_row_from_row_rev(fields: &[Arc], row_rev: Arc) -> Option { - make_rows_from_row_revs(fields, &[row_rev]).pop() +pub(crate) fn make_row_from_row_rev(row_rev: Arc) -> Option { + make_rows_from_row_revs(&[row_rev]).pop() } -pub(crate) fn make_rows_from_row_revs(_fields: &[Arc], row_revs: &[Arc]) -> Vec { - // let field_rev_map = fields - // .iter() - // .map(|field_rev| (&field_rev.id, field_rev)) - // .collect::>(); - - let make_row = |row_rev: &Arc| { - // let cell_by_field_id = row_rev - // .cells - // .clone() - // .into_iter() - // .flat_map(|(field_id, cell_rev)| make_cell_by_field_id(&field_rev_map, field_id, cell_rev)) - // .collect::>(); - - Row { - id: row_rev.id.clone(), - height: row_rev.height, - } +pub(crate) fn make_rows_from_row_revs(row_revs: &[Arc]) -> Vec { + let make_row = |row_rev: &Arc| Row { + id: row_rev.id.clone(), + height: row_rev.height, }; row_revs.iter().map(make_row).collect::>() diff --git a/frontend/rust-lib/flowy-grid/src/util.rs b/frontend/rust-lib/flowy-grid/src/util.rs index e0055d09b6..3b48e313a9 100644 --- a/frontend/rust-lib/flowy-grid/src/util.rs +++ b/frontend/rust-lib/flowy-grid/src/util.rs @@ -4,29 +4,29 @@ use flowy_grid_data_model::revision::BuildGridContext; use flowy_sync::client_grid::GridBuilder; pub fn make_default_grid() -> BuildGridContext { + let mut grid_builder = GridBuilder::new(); // text let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) .name("Name") .visibility(true) .primary(true) .build(); + grid_builder.add_field(text_field); // single select let single_select = SingleSelectTypeOptionBuilder::default(); let single_select_field = FieldBuilder::new(single_select).name("Type").visibility(true).build(); + grid_builder.add_field(single_select_field); // checkbox let checkbox_field = FieldBuilder::from_field_type(&FieldType::Checkbox) .name("Done") .visibility(true) .build(); + grid_builder.add_field(checkbox_field); - GridBuilder::default() - .add_field(text_field) - .add_field(single_select_field) - .add_field(checkbox_field) - .add_empty_row() - .add_empty_row() - .add_empty_row() - .build() + grid_builder.add_empty_row(); + grid_builder.add_empty_row(); + grid_builder.add_empty_row(); + grid_builder.build() } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index 96c23611b0..ec57893d9b 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -1,13 +1,5 @@ use crate::grid::block_test::script::GridRowTest; use crate::grid::block_test::script::RowScript::*; -use crate::grid::block_test::util::GridRowTestBuilder; -use chrono::NaiveDateTime; -use flowy_grid::entities::FieldType; -use flowy_grid::services::cell::decode_any_cell_data; -use flowy_grid::services::field::select_option::SELECTION_IDS_SEPARATOR; -use flowy_grid::services::field::{DateCellData, MultiSelectTypeOption, SingleSelectTypeOption}; - -use crate::grid::field_test::util::make_date_cell_string; use flowy_grid_data_model::revision::RowMetaChangeset; #[tokio::test] @@ -18,7 +10,7 @@ async fn grid_create_row_count_test() { CreateEmptyRow, CreateEmptyRow, CreateRow { - payload: GridRowTestBuilder::new(&test).build(), + row_rev: test.row_builder().build(), }, AssertRowCount(6), ]; @@ -28,15 +20,15 @@ async fn grid_create_row_count_test() { #[tokio::test] async fn grid_update_row() { let mut test = GridRowTest::new().await; - let payload = GridRowTestBuilder::new(&test).build(); + let row_rev = test.row_builder().build(); let changeset = RowMetaChangeset { - row_id: payload.row_id.clone(), + row_id: row_rev.id.clone(), height: None, visibility: None, cell_by_field_id: Default::default(), }; - let scripts = vec![AssertRowCount(3), CreateRow { payload }, UpdateRow { changeset }]; + let scripts = vec![AssertRowCount(3), CreateRow { row_rev }, UpdateRow { changeset }]; test.run_scripts(scripts).await; let expected_row = test.last_row().unwrap(); @@ -47,13 +39,13 @@ async fn grid_update_row() { #[tokio::test] async fn grid_delete_row() { let mut test = GridRowTest::new().await; - let payload1 = GridRowTestBuilder::new(&test).build(); - let payload2 = GridRowTestBuilder::new(&test).build(); - let row_ids = vec![payload1.row_id.clone(), payload2.row_id.clone()]; + let row_1 = test.row_builder().build(); + let row_2 = test.row_builder().build(); + let row_ids = vec![row_1.id.clone(), row_2.id.clone()]; let scripts = vec![ AssertRowCount(3), - CreateRow { payload: payload1 }, - CreateRow { payload: payload2 }, + CreateRow { row_rev: row_1 }, + CreateRow { row_rev: row_2 }, AssertBlockCount(1), AssertBlock { block_index: 0, @@ -73,78 +65,17 @@ async fn grid_delete_row() { #[tokio::test] async fn grid_row_add_cells_test() { let mut test = GridRowTest::new().await; - let mut builder = test.builder(); - for field in test.field_revs() { - let field_type: FieldType = field.field_type_rev.into(); - match field_type { - FieldType::RichText => { - builder.add_cell(&field.id, "hello world".to_owned()).unwrap(); - } - FieldType::Number => { - builder.add_cell(&field.id, "18,443".to_owned()).unwrap(); - } - FieldType::DateTime => { - builder - .add_cell(&field.id, make_date_cell_string("1647251762")) - .unwrap(); - } - FieldType::SingleSelect => { - let type_option = SingleSelectTypeOption::from(field); - let option = type_option.options.first().unwrap(); - builder.add_select_option_cell(&field.id, option.id.clone()).unwrap(); - } - FieldType::MultiSelect => { - let type_option = MultiSelectTypeOption::from(field); - let ops_ids = type_option - .options - .iter() - .map(|option| option.id.clone()) - .collect::>() - .join(SELECTION_IDS_SEPARATOR); - builder.add_select_option_cell(&field.id, ops_ids).unwrap(); - } - FieldType::Checkbox => { - builder.add_cell(&field.id, "false".to_string()).unwrap(); - } - FieldType::URL => { - builder.add_cell(&field.id, "1".to_string()).unwrap(); - } - } - } - let context = builder.build(); - let scripts = vec![CreateRow { payload: context }]; - test.run_scripts(scripts).await; -} + let mut builder = test.row_builder(); -#[tokio::test] -async fn grid_row_add_date_cell_test() { - let mut test = GridRowTest::new().await; - let mut builder = test.builder(); - let mut date_field = None; - let timestamp = 1647390674; - for field in test.field_revs() { - let field_type: FieldType = field.field_type_rev.into(); - if field_type == FieldType::DateTime { - date_field = Some(field.clone()); - NaiveDateTime::from_timestamp(123, 0); - // The data should not be empty - assert!(builder.add_cell(&field.id, "".to_string()).is_err()); - assert!(builder.add_cell(&field.id, make_date_cell_string("123")).is_ok()); - assert!(builder - .add_cell(&field.id, make_date_cell_string(×tamp.to_string())) - .is_ok()); - } - } - let context = builder.build(); - let date_field = date_field.unwrap(); - let cell_rev = context.cell_by_field_id.get(&date_field.id).unwrap(); - assert_eq!( - decode_any_cell_data(cell_rev, &date_field) - .parse::() - .unwrap() - .date, - "2022/03/16", - ); - let scripts = vec![CreateRow { payload: context }]; + builder.insert_text_cell("hello world"); + builder.insert_number_cell("18,443"); + builder.insert_date_cell("1647251762"); + builder.insert_single_select_cell(|options| options.first().unwrap()); + builder.insert_multi_select_cell(|options| options); + builder.insert_checkbox_cell("false"); + builder.insert_url_cell("1"); + + let row_rev = builder.build(); + let scripts = vec![CreateRow { row_rev }]; test.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 288133958b..642cd51670 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -1,15 +1,16 @@ +use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; -use flowy_grid::entities::RowInfo; -use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; +use flowy_grid::entities::{CellIdentifier, RowInfo}; + use flowy_grid_data_model::revision::{ - FieldRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, + GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, }; use std::sync::Arc; pub enum RowScript { CreateEmptyRow, CreateRow { - payload: CreateRowRevisionPayload, + row_rev: RowRevision, }, UpdateRow { changeset: RowMetaChangeset, @@ -20,6 +21,11 @@ pub enum RowScript { DeleteRows { row_ids: Vec, }, + AssertCell { + row_id: String, + field_id: String, + expected_display: Option, + }, AssertRowCount(usize), CreateBlock { block: GridBlockMetaRevision, @@ -49,10 +55,6 @@ impl GridRowTest { Self { inner: editor_test } } - pub fn field_revs(&self) -> &Vec> { - &self.field_revs - } - pub fn last_row(&self) -> Option { self.row_revs.last().map(|a| a.clone().as_ref().clone()) } @@ -63,8 +65,8 @@ impl GridRowTest { } } - pub fn builder(&self) -> CreateRowRevisionBuilder { - CreateRowRevisionBuilder::new(&self.field_revs) + pub fn row_builder(&self) -> GridRowTestBuilder { + GridRowTestBuilder::new(self.block_id(), &self.field_revs) } pub async fn run_script(&mut self, script: RowScript) { @@ -76,8 +78,8 @@ impl GridRowTest { self.row_revs = self.get_row_revs().await; self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); } - RowScript::CreateRow { payload: context } => { - let row_orders = self.editor.insert_rows(vec![context]).await.unwrap(); + RowScript::CreateRow { row_rev } => { + let row_orders = self.editor.insert_rows(vec![row_rev]).await.unwrap(); for row_order in row_orders { self.row_order_by_row_id .insert(row_order.row_id().to_owned(), row_order); @@ -96,6 +98,24 @@ impl GridRowTest { self.row_revs = self.get_row_revs().await; self.block_meta_revs = self.editor.get_block_meta_revs().await.unwrap(); } + RowScript::AssertCell { + row_id, + field_id, + expected_display, + } => { + let id = CellIdentifier { + grid_id: self.grid_id.clone(), + field_id, + row_id, + }; + let display = self.editor.get_cell_display(&id).await; + match expected_display { + None => {} + Some(expected_display) => { + assert_eq!(display.unwrap(), expected_display); + } + } + } RowScript::AssertRow { expected_row } => { let row = &*self .row_revs diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs index 49b8383fee..baf1bf6ae0 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs @@ -1,66 +1,97 @@ -use crate::grid::block_test::script::GridRowTest; - use flowy_grid::entities::FieldType; -use flowy_grid::services::field::DateCellChangeset; -use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; -use flowy_grid_data_model::revision::FieldRevision; +use flowy_grid::services::field::select_option::{SelectOption, SELECTION_IDS_SEPARATOR}; +use flowy_grid::services::field::{DateCellChangeset, MultiSelectTypeOption, SingleSelectTypeOption}; +use flowy_grid::services::row::RowRevisionBuilder; +use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; +use std::sync::Arc; use strum::EnumCount; pub struct GridRowTestBuilder<'a> { - test: &'a GridRowTest, - inner_builder: CreateRowRevisionBuilder<'a>, + block_id: String, + field_revs: &'a [Arc], + inner_builder: RowRevisionBuilder<'a>, } impl<'a> GridRowTestBuilder<'a> { - pub fn new(test: &'a GridRowTest) -> Self { - assert_eq!(test.field_revs().len(), FieldType::COUNT); - - let inner_builder = CreateRowRevisionBuilder::new(test.field_revs()); - Self { test, inner_builder } - } - #[allow(dead_code)] - 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 new(block_id: &str, field_revs: &'a [Arc]) -> Self { + assert_eq!(field_revs.len(), FieldType::COUNT); + let inner_builder = RowRevisionBuilder::new(field_revs); + Self { + block_id: block_id.to_owned(), + field_revs, + inner_builder, + } } - #[allow(dead_code)] - 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 insert_text_cell(&mut self, data: &str) { + let text_field = self.field_rev_with_type(&FieldType::RichText); + self.inner_builder + .insert_cell(&text_field.id, data.to_string()) + .unwrap(); } - #[allow(dead_code)] - pub fn update_date_cell(mut self, value: i64) -> Self { + pub fn insert_number_cell(&mut self, data: &str) { + let number_field = self.field_rev_with_type(&FieldType::Number); + self.inner_builder + .insert_cell(&number_field.id, data.to_string()) + .unwrap(); + } + + pub fn insert_date_cell(&mut self, data: &str) { let value = serde_json::to_string(&DateCellChangeset { - date: Some(value.to_string()), + date: Some(data.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 + self.inner_builder.insert_cell(&date_field.id, value).unwrap(); } - #[allow(dead_code)] - pub fn update_checkbox_cell(mut self, data: bool) -> Self { + pub fn insert_checkbox_cell(&mut self, data: &str) { let number_field = self.field_rev_with_type(&FieldType::Checkbox); - self.inner_builder.add_cell(&number_field.id, data.to_string()).unwrap(); - self + self.inner_builder + .insert_cell(&number_field.id, data.to_string()) + .unwrap(); } - #[allow(dead_code)] - 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 insert_url_cell(&mut self, data: &str) { + let number_field = self.field_rev_with_type(&FieldType::URL); + self.inner_builder + .insert_cell(&number_field.id, data.to_string()) + .unwrap(); + } + + pub fn insert_single_select_cell(&mut self, f: F) + where + F: Fn(&Vec) -> &SelectOption, + { + let single_select_field = self.field_rev_with_type(&FieldType::SingleSelect); + let type_option = SingleSelectTypeOption::from(&single_select_field); + let option = f(&type_option.options); + self.inner_builder + .insert_select_option_cell(&single_select_field.id, option.id.clone()) + .unwrap(); + } + + pub fn insert_multi_select_cell(&mut self, f: F) + where + F: Fn(&Vec) -> &Vec, + { + let multi_select_field = self.field_rev_with_type(&FieldType::MultiSelect); + let type_option = MultiSelectTypeOption::from(&multi_select_field); + let options = f(&type_option.options); + let ops_ids = options + .iter() + .map(|option| option.id.clone()) + .collect::>() + .join(SELECTION_IDS_SEPARATOR); + self.inner_builder + .insert_select_option_cell(&multi_select_field.id, ops_ids) + .unwrap(); } pub fn field_rev_with_type(&self, field_type: &FieldType) -> FieldRevision { - self.test - .field_revs() + self.field_revs .iter() .find(|field_rev| { let t_field_type: FieldType = field_rev.field_type_rev.into(); @@ -71,7 +102,7 @@ impl<'a> GridRowTestBuilder<'a> { .clone() } - pub fn build(self) -> CreateRowRevisionPayload { - self.inner_builder.build() + pub fn build(self) -> RowRevision { + self.inner_builder.build(&self.block_id) } } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index d944aac6c5..85c81c4058 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -6,7 +6,7 @@ use flowy_grid::entities::*; use flowy_grid::services::field::select_option::SelectOption; use flowy_grid::services::field::*; use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; -use flowy_grid::services::row::CreateRowRevisionPayload; +use flowy_grid::services::row::{CreateRowRevisionPayload, RowRevisionBuilder}; use flowy_grid::services::setting::GridSettingChangesetBuilder; use flowy_grid_data_model::revision::*; use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; @@ -20,6 +20,7 @@ use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; use strum::EnumCount; +use strum::IntoEnumIterator; use tokio::time::sleep; pub struct GridEditorTest { @@ -37,14 +38,13 @@ impl GridEditorTest { pub async fn new() -> Self { let sdk = FlowySDKTest::default(); let _ = sdk.init_user().await; - let build_context = make_all_field_test_grid(); + let build_context = make_test_grid(); let view_data: Bytes = build_context.into(); let test = ViewTest::new_grid_view(&sdk, view_data.to_vec()).await; let editor = sdk.grid_manager.open_grid(&test.view.id).await.unwrap(); let field_revs = editor.get_field_revs(None).await.unwrap(); let block_meta_revs = editor.get_block_meta_revs().await.unwrap(); let row_revs = editor.grid_block_snapshots(None).await.unwrap().pop().unwrap().row_revs; - assert_eq!(row_revs.len(), 3); assert_eq!(block_meta_revs.len(), 1); // It seems like you should add the field in the make_test_grid() function. @@ -90,75 +90,98 @@ impl GridEditorTest { .pop() .unwrap() } + + pub fn block_id(&self) -> &str { + &self.block_meta_revs.last().unwrap().block_id + } } -fn make_all_field_test_grid() -> BuildGridContext { - let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) - .name("Name") - .visibility(true) - .build(); +// This grid is assumed to contain all the Fields. +fn make_test_grid() -> BuildGridContext { + let mut grid_builder = GridBuilder::new(); + // Iterate through the FieldType to create the corresponding Field. + for field_type in FieldType::iter() { + let field_type: FieldType = field_type; - // Single Select - let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Live")) - .option(SelectOption::new("Completed")) - .option(SelectOption::new("Planned")) - .option(SelectOption::new("Paused")); - let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); + // The + match field_type { + FieldType::RichText => { + let text_field = FieldBuilder::new(RichTextTypeOptionBuilder::default()) + .name("Name") + .visibility(true) + .build(); + grid_builder.add_field(text_field); + } + FieldType::Number => { + // Number + let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); + let number_field = FieldBuilder::new(number).name("Price").visibility(true).build(); + grid_builder.add_field(number_field); + } + FieldType::DateTime => { + // Date + let date = DateTypeOptionBuilder::default() + .date_format(DateFormat::US) + .time_format(TimeFormat::TwentyFourHour); + let date_field = FieldBuilder::new(date).name("Time").visibility(true).build(); + grid_builder.add_field(date_field); + } + FieldType::SingleSelect => { + // Single Select + let single_select = SingleSelectTypeOptionBuilder::default() + .option(SelectOption::new("Live")) + .option(SelectOption::new("Completed")) + .option(SelectOption::new("Planned")) + .option(SelectOption::new("Paused")); + let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); + grid_builder.add_field(single_select_field); + } + FieldType::MultiSelect => { + // MultiSelect + let multi_select = MultiSelectTypeOptionBuilder::default() + .option(SelectOption::new("Google")) + .option(SelectOption::new("Facebook")) + .option(SelectOption::new("Twitter")); + let multi_select_field = FieldBuilder::new(multi_select) + .name("Platform") + .visibility(true) + .build(); + grid_builder.add_field(multi_select_field); + } + FieldType::Checkbox => { + // Checkbox + let checkbox = CheckboxTypeOptionBuilder::default(); + let checkbox_field = FieldBuilder::new(checkbox).name("is done").visibility(true).build(); + grid_builder.add_field(checkbox_field); + } + FieldType::URL => { + // URL + let url = URLTypeOptionBuilder::default(); + let url_field = FieldBuilder::new(url).name("link").visibility(true).build(); + grid_builder.add_field(url_field); + } + } + } - // MultiSelect - let multi_select = MultiSelectTypeOptionBuilder::default() - .option(SelectOption::new("Google")) - .option(SelectOption::new("Facebook")) - .option(SelectOption::new("Twitter")); - let multi_select_field = FieldBuilder::new(multi_select) - .name("Platform") - .visibility(true) - .build(); - - // Number - let number = NumberTypeOptionBuilder::default().set_format(NumberFormat::USD); - let number_field = FieldBuilder::new(number).name("Price").visibility(true).build(); - - // Date - let date = DateTypeOptionBuilder::default() - .date_format(DateFormat::US) - .time_format(TimeFormat::TwentyFourHour); - let date_field = FieldBuilder::new(date).name("Time").visibility(true).build(); - - // Checkbox - let checkbox = CheckboxTypeOptionBuilder::default(); - let checkbox_field = FieldBuilder::new(checkbox).name("is done").visibility(true).build(); - - // URL - let url = URLTypeOptionBuilder::default(); - let url_field = FieldBuilder::new(url).name("link").visibility(true).build(); - - // for i in 0..3 { - // for field_type in FieldType::iter() { - // let field_type: FieldType = field_type; - // match field_type { - // FieldType::RichText => {} - // FieldType::Number => {} - // FieldType::DateTime => {} - // FieldType::SingleSelect => {} - // FieldType::MultiSelect => {} - // FieldType::Checkbox => {} - // FieldType::URL => {} - // } - // } - // } - - GridBuilder::default() - .add_field(text_field) - .add_field(single_select_field) - .add_field(multi_select_field) - .add_field(number_field) - .add_field(date_field) - .add_field(checkbox_field) - .add_field(url_field) - .add_empty_row() - .add_empty_row() - .add_empty_row() - .build() + // We have many assumptions base on the number of the rows, so do not change the number of the loop. + for _i in 0..10 { + for field_type in FieldType::iter() { + let field_type: FieldType = field_type; + // let mut row_builder = RowRevisionBuilder::new() + match field_type { + FieldType::RichText => {} + FieldType::Number => {} + FieldType::DateTime => {} + FieldType::SingleSelect => {} + FieldType::MultiSelect => {} + FieldType::Checkbox => {} + FieldType::URL => {} + } + } + } + // assert_eq!(row_revs.len(), 10); + // .add_empty_row() + // .add_empty_row() + // .add_empty_row() + grid_builder.build() } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs index d1fbed3f53..1dffa6c0c6 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -26,18 +26,23 @@ impl std::default::Default for GridBuilder { } impl GridBuilder { - pub fn add_field(mut self, field: FieldRevision) -> Self { + pub fn new() -> Self { + Self::default() + } + pub fn add_field(&mut self, field: FieldRevision) { self.build_context.field_revs.push(field); - self } - pub fn add_empty_row(mut self) -> Self { - let row = RowRevision::new(&self.build_context.blocks.first().unwrap().block_id); + pub fn add_row(&mut self, row_rev: RowRevision) { let block_meta_rev = self.build_context.blocks.first_mut().unwrap(); let block_rev = self.build_context.blocks_meta_data.first_mut().unwrap(); - block_rev.rows.push(Arc::new(row)); + block_rev.rows.push(Arc::new(row_rev)); block_meta_rev.row_count += 1; - self + } + + pub fn add_empty_row(&mut self) { + let row = RowRevision::new(&self.build_context.blocks.first().unwrap().block_id); + self.add_row(row); } pub fn build(self) -> BuildGridContext { From 1e3640f8acb88601a9aad9a0cbb578a0a34558f1 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 12 Jul 2022 22:24:01 +0800 Subject: [PATCH 012/112] chore: config cell displayable data --- .../rust-lib/flowy-grid/src/event_handler.rs | 2 +- .../src/services/cell/any_cell_data.rs | 29 ++++++---- .../src/services/cell/cell_operation.rs | 55 +++++++++++-------- .../src/services/field/select_option.rs | 31 +++++++++-- .../type_options/checkbox_type_option.rs | 22 ++++++-- .../field/type_options/date_type_option.rs | 25 ++++++--- .../type_options/multi_select_type_option.rs | 26 +++------ .../number_type_option/number_type_option.rs | 10 ++-- .../type_options/single_select_type_option.rs | 28 ++++------ .../field/type_options/text_type_option.rs | 20 +++++-- .../field/type_options/url_type_option.rs | 24 ++++++-- .../filter/impls/select_option_filter.rs | 4 +- .../flowy-grid/src/services/grid_editor.rs | 2 +- 13 files changed, 171 insertions(+), 107 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index c2faceb9b5..27f3da7cc1 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -376,7 +376,7 @@ pub(crate) async fn get_select_option_handler( }, Some(cell_rev) => cell_rev.try_into()?, }; - let option_context = type_option.selected_select_option(any_cell_data); + let option_context = type_option.selected_select_option(any_cell_data.into()); data_result(option_context) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs b/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs index 259fcc79ef..1b85f3d1a9 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs @@ -100,36 +100,33 @@ impl AnyCellData { /// * Use String to parse the data when the FieldType is RichText, Number, or Checkbox. /// * Check out the implementation of CellDataOperation trait for more information. #[derive(Default)] -pub struct DecodedCellData { - pub data: Vec, -} +pub struct CellBytes(pub Bytes); -impl DecodedCellData { +impl CellBytes { pub fn new>(data: T) -> Self { - Self { - data: data.as_ref().to_vec(), - } + let bytes = Bytes::from(data.as_ref().to_vec()); + Self(bytes) } - pub fn try_from_bytes>(bytes: T) -> FlowyResult + pub fn from>(bytes: T) -> FlowyResult where >::Error: std::fmt::Debug, { let bytes = bytes.try_into().map_err(internal_error)?; - Ok(Self { data: bytes.to_vec() }) + Ok(Self(bytes)) } pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult where >::Error: std::fmt::Debug, { - T::try_from(self.data.as_ref()).map_err(internal_error) + T::try_from(self.0.as_ref()).map_err(internal_error) } } -impl ToString for DecodedCellData { +impl ToString for CellBytes { fn to_string(&self) -> String { - match String::from_utf8(self.data.clone()) { + match String::from_utf8(self.0.to_vec()) { Ok(s) => s, Err(e) => { tracing::error!("DecodedCellData to string failed: {:?}", e); @@ -138,3 +135,11 @@ impl ToString for DecodedCellData { } } } + +impl std::ops::Deref for CellBytes { + type Target = Bytes; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs index 05c331bda8..584623811d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -1,31 +1,45 @@ +use crate::entities::FieldType; +use crate::services::cell::{AnyCellData, CellBytes}; +use crate::services::field::*; + use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, FieldTypeRevision}; -use crate::entities::FieldType; -use crate::services::cell::{AnyCellData, DecodedCellData}; -use crate::services::field::*; - +/// This trait is used when doing filter/search on the grid. pub trait CellFilterOperation { /// Return true if any_cell_data match the filter condition. fn apply_filter(&self, any_cell_data: AnyCellData, filter: &T) -> FlowyResult; } -pub trait CellDataOperation { - /// The cell_data is able to parse into the specific data that was impl the FromCellData trait. +/// Return object that describes the cell. +pub trait CellDisplayable { + fn display_data( + &self, + cell_data: CellData, + decoded_field_type: &FieldType, + field_rev: &FieldRevision, + ) -> FlowyResult; +} + +// CD: Short for CellData. This type is the type return by apply_changeset function. +// CS: Short for Changeset. Parse the string into specific Changeset type. +pub trait CellDataOperation { + /// The cell_data is able to parse into the specific data if CD impl the FromCellData trait. /// For example: /// URLCellData, DateCellData. etc. fn decode_cell_data( &self, - cell_data: CellData, + cell_data: CellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, - ) -> FlowyResult; + ) -> FlowyResult; - /// The changeset is able to parse into the specific data that was impl the FromCellChangeset trait. + /// The changeset is able to parse into the specific data if CS impl the FromCellChangeset trait. /// For example: /// SelectOptionCellChangeset,DateCellChangeset. etc. - fn apply_changeset(&self, changeset: CellDataChangeset, cell_rev: Option) -> FlowyResult; + fn apply_changeset(&self, changeset: CellDataChangeset, cell_rev: Option) -> FlowyResult; } + /// changeset: It will be deserialized into specific data base on the FieldType. /// For example, /// FieldType::RichText => String @@ -53,23 +67,20 @@ pub fn apply_cell_data_changeset>( Ok(AnyCellData::new(s, field_type).json()) } -pub fn decode_any_cell_data>(data: T, field_rev: &FieldRevision) -> DecodedCellData { +pub fn decode_any_cell_data>(data: T, field_rev: &FieldRevision) -> CellBytes { if let Ok(any_cell_data) = data.try_into() { - let AnyCellData { - data: cell_data, - field_type, - } = any_cell_data; + let AnyCellData { data, field_type } = any_cell_data; let to_field_type = field_rev.field_type_rev.into(); - match try_decode_cell_data(CellData(Some(cell_data)), field_rev, &field_type, &to_field_type) { - Ok(cell_data) => cell_data, + match try_decode_cell_data(data.into(), field_rev, &field_type, &to_field_type) { + Ok(cell_bytes) => cell_bytes, Err(e) => { tracing::error!("Decode cell data failed, {:?}", e); - DecodedCellData::default() + CellBytes::default() } } } else { tracing::error!("Decode type option data failed"); - DecodedCellData::default() + CellBytes::default() } } @@ -78,7 +89,7 @@ pub fn try_decode_cell_data( field_rev: &FieldRevision, s_field_type: &FieldType, t_field_type: &FieldType, -) -> FlowyResult { +) -> FlowyResult { let cell_data = cell_data.try_into_inner()?; let get_cell_data = || { let field_type: FieldTypeRevision = t_field_type.into(); @@ -112,9 +123,9 @@ pub fn try_decode_cell_data( Some(Ok(data)) => Ok(data), Some(Err(err)) => { tracing::error!("{:?}", err); - Ok(DecodedCellData::default()) + Ok(CellBytes::default()) } - None => Ok(DecodedCellData::default()), + None => Ok(CellBytes::default()), } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs index 3e974e9f56..d429899587 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs @@ -1,5 +1,5 @@ use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType}; -use crate::services::cell::{AnyCellData, FromCellChangeset, FromCellString}; +use crate::services::cell::{AnyCellData, CellData, CellDisplayable, FromCellChangeset, FromCellString}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; @@ -60,12 +60,11 @@ impl std::default::Default for SelectOptionColor { } } -pub fn make_selected_select_options>( - any_cell_data: T, +pub fn make_selected_select_options( + cell_data: CellData, options: &[SelectOption], ) -> Vec { - if let Ok(type_option_cell_data) = any_cell_data.try_into() { - let ids = SelectOptionIds::from(type_option_cell_data.data); + if let Ok(ids) = cell_data.try_into_inner() { ids.iter() .flat_map(|option_id| options.iter().find(|option| &option.id == option_id).cloned()) .collect() @@ -100,13 +99,27 @@ pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync { SelectOption::with_color(name, color) } - fn selected_select_option(&self, any_cell_data: AnyCellData) -> SelectOptionCellData; + fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellData; fn options(&self) -> &Vec; fn mut_options(&mut self) -> &mut Vec; } +impl CellDisplayable for T +where + T: SelectOptionOperation, +{ + fn display_data( + &self, + cell_data: CellData, + _decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + Ok(self.selected_select_option(cell_data)) + } +} + pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult> { let field_type: FieldType = field_rev.field_type_rev.into(); match &field_type { @@ -155,6 +168,12 @@ impl std::convert::TryFrom for SelectOptionIds { } } +impl std::convert::From for CellData { + fn from(any_cell_data: AnyCellData) -> Self { + any_cell_data.data.into() + } +} + impl FromCellString for SelectOptionIds { fn from_cell_str(s: &str) -> FlowyResult where diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs index 1808f0dc82..3266c04840 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs @@ -1,6 +1,6 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData}; +use crate::services::cell::{AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -40,23 +40,35 @@ impl_type_option!(CheckboxTypeOption, FieldType::Checkbox); const YES: &str = "Yes"; const NO: &str = "No"; +impl CellDisplayable for CheckboxTypeOption { + fn display_data( + &self, + cell_data: CellData, + _decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + let s: String = cell_data.try_into_inner()?; + Ok(s == YES) + } +} + impl CellDataOperation for CheckboxTypeOption { fn decode_cell_data( &self, cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult { + ) -> FlowyResult { if !decoded_field_type.is_checkbox() { - return Ok(DecodedCellData::default()); + return Ok(CellBytes::default()); } let s: String = cell_data.try_into_inner()?; if s == YES || s == NO { - return Ok(DecodedCellData::new(s)); + return Ok(CellBytes::new(s)); } - Ok(DecodedCellData::default()) + Ok(CellBytes::default()) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 2200dad63c..f26e29de53 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -2,7 +2,8 @@ use crate::entities::{CellChangeset, FieldType}; use crate::entities::{CellIdentifier, CellIdentifierPayload}; use crate::impl_type_option; use crate::services::cell::{ - AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData, FromCellChangeset, FromCellString, + AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, FromCellChangeset, + FromCellString, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; @@ -121,23 +122,33 @@ impl DateTypeOption { } } +impl CellDisplayable for DateTypeOption { + fn display_data( + &self, + cell_data: CellData, + _decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + let timestamp = cell_data.try_into_inner()?; + Ok(self.today_desc_from_timestamp(timestamp.0)) + } +} + impl CellDataOperation for DateTypeOption { fn decode_cell_data( &self, cell_data: CellData, decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { + field_rev: &FieldRevision, + ) -> FlowyResult { // Return default data if the type_option_cell_data is not FieldType::DateTime. // It happens when switching from one field to another. // For example: // FieldType::RichText -> FieldType::DateTime, it will display empty content on the screen. if !decoded_field_type.is_date() { - return Ok(DecodedCellData::default()); + return Ok(CellBytes::default()); } - let timestamp = cell_data.try_into_inner()?; - let date = self.today_desc_from_timestamp(timestamp.0); - DecodedCellData::try_from_bytes(date) + CellBytes::from(self.display_data(cell_data, decoded_field_type, field_rev)?) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs index 209ed234f7..902170307b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs @@ -1,7 +1,7 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData}; +use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; use crate::services::field::select_option::{ make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, SelectOptionOperation, SELECTION_IDS_SEPARATOR, @@ -28,8 +28,8 @@ pub struct MultiSelectTypeOption { impl_type_option!(MultiSelectTypeOption, FieldType::MultiSelect); impl SelectOptionOperation for MultiSelectTypeOption { - fn selected_select_option(&self, any_cell_data: AnyCellData) -> SelectOptionCellData { - let select_options = make_selected_select_options(any_cell_data, &self.options); + fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellData { + let select_options = make_selected_select_options(cell_data, &self.options); SelectOptionCellData { options: self.options.clone(), select_options, @@ -50,24 +50,14 @@ impl CellDataOperation for MultiSele &self, cell_data: CellData, decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { + field_rev: &FieldRevision, + ) -> FlowyResult { if !decoded_field_type.is_select_option() { - return Ok(DecodedCellData::default()); + return Ok(CellBytes::default()); } - let ids: SelectOptionIds = cell_data.try_into_inner()?; - let select_options = ids - .iter() - .flat_map(|option_id| self.options.iter().find(|option| &option.id == option_id).cloned()) - .collect::>(); - - let cell_data = SelectOptionCellData { - options: self.options.clone(), - select_options, - }; - - DecodedCellData::try_from_bytes(cell_data) + let cell_data = self.display_data(cell_data, decoded_field_type, field_rev)?; + CellBytes::from(cell_data) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs index c8f79df20c..c1c3dbdae3 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs @@ -1,7 +1,7 @@ use crate::impl_type_option; use crate::entities::FieldType; -use crate::services::cell::{CellData, CellDataChangeset, CellDataOperation, DecodedCellData}; +use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation}; use crate::services::field::number_currency::Currency; use crate::services::field::type_options::number_type_option::format::*; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; @@ -110,15 +110,15 @@ impl CellDataOperation for NumberTypeOption { cell_data: CellData, decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult { + ) -> FlowyResult { if decoded_field_type.is_date() { - return Ok(DecodedCellData::default()); + return Ok(CellBytes::default()); } let cell_data: String = cell_data.try_into_inner()?; match self.format_cell_data(&cell_data) { - Ok(num) => Ok(DecodedCellData::new(num.to_string())), - Err(_) => Ok(DecodedCellData::default()), + Ok(num) => Ok(CellBytes::new(num.to_string())), + Err(_) => Ok(CellBytes::default()), } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs index 6094f8567b..35a2ac4853 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs @@ -1,6 +1,6 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData}; +use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; use crate::services::field::select_option::{ make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, SelectOptionOperation, @@ -24,8 +24,10 @@ pub struct SingleSelectTypeOption { impl_type_option!(SingleSelectTypeOption, FieldType::SingleSelect); impl SelectOptionOperation for SingleSelectTypeOption { - fn selected_select_option(&self, any_cell_data: AnyCellData) -> SelectOptionCellData { - let select_options = make_selected_select_options(any_cell_data, &self.options); + fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellData { + let mut select_options = make_selected_select_options(cell_data, &self.options); + // only keep option in single select + select_options.truncate(1); SelectOptionCellData { options: self.options.clone(), select_options, @@ -46,24 +48,14 @@ impl CellDataOperation for SingleSel &self, cell_data: CellData, decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { + field_rev: &FieldRevision, + ) -> FlowyResult { if !decoded_field_type.is_select_option() { - return Ok(DecodedCellData::default()); + return Ok(CellBytes::default()); } - let ids: SelectOptionIds = cell_data.try_into_inner()?; - let mut cell_data = SelectOptionCellData { - options: self.options.clone(), - select_options: vec![], - }; - if let Some(option_id) = ids.first() { - if let Some(option) = self.options.iter().find(|option| &option.id == option_id) { - cell_data.select_options.push(option.clone()); - } - } - - DecodedCellData::try_from_bytes(cell_data) + let cell_data = self.display_data(cell_data, decoded_field_type, field_rev)?; + CellBytes::from(cell_data) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs index a23366e2a4..4d4b4e65fc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -1,7 +1,7 @@ use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{ - try_decode_cell_data, AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData, + try_decode_cell_data, AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; @@ -32,13 +32,25 @@ pub struct RichTextTypeOption { } impl_type_option!(RichTextTypeOption, FieldType::RichText); +impl CellDisplayable for RichTextTypeOption { + fn display_data( + &self, + cell_data: CellData, + _decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + let cell_str: String = cell_data.try_into_inner()?; + Ok(cell_str) + } +} + impl CellDataOperation for RichTextTypeOption { fn decode_cell_data( &self, cell_data: CellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, - ) -> FlowyResult { + ) -> FlowyResult { if decoded_field_type.is_date() || decoded_field_type.is_single_select() || decoded_field_type.is_multi_select() @@ -46,8 +58,8 @@ impl CellDataOperation for RichTextTypeOption { { try_decode_cell_data(cell_data, field_rev, decoded_field_type, decoded_field_type) } else { - let cell_data: String = cell_data.try_into_inner()?; - Ok(DecodedCellData::new(cell_data)) + let content = self.display_data(cell_data, decoded_field_type, field_rev)?; + Ok(CellBytes::new(content)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs index 74fc9fc26b..18144e3f2a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs @@ -1,7 +1,7 @@ use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{ - AnyCellData, CellData, CellDataChangeset, CellDataOperation, DecodedCellData, FromCellString, + AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, FromCellString, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; @@ -34,18 +34,30 @@ pub struct URLTypeOption { } impl_type_option!(URLTypeOption, FieldType::URL); +impl CellDisplayable for URLTypeOption { + fn display_data( + &self, + cell_data: CellData, + _decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + let cell_data: URLCellData = cell_data.try_into_inner()?; + Ok(cell_data) + } +} + impl CellDataOperation for URLTypeOption { fn decode_cell_data( &self, cell_data: CellData, decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { + field_rev: &FieldRevision, + ) -> FlowyResult { if !decoded_field_type.is_url() { - return Ok(DecodedCellData::default()); + return Ok(CellBytes::default()); } - let cell_data: URLCellData = cell_data.try_into_inner()?; - DecodedCellData::try_from_bytes(cell_data) + let cell_data = self.display_data(cell_data, decoded_field_type, field_rev)?; + CellBytes::from(cell_data) } fn apply_changeset( diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs index cd25bfef0e..3ef3a77b84 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs @@ -45,7 +45,7 @@ impl CellFilterOperation for MultiSelectTypeOption { return Ok(true); } - let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data)); + let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data.into())); Ok(filter.is_visible(&selected_options)) } } @@ -55,7 +55,7 @@ impl CellFilterOperation for SingleSelectTypeOption { if !any_cell_data.is_single_select() { return Ok(true); } - let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data)); + let selected_options = SelectedSelectOptions::from(self.selected_select_option(any_cell_data.into())); Ok(filter.is_visible(&selected_options)) } } 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 93d9317565..919e24f2bf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -344,7 +344,7 @@ impl GridRevisionEditor { let row_rev = self.block_manager.get_row_rev(¶ms.row_id).await.ok()??; let cell_rev = row_rev.cells.get(¶ms.field_id)?.clone(); - let data = decode_any_cell_data(cell_rev.data, &field_rev).data; + let data = decode_any_cell_data(cell_rev.data, &field_rev).to_vec(); Some(Cell::new(¶ms.field_id, data)) } From f10e324b735a1d0cabdddae8c1694502072b00b0 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 13 Jul 2022 11:09:13 +0800 Subject: [PATCH 013/112] refactor: type options directory --- frontend/rust-lib/flowy-grid/Flowy.toml | 1 - .../filter_entities/select_option_filter.rs | 2 +- .../rust-lib/flowy-grid/src/event_handler.rs | 6 +- .../src/services/cell/cell_operation.rs | 4 +- .../flowy-grid/src/services/field/mod.rs | 1 - .../type_options/checkbox_type_option.rs | 145 ---- .../checkbox_type_option/checkbox_option.rs | 75 ++ .../checkbox_option_entities.rs | 61 ++ .../type_options/checkbox_type_option/mod.rs | 6 + .../checkbox_type_option/tests.rs | 30 + .../field/type_options/date_type_option.rs | 672 ------------------ .../date_type_option/date_option.rs | 199 ++++++ .../date_type_option/date_option_entities.rs | 206 ++++++ .../type_options/date_type_option/mod.rs | 6 + .../type_options/date_type_option/tests.rs | 272 +++++++ .../src/services/field/type_options/mod.rs | 17 +- .../type_options/number_type_option/mod.rs | 7 +- .../number_type_option/number_option.rs | 149 ++++ .../number_option_entities.rs | 93 +++ .../number_type_option/number_type_option.rs | 376 ---------- .../type_options/number_type_option/tests.rs | 139 ++++ .../type_options/selection_type_option/mod.rs | 7 + .../multi_select_type_option.rs | 17 +- .../selection_type_option}/select_option.rs | 8 +- .../single_select_type_option.rs | 7 +- .../type_options/text_type_option/mod.rs | 2 + .../text_option.rs} | 11 +- .../field/type_options/url_type_option.rs | 206 ------ .../field/type_options/url_type_option/mod.rs | 6 + .../type_options/url_type_option/tests.rs | 67 ++ .../url_type_option/url_option.rs | 101 +++ .../url_type_option/url_option_entities.rs | 40 ++ .../services/field/type_options/util/mod.rs | 1 - .../filter/impls/select_option_filter.rs | 4 +- .../src/services/row/row_builder.rs | 2 +- .../flowy-grid/tests/grid/block_test/util.rs | 2 +- .../flowy-grid/tests/grid/cell_test/test.rs | 2 +- .../flowy-grid/tests/grid/field_test/test.rs | 2 +- .../flowy-grid/tests/grid/field_test/util.rs | 2 +- .../flowy-grid/tests/grid/grid_editor.rs | 2 +- 40 files changed, 1504 insertions(+), 1452 deletions(-) delete mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/tests.rs delete mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/tests.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs delete mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/tests.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/mod.rs rename frontend/rust-lib/flowy-grid/src/services/field/type_options/{ => selection_type_option}/multi_select_type_option.rs (93%) rename frontend/rust-lib/flowy-grid/src/services/field/{ => type_options/selection_type_option}/select_option.rs (97%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/{ => selection_type_option}/single_select_type_option.rs (96%) create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs rename frontend/rust-lib/flowy-grid/src/services/field/type_options/{text_type_option.rs => text_type_option/text_option.rs} (95%) delete mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/tests.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs diff --git a/frontend/rust-lib/flowy-grid/Flowy.toml b/frontend/rust-lib/flowy-grid/Flowy.toml index 94bd0c0225..00e9cf7c04 100644 --- a/frontend/rust-lib/flowy-grid/Flowy.toml +++ b/frontend/rust-lib/flowy-grid/Flowy.toml @@ -2,7 +2,6 @@ proto_input = [ "src/event_map.rs", "src/services/field/type_options", - "src/services/field/select_option.rs", "src/entities", "src/dart_notification.rs" ] diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs index 73c39cb657..9eb4ff3fe9 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/select_option_filter.rs @@ -1,4 +1,4 @@ -use crate::services::field::select_option::SelectOptionIds; +use crate::services::field::SelectOptionIds; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::revision::GridFilterRevision; diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 27f3da7cc1..52c3c3424c 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -1,9 +1,11 @@ use crate::entities::*; use crate::manager::GridManager; use crate::services::cell::AnyCellData; -use crate::services::field::select_option::*; use crate::services::field::{ - default_type_option_builder_from_type, type_option_builder_from_json_str, DateChangesetParams, DateChangesetPayload, + default_type_option_builder_from_type, select_option_operation, type_option_builder_from_json_str, + DateChangesetParams, DateChangesetPayload, SelectOption, SelectOptionCellChangeset, + SelectOptionCellChangesetParams, SelectOptionCellChangesetPayload, SelectOptionCellData, SelectOptionChangeset, + SelectOptionChangesetPayload, }; use crate::services::row::make_row_from_row_rev; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs index 584623811d..4bbeafa814 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -12,13 +12,13 @@ pub trait CellFilterOperation { } /// Return object that describes the cell. -pub trait CellDisplayable { +pub trait CellDisplayable { fn display_data( &self, cell_data: CellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, - ) -> FlowyResult; + ) -> FlowyResult; } // CD: Short for CellData. This type is the type return by apply_changeset function. diff --git a/frontend/rust-lib/flowy-grid/src/services/field/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/mod.rs index 8a01d90d1f..c1b689fbf4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/mod.rs @@ -1,5 +1,4 @@ mod field_builder; -pub mod select_option; pub(crate) mod type_options; pub use field_builder::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs deleted file mode 100644 index 3266c04840..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs +++ /dev/null @@ -1,145 +0,0 @@ -use crate::entities::FieldType; -use crate::impl_type_option; -use crate::services::cell::{AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use bytes::Bytes; -use flowy_derive::ProtoBuf; -use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; -use serde::{Deserialize, Serialize}; - -#[derive(Default)] -pub struct CheckboxTypeOptionBuilder(CheckboxTypeOption); -impl_into_box_type_option_builder!(CheckboxTypeOptionBuilder); -impl_builder_from_json_str_and_from_bytes!(CheckboxTypeOptionBuilder, CheckboxTypeOption); - -impl CheckboxTypeOptionBuilder { - pub fn set_selected(mut self, is_selected: bool) -> Self { - self.0.is_selected = is_selected; - self - } -} - -impl TypeOptionBuilder for CheckboxTypeOptionBuilder { - fn field_type(&self) -> FieldType { - FieldType::Checkbox - } - - fn entry(&self) -> &dyn TypeOptionDataEntry { - &self.0 - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)] -pub struct CheckboxTypeOption { - #[pb(index = 1)] - pub is_selected: bool, -} -impl_type_option!(CheckboxTypeOption, FieldType::Checkbox); - -const YES: &str = "Yes"; -const NO: &str = "No"; - -impl CellDisplayable for CheckboxTypeOption { - fn display_data( - &self, - cell_data: CellData, - _decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { - let s: String = cell_data.try_into_inner()?; - Ok(s == YES) - } -} - -impl CellDataOperation for CheckboxTypeOption { - fn decode_cell_data( - &self, - cell_data: CellData, - decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { - if !decoded_field_type.is_checkbox() { - return Ok(CellBytes::default()); - } - - let s: String = cell_data.try_into_inner()?; - if s == YES || s == NO { - return Ok(CellBytes::new(s)); - } - - Ok(CellBytes::default()) - } - - fn apply_changeset( - &self, - changeset: CellDataChangeset, - _cell_rev: Option, - ) -> Result { - let changeset = changeset.try_into_inner()?; - let s = match string_to_bool(&changeset) { - true => YES, - false => NO, - }; - Ok(s.to_string()) - } -} - -fn string_to_bool(bool_str: &str) -> bool { - let lower_case_str: &str = &bool_str.to_lowercase(); - match lower_case_str { - "1" => true, - "true" => true, - "yes" => true, - "0" => false, - "false" => false, - "no" => false, - _ => false, - } -} - -pub struct CheckboxCellData(pub String); - -impl CheckboxCellData { - pub fn is_check(&self) -> bool { - string_to_bool(&self.0) - } -} -impl std::convert::TryFrom for CheckboxCellData { - type Error = FlowyError; - - fn try_from(_value: AnyCellData) -> Result { - todo!() - } -} - -#[cfg(test)] -mod tests { - use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data}; - use crate::services::field::type_options::checkbox_type_option::{NO, YES}; - use crate::services::field::FieldBuilder; - - use crate::entities::FieldType; - - #[test] - fn checkout_box_description_test() { - let field_rev = FieldBuilder::from_field_type(&FieldType::Checkbox).build(); - let data = apply_cell_data_changeset("true", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev).to_string(), YES); - - let data = apply_cell_data_changeset("1", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES); - - let data = apply_cell_data_changeset("yes", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES); - - let data = apply_cell_data_changeset("false", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); - - let data = apply_cell_data_changeset("no", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); - - let data = apply_cell_data_changeset("12", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs new file mode 100644 index 0000000000..b6e1d39410 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs @@ -0,0 +1,75 @@ +use crate::entities::FieldType; +use crate::impl_type_option; +use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; +use crate::services::field::{BoxTypeOptionBuilder, CheckboxCellData, TypeOptionBuilder}; +use bytes::Bytes; +use flowy_derive::ProtoBuf; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; +use serde::{Deserialize, Serialize}; + +#[derive(Default)] +pub struct CheckboxTypeOptionBuilder(CheckboxTypeOption); +impl_into_box_type_option_builder!(CheckboxTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(CheckboxTypeOptionBuilder, CheckboxTypeOption); + +impl CheckboxTypeOptionBuilder { + pub fn set_selected(mut self, is_selected: bool) -> Self { + self.0.is_selected = is_selected; + self + } +} + +impl TypeOptionBuilder for CheckboxTypeOptionBuilder { + fn field_type(&self) -> FieldType { + FieldType::Checkbox + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)] +pub struct CheckboxTypeOption { + #[pb(index = 1)] + pub is_selected: bool, +} +impl_type_option!(CheckboxTypeOption, FieldType::Checkbox); + +impl CellDisplayable for CheckboxTypeOption { + fn display_data( + &self, + cell_data: CellData, + _decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + let cell_data = cell_data.try_into_inner()?; + Ok(CellBytes::new(cell_data)) + } +} + +impl CellDataOperation for CheckboxTypeOption { + fn decode_cell_data( + &self, + cell_data: CellData, + decoded_field_type: &FieldType, + field_rev: &FieldRevision, + ) -> FlowyResult { + if !decoded_field_type.is_checkbox() { + return Ok(CellBytes::default()); + } + + self.display_data(cell_data, decoded_field_type, field_rev) + } + + fn apply_changeset( + &self, + changeset: CellDataChangeset, + _cell_rev: Option, + ) -> Result { + let changeset = changeset.try_into_inner()?; + let cell_data = CheckboxCellData::from_str(&changeset); + Ok(cell_data.to_string()) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs new file mode 100644 index 0000000000..99f9866d41 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs @@ -0,0 +1,61 @@ +use crate::services::cell::{AnyCellData, FromCellString}; +use flowy_error::{FlowyError, FlowyResult}; + +pub const YES: &str = "Yes"; +pub const NO: &str = "No"; + +pub struct CheckboxCellData(pub String); + +impl CheckboxCellData { + pub fn from_str(s: &str) -> Self { + let lower_case_str: &str = &s.to_lowercase(); + let val = match lower_case_str { + "1" => Some(true), + "true" => Some(true), + "yes" => Some(true), + "0" => Some(false), + "false" => Some(false), + "no" => Some(false), + _ => None, + }; + + match val { + Some(true) => Self(YES.to_string()), + Some(false) => Self(NO.to_string()), + None => Self("".to_string()), + } + } + + pub fn is_check(&self) -> bool { + &self.0 == YES + } +} + +impl AsRef<[u8]> for CheckboxCellData { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl std::convert::TryFrom for CheckboxCellData { + type Error = FlowyError; + + fn try_from(value: AnyCellData) -> Result { + Ok(Self::from_str(&value.data)) + } +} + +impl FromCellString for CheckboxCellData { + fn from_cell_str(s: &str) -> FlowyResult + where + Self: Sized, + { + Ok(Self::from_str(s)) + } +} + +impl ToString for CheckboxCellData { + fn to_string(&self) -> String { + self.0.clone() + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs new file mode 100644 index 0000000000..705b9bcdb0 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs @@ -0,0 +1,6 @@ +mod checkbox_option; +mod checkbox_option_entities; +mod tests; + +pub use checkbox_option::*; +pub use checkbox_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/tests.rs new file mode 100644 index 0000000000..9e041cc415 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/tests.rs @@ -0,0 +1,30 @@ +#[cfg(test)] +mod tests { + use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data}; + use crate::services::field::type_options::checkbox_type_option::{NO, YES}; + use crate::services::field::FieldBuilder; + + use crate::entities::FieldType; + + #[test] + fn checkout_box_description_test() { + let field_rev = FieldBuilder::from_field_type(&FieldType::Checkbox).build(); + let data = apply_cell_data_changeset("true", None, &field_rev).unwrap(); + assert_eq!(decode_any_cell_data(data, &field_rev).to_string(), YES); + + let data = apply_cell_data_changeset("1", None, &field_rev).unwrap(); + assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES); + + let data = apply_cell_data_changeset("yes", None, &field_rev).unwrap(); + assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES); + + let data = apply_cell_data_changeset("false", None, &field_rev).unwrap(); + assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); + + let data = apply_cell_data_changeset("no", None, &field_rev).unwrap(); + assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); + + let data = apply_cell_data_changeset("12", None, &field_rev).unwrap(); + assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs deleted file mode 100644 index f26e29de53..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ /dev/null @@ -1,672 +0,0 @@ -use crate::entities::{CellChangeset, FieldType}; -use crate::entities::{CellIdentifier, CellIdentifierPayload}; -use crate::impl_type_option; -use crate::services::cell::{ - AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, FromCellChangeset, - FromCellString, -}; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use bytes::Bytes; -use chrono::format::strftime::StrftimeItems; -use chrono::{NaiveDateTime, Timelike}; -use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; -use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; -use serde::{Deserialize, Serialize}; -use strum_macros::EnumIter; - -// Date -#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] -pub struct DateTypeOption { - #[pb(index = 1)] - pub date_format: DateFormat, - - #[pb(index = 2)] - pub time_format: TimeFormat, - - #[pb(index = 3)] - pub include_time: bool, -} -impl_type_option!(DateTypeOption, FieldType::DateTime); - -impl DateTypeOption { - #[allow(dead_code)] - pub fn new() -> Self { - Self::default() - } - - fn today_desc_from_timestamp(&self, timestamp: i64) -> DateCellData { - let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0); - self.date_from_native(native) - } - - fn date_from_native(&self, native: chrono::NaiveDateTime) -> DateCellData { - if native.timestamp() == 0 { - return DateCellData::default(); - } - - let time = native.time(); - let has_time = time.hour() != 0 || time.second() != 0; - - let utc = self.utc_date_time_from_native(native); - let fmt = self.date_format.format_str(); - let date = format!("{}", utc.format_with_items(StrftimeItems::new(fmt))); - - let mut time = "".to_string(); - if has_time { - let fmt = format!("{} {}", self.date_format.format_str(), self.time_format.format_str()); - time = format!("{}", utc.format_with_items(StrftimeItems::new(&fmt))).replace(&date, ""); - } - - let timestamp = native.timestamp(); - DateCellData { date, time, timestamp } - } - - fn date_fmt(&self, time: &Option) -> String { - if self.include_time { - match time.as_ref() { - None => self.date_format.format_str().to_string(), - Some(time_str) => { - if time_str.is_empty() { - self.date_format.format_str().to_string() - } else { - format!("{} {}", self.date_format.format_str(), self.time_format.format_str()) - } - } - } - } else { - self.date_format.format_str().to_string() - } - } - - fn timestamp_from_utc_with_time( - &self, - utc: &chrono::DateTime, - time: &Option, - ) -> FlowyResult { - if let Some(time_str) = time.as_ref() { - if !time_str.is_empty() { - let date_str = format!( - "{}{}", - utc.format_with_items(StrftimeItems::new(self.date_format.format_str())), - &time_str - ); - - return match NaiveDateTime::parse_from_str(&date_str, &self.date_fmt(time)) { - Ok(native) => { - let utc = self.utc_date_time_from_native(native); - Ok(utc.timestamp()) - } - Err(_e) => { - let msg = format!("Parse {} failed", date_str); - Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg)) - } - }; - } - } - - Ok(utc.timestamp()) - } - - fn utc_date_time_from_timestamp(&self, timestamp: i64) -> chrono::DateTime { - let native = NaiveDateTime::from_timestamp(timestamp, 0); - let native2 = NaiveDateTime::from_timestamp(timestamp, 0); - - if native > native2 {} - - self.utc_date_time_from_native(native) - } - - fn utc_date_time_from_native(&self, naive: chrono::NaiveDateTime) -> chrono::DateTime { - chrono::DateTime::::from_utc(naive, chrono::Utc) - } -} - -impl CellDisplayable for DateTypeOption { - fn display_data( - &self, - cell_data: CellData, - _decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { - let timestamp = cell_data.try_into_inner()?; - Ok(self.today_desc_from_timestamp(timestamp.0)) - } -} - -impl CellDataOperation for DateTypeOption { - fn decode_cell_data( - &self, - cell_data: CellData, - decoded_field_type: &FieldType, - field_rev: &FieldRevision, - ) -> FlowyResult { - // Return default data if the type_option_cell_data is not FieldType::DateTime. - // It happens when switching from one field to another. - // For example: - // FieldType::RichText -> FieldType::DateTime, it will display empty content on the screen. - if !decoded_field_type.is_date() { - return Ok(CellBytes::default()); - } - CellBytes::from(self.display_data(cell_data, decoded_field_type, field_rev)?) - } - - fn apply_changeset( - &self, - changeset: CellDataChangeset, - _cell_rev: Option, - ) -> Result { - let changeset = changeset.try_into_inner()?; - let cell_data = match changeset.date_timestamp() { - None => 0, - Some(date_timestamp) => match (self.include_time, changeset.time) { - (true, Some(time)) => { - let time = Some(time.trim().to_uppercase()); - let utc = self.utc_date_time_from_timestamp(date_timestamp); - self.timestamp_from_utc_with_time(&utc, &time)? - } - _ => date_timestamp, - }, - }; - - Ok(cell_data.to_string()) - } -} - -pub struct DateTimestamp(i64); -impl AsRef for DateTimestamp { - fn as_ref(&self) -> &i64 { - &self.0 - } -} - -impl std::convert::From for i64 { - fn from(timestamp: DateTimestamp) -> Self { - timestamp.0 - } -} - -impl FromCellString for DateTimestamp { - fn from_cell_str(s: &str) -> FlowyResult - where - Self: Sized, - { - let num = s.parse::().unwrap_or(0); - Ok(DateTimestamp(num)) - } -} - -impl std::convert::From for DateTimestamp { - fn from(data: AnyCellData) -> Self { - let num = data.data.parse::().unwrap_or(0); - DateTimestamp(num) - } -} - -#[derive(Default)] -pub struct DateTypeOptionBuilder(DateTypeOption); -impl_into_box_type_option_builder!(DateTypeOptionBuilder); -impl_builder_from_json_str_and_from_bytes!(DateTypeOptionBuilder, DateTypeOption); - -impl DateTypeOptionBuilder { - pub fn date_format(mut self, date_format: DateFormat) -> Self { - self.0.date_format = date_format; - self - } - - pub fn time_format(mut self, time_format: TimeFormat) -> Self { - self.0.time_format = time_format; - self - } -} -impl TypeOptionBuilder for DateTypeOptionBuilder { - fn field_type(&self) -> FieldType { - FieldType::DateTime - } - - fn entry(&self) -> &dyn TypeOptionDataEntry { - &self.0 - } -} - -#[derive(Clone, Debug, Copy, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)] -pub enum DateFormat { - Local = 0, - US = 1, - ISO = 2, - Friendly = 3, -} -impl std::default::Default for DateFormat { - fn default() -> Self { - DateFormat::Friendly - } -} - -impl std::convert::From for DateFormat { - fn from(value: i32) -> Self { - match value { - 0 => DateFormat::Local, - 1 => DateFormat::US, - 2 => DateFormat::ISO, - 3 => DateFormat::Friendly, - _ => { - tracing::error!("Unsupported date format, fallback to friendly"); - DateFormat::Friendly - } - } - } -} - -impl DateFormat { - pub fn value(&self) -> i32 { - *self as i32 - } - // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html - pub fn format_str(&self) -> &'static str { - match self { - DateFormat::Local => "%Y/%m/%d", - DateFormat::US => "%Y/%m/%d", - DateFormat::ISO => "%Y-%m-%d", - DateFormat::Friendly => "%b %d,%Y", - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, EnumIter, Debug, Hash, Serialize, Deserialize, ProtoBuf_Enum)] -pub enum TimeFormat { - TwelveHour = 0, - TwentyFourHour = 1, -} - -impl std::convert::From for TimeFormat { - fn from(value: i32) -> Self { - match value { - 0 => TimeFormat::TwelveHour, - 1 => TimeFormat::TwentyFourHour, - _ => { - tracing::error!("Unsupported time format, fallback to TwentyFourHour"); - TimeFormat::TwentyFourHour - } - } - } -} - -impl TimeFormat { - pub fn value(&self) -> i32 { - *self as i32 - } - - // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html - pub fn format_str(&self) -> &'static str { - match self { - TimeFormat::TwelveHour => "%I:%M %p", - TimeFormat::TwentyFourHour => "%R", - } - } -} - -impl std::default::Default for TimeFormat { - fn default() -> Self { - TimeFormat::TwentyFourHour - } -} - -#[derive(Clone, Debug, Default, ProtoBuf)] -pub struct DateCellData { - #[pb(index = 1)] - pub date: String, - - #[pb(index = 2)] - pub time: String, - - #[pb(index = 3)] - pub timestamp: i64, -} - -#[derive(Clone, Debug, Default, ProtoBuf)] -pub struct DateChangesetPayload { - #[pb(index = 1)] - pub cell_identifier: CellIdentifierPayload, - - #[pb(index = 2, one_of)] - pub date: Option, - - #[pb(index = 3, one_of)] - pub time: Option, -} - -pub struct DateChangesetParams { - pub cell_identifier: CellIdentifier, - pub date: Option, - pub time: Option, -} - -impl TryInto for DateChangesetPayload { - type Error = ErrorCode; - - fn try_into(self) -> Result { - let cell_identifier: CellIdentifier = self.cell_identifier.try_into()?; - Ok(DateChangesetParams { - cell_identifier, - date: self.date, - time: self.time, - }) - } -} - -impl std::convert::From for CellChangeset { - fn from(params: DateChangesetParams) -> Self { - let changeset = DateCellChangeset { - date: params.date, - time: params.time, - }; - let s = serde_json::to_string(&changeset).unwrap(); - CellChangeset { - grid_id: params.cell_identifier.grid_id, - row_id: params.cell_identifier.row_id, - field_id: params.cell_identifier.field_id, - content: Some(s), - } - } -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct DateCellChangeset { - pub date: Option, - pub time: Option, -} - -impl DateCellChangeset { - pub fn date_timestamp(&self) -> Option { - if let Some(date) = &self.date { - match date.parse::() { - Ok(date_timestamp) => Some(date_timestamp), - Err(_) => None, - } - } else { - None - } - } -} - -impl FromCellChangeset for DateCellChangeset { - fn from_changeset(changeset: String) -> FlowyResult - where - Self: Sized, - { - serde_json::from_str::(&changeset).map_err(internal_error) - } -} - -#[cfg(test)] -mod tests { - use crate::entities::FieldType; - use crate::services::cell::{CellDataChangeset, CellDataOperation}; - use crate::services::field::FieldBuilder; - use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; - use flowy_grid_data_model::revision::FieldRevision; - use strum::IntoEnumIterator; - - #[test] - fn date_type_option_invalid_input_test() { - let type_option = DateTypeOption::default(); - let field_type = FieldType::DateTime; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some("1e".to_string()), - time: Some("23:00".to_owned()), - }, - &field_type, - &field_rev, - "", - ); - } - - #[test] - fn date_type_option_date_format_test() { - let mut type_option = DateTypeOption::default(); - let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); - for date_format in DateFormat::iter() { - type_option.date_format = date_format; - match date_format { - DateFormat::Friendly => { - assert_decode_timestamp(1647251762, &type_option, &field_rev, "Mar 14,2022"); - } - DateFormat::US => { - assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022/03/14"); - } - DateFormat::ISO => { - assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022-03-14"); - } - DateFormat::Local => { - assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022/03/14"); - } - } - } - } - - #[test] - fn date_type_option_time_format_test() { - let mut type_option = DateTypeOption::default(); - let field_type = FieldType::DateTime; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - - for time_format in TimeFormat::iter() { - type_option.time_format = time_format; - type_option.include_time = true; - match time_format { - TimeFormat::TwentyFourHour => { - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(1653609600.to_string()), - time: None, - }, - &field_type, - &field_rev, - "May 27,2022", - ); - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(1653609600.to_string()), - time: Some("23:00".to_owned()), - }, - &field_type, - &field_rev, - "May 27,2022 23:00", - ); - } - TimeFormat::TwelveHour => { - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(1653609600.to_string()), - time: None, - }, - &field_type, - &field_rev, - "May 27,2022", - ); - // - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(1653609600.to_string()), - time: Some("".to_owned()), - }, - &field_type, - &field_rev, - "May 27,2022", - ); - - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(1653609600.to_string()), - time: Some("11:23 pm".to_owned()), - }, - &field_type, - &field_rev, - "May 27,2022 11:23 PM", - ); - } - } - } - } - - #[test] - fn date_type_option_apply_changeset_test() { - let mut type_option = DateTypeOption::new(); - let field_type = FieldType::DateTime; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - let date_timestamp = "1653609600".to_owned(); - - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(date_timestamp.clone()), - time: None, - }, - &field_type, - &field_rev, - "May 27,2022", - ); - - type_option.include_time = true; - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(date_timestamp.clone()), - time: None, - }, - &field_type, - &field_rev, - "May 27,2022", - ); - - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(date_timestamp.clone()), - time: Some("1:00".to_owned()), - }, - &field_type, - &field_rev, - "May 27,2022 01:00", - ); - - type_option.time_format = TimeFormat::TwelveHour; - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(date_timestamp), - time: Some("1:00 am".to_owned()), - }, - &field_type, - &field_rev, - "May 27,2022 01:00 AM", - ); - } - - #[test] - #[should_panic] - fn date_type_option_apply_changeset_error_test() { - let mut type_option = DateTypeOption::new(); - type_option.include_time = true; - let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); - let date_timestamp = "1653609600".to_owned(); - - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(date_timestamp.clone()), - time: Some("1:".to_owned()), - }, - &FieldType::DateTime, - &field_rev, - "May 27,2022 01:00", - ); - - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(date_timestamp), - time: Some("1:00".to_owned()), - }, - &FieldType::DateTime, - &field_rev, - "May 27,2022 01:00", - ); - } - - #[test] - #[should_panic] - fn date_type_option_twelve_hours_to_twenty_four_hours() { - let mut type_option = DateTypeOption::new(); - type_option.include_time = true; - let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); - let date_timestamp = "1653609600".to_owned(); - - assert_changeset_result( - &type_option, - DateCellChangeset { - date: Some(date_timestamp), - time: Some("1:00 am".to_owned()), - }, - &FieldType::DateTime, - &field_rev, - "May 27,2022 01:00", - ); - } - - fn assert_changeset_result( - type_option: &DateTypeOption, - changeset: DateCellChangeset, - _field_type: &FieldType, - field_rev: &FieldRevision, - expected: &str, - ) { - let changeset = CellDataChangeset(Some(changeset)); - let encoded_data = type_option.apply_changeset(changeset, None).unwrap(); - assert_eq!( - expected.to_owned(), - decode_cell_data(encoded_data, type_option, field_rev) - ); - } - - fn assert_decode_timestamp( - timestamp: i64, - type_option: &DateTypeOption, - field_rev: &FieldRevision, - expected: &str, - ) { - let s = serde_json::to_string(&DateCellChangeset { - date: Some(timestamp.to_string()), - time: None, - }) - .unwrap(); - let encoded_data = type_option.apply_changeset(s.into(), None).unwrap(); - - assert_eq!( - expected.to_owned(), - decode_cell_data(encoded_data, type_option, field_rev) - ); - } - - fn decode_cell_data(encoded_data: String, type_option: &DateTypeOption, field_rev: &FieldRevision) -> String { - let decoded_data = type_option - .decode_cell_data(encoded_data.into(), &FieldType::DateTime, field_rev) - .unwrap() - .parse::() - .unwrap(); - - if type_option.include_time { - format!("{}{}", decoded_data.date, decoded_data.time) - } else { - decoded_data.date - } - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs new file mode 100644 index 0000000000..63ed4ee2a9 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs @@ -0,0 +1,199 @@ +use crate::entities::{FieldType}; + +use crate::impl_type_option; +use crate::services::cell::{ + AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, FromCellChangeset, + FromCellString, +}; +use crate::services::field::{ + BoxTypeOptionBuilder, DateCellChangeset, DateCellData, DateFormat, DateTimestamp, TimeFormat, TypeOptionBuilder, +}; +use bytes::Bytes; +use chrono::format::strftime::StrftimeItems; +use chrono::{NaiveDateTime, Timelike}; +use flowy_derive::{ProtoBuf}; +use flowy_error::{ErrorCode, FlowyError, FlowyResult}; +use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; +use serde::{Deserialize, Serialize}; + + +// Date +#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] +pub struct DateTypeOption { + #[pb(index = 1)] + pub date_format: DateFormat, + + #[pb(index = 2)] + pub time_format: TimeFormat, + + #[pb(index = 3)] + pub include_time: bool, +} +impl_type_option!(DateTypeOption, FieldType::DateTime); + +impl DateTypeOption { + #[allow(dead_code)] + pub fn new() -> Self { + Self::default() + } + + fn today_desc_from_timestamp>(&self, timestamp: T) -> DateCellData { + let timestamp = *timestamp.as_ref(); + let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0); + self.date_from_native(native) + } + + fn date_from_native(&self, native: chrono::NaiveDateTime) -> DateCellData { + if native.timestamp() == 0 { + return DateCellData::default(); + } + + let time = native.time(); + let has_time = time.hour() != 0 || time.second() != 0; + + let utc = self.utc_date_time_from_native(native); + let fmt = self.date_format.format_str(); + let date = format!("{}", utc.format_with_items(StrftimeItems::new(fmt))); + + let mut time = "".to_string(); + if has_time { + let fmt = format!("{} {}", self.date_format.format_str(), self.time_format.format_str()); + time = format!("{}", utc.format_with_items(StrftimeItems::new(&fmt))).replace(&date, ""); + } + + let timestamp = native.timestamp(); + DateCellData { date, time, timestamp } + } + + fn date_fmt(&self, time: &Option) -> String { + if self.include_time { + match time.as_ref() { + None => self.date_format.format_str().to_string(), + Some(time_str) => { + if time_str.is_empty() { + self.date_format.format_str().to_string() + } else { + format!("{} {}", self.date_format.format_str(), self.time_format.format_str()) + } + } + } + } else { + self.date_format.format_str().to_string() + } + } + + fn timestamp_from_utc_with_time( + &self, + utc: &chrono::DateTime, + time: &Option, + ) -> FlowyResult { + if let Some(time_str) = time.as_ref() { + if !time_str.is_empty() { + let date_str = format!( + "{}{}", + utc.format_with_items(StrftimeItems::new(self.date_format.format_str())), + &time_str + ); + + return match NaiveDateTime::parse_from_str(&date_str, &self.date_fmt(time)) { + Ok(native) => { + let utc = self.utc_date_time_from_native(native); + Ok(utc.timestamp()) + } + Err(_e) => { + let msg = format!("Parse {} failed", date_str); + Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg)) + } + }; + } + } + + Ok(utc.timestamp()) + } + + fn utc_date_time_from_timestamp(&self, timestamp: i64) -> chrono::DateTime { + let native = NaiveDateTime::from_timestamp(timestamp, 0); + self.utc_date_time_from_native(native) + } + + fn utc_date_time_from_native(&self, naive: chrono::NaiveDateTime) -> chrono::DateTime { + chrono::DateTime::::from_utc(naive, chrono::Utc) + } +} + +impl CellDisplayable for DateTypeOption { + fn display_data( + &self, + cell_data: CellData, + _decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + let timestamp = cell_data.try_into_inner()?; + CellBytes::from(self.today_desc_from_timestamp(timestamp)) + } +} + +impl CellDataOperation for DateTypeOption { + fn decode_cell_data( + &self, + cell_data: CellData, + decoded_field_type: &FieldType, + field_rev: &FieldRevision, + ) -> FlowyResult { + // Return default data if the type_option_cell_data is not FieldType::DateTime. + // It happens when switching from one field to another. + // For example: + // FieldType::RichText -> FieldType::DateTime, it will display empty content on the screen. + if !decoded_field_type.is_date() { + return Ok(CellBytes::default()); + } + self.display_data(cell_data, decoded_field_type, field_rev) + } + + fn apply_changeset( + &self, + changeset: CellDataChangeset, + _cell_rev: Option, + ) -> Result { + let changeset = changeset.try_into_inner()?; + let cell_data = match changeset.date_timestamp() { + None => 0, + Some(date_timestamp) => match (self.include_time, changeset.time) { + (true, Some(time)) => { + let time = Some(time.trim().to_uppercase()); + let utc = self.utc_date_time_from_timestamp(date_timestamp); + self.timestamp_from_utc_with_time(&utc, &time)? + } + _ => date_timestamp, + }, + }; + + Ok(cell_data.to_string()) + } +} + +#[derive(Default)] +pub struct DateTypeOptionBuilder(DateTypeOption); +impl_into_box_type_option_builder!(DateTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(DateTypeOptionBuilder, DateTypeOption); + +impl DateTypeOptionBuilder { + pub fn date_format(mut self, date_format: DateFormat) -> Self { + self.0.date_format = date_format; + self + } + + pub fn time_format(mut self, time_format: TimeFormat) -> Self { + self.0.time_format = time_format; + self + } +} +impl TypeOptionBuilder for DateTypeOptionBuilder { + fn field_type(&self) -> FieldType { + FieldType::DateTime + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs new file mode 100644 index 0000000000..aa63eee9dd --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs @@ -0,0 +1,206 @@ +use crate::entities::CellChangeset; +use crate::entities::{CellIdentifier, CellIdentifierPayload}; +use crate::services::cell::{AnyCellData, FromCellChangeset, FromCellString}; + +use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; +use flowy_error::{internal_error, ErrorCode, FlowyResult}; + +use serde::{Deserialize, Serialize}; +use strum_macros::EnumIter; + +#[derive(Clone, Debug, Default, ProtoBuf)] +pub struct DateCellData { + #[pb(index = 1)] + pub date: String, + + #[pb(index = 2)] + pub time: String, + + #[pb(index = 3)] + pub timestamp: i64, +} + +#[derive(Clone, Debug, Default, ProtoBuf)] +pub struct DateChangesetPayload { + #[pb(index = 1)] + pub cell_identifier: CellIdentifierPayload, + + #[pb(index = 2, one_of)] + pub date: Option, + + #[pb(index = 3, one_of)] + pub time: Option, +} + +pub struct DateChangesetParams { + pub cell_identifier: CellIdentifier, + pub date: Option, + pub time: Option, +} + +impl TryInto for DateChangesetPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let cell_identifier: CellIdentifier = self.cell_identifier.try_into()?; + Ok(DateChangesetParams { + cell_identifier, + date: self.date, + time: self.time, + }) + } +} + +impl std::convert::From for CellChangeset { + fn from(params: DateChangesetParams) -> Self { + let changeset = DateCellChangeset { + date: params.date, + time: params.time, + }; + let s = serde_json::to_string(&changeset).unwrap(); + CellChangeset { + grid_id: params.cell_identifier.grid_id, + row_id: params.cell_identifier.row_id, + field_id: params.cell_identifier.field_id, + content: Some(s), + } + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct DateCellChangeset { + pub date: Option, + pub time: Option, +} + +impl DateCellChangeset { + pub fn date_timestamp(&self) -> Option { + if let Some(date) = &self.date { + match date.parse::() { + Ok(date_timestamp) => Some(date_timestamp), + Err(_) => None, + } + } else { + None + } + } +} + +impl FromCellChangeset for DateCellChangeset { + fn from_changeset(changeset: String) -> FlowyResult + where + Self: Sized, + { + serde_json::from_str::(&changeset).map_err(internal_error) + } +} +pub struct DateTimestamp(i64); +impl AsRef for DateTimestamp { + fn as_ref(&self) -> &i64 { + &self.0 + } +} + +impl std::convert::From for i64 { + fn from(timestamp: DateTimestamp) -> Self { + timestamp.0 + } +} + +impl FromCellString for DateTimestamp { + fn from_cell_str(s: &str) -> FlowyResult + where + Self: Sized, + { + let num = s.parse::().unwrap_or(0); + Ok(DateTimestamp(num)) + } +} + +impl std::convert::From for DateTimestamp { + fn from(data: AnyCellData) -> Self { + let num = data.data.parse::().unwrap_or(0); + DateTimestamp(num) + } +} +#[derive(Clone, Debug, Copy, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)] +pub enum DateFormat { + Local = 0, + US = 1, + ISO = 2, + Friendly = 3, +} +impl std::default::Default for DateFormat { + fn default() -> Self { + DateFormat::Friendly + } +} + +impl std::convert::From for DateFormat { + fn from(value: i32) -> Self { + match value { + 0 => DateFormat::Local, + 1 => DateFormat::US, + 2 => DateFormat::ISO, + 3 => DateFormat::Friendly, + _ => { + tracing::error!("Unsupported date format, fallback to friendly"); + DateFormat::Friendly + } + } + } +} + +impl DateFormat { + pub fn value(&self) -> i32 { + *self as i32 + } + // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html + pub fn format_str(&self) -> &'static str { + match self { + DateFormat::Local => "%Y/%m/%d", + DateFormat::US => "%Y/%m/%d", + DateFormat::ISO => "%Y-%m-%d", + DateFormat::Friendly => "%b %d,%Y", + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, EnumIter, Debug, Hash, Serialize, Deserialize, ProtoBuf_Enum)] +pub enum TimeFormat { + TwelveHour = 0, + TwentyFourHour = 1, +} + +impl std::convert::From for TimeFormat { + fn from(value: i32) -> Self { + match value { + 0 => TimeFormat::TwelveHour, + 1 => TimeFormat::TwentyFourHour, + _ => { + tracing::error!("Unsupported time format, fallback to TwentyFourHour"); + TimeFormat::TwentyFourHour + } + } + } +} + +impl TimeFormat { + pub fn value(&self) -> i32 { + *self as i32 + } + + // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html + pub fn format_str(&self) -> &'static str { + match self { + TimeFormat::TwelveHour => "%I:%M %p", + TimeFormat::TwentyFourHour => "%R", + } + } +} + +impl std::default::Default for TimeFormat { + fn default() -> Self { + TimeFormat::TwentyFourHour + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs new file mode 100644 index 0000000000..9785924a8c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs @@ -0,0 +1,6 @@ +mod date_option; +mod date_option_entities; +mod tests; + +pub use date_option::*; +pub use date_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/tests.rs new file mode 100644 index 0000000000..22e6f08b49 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/tests.rs @@ -0,0 +1,272 @@ +#[cfg(test)] +mod tests { + use crate::entities::FieldType; + use crate::services::cell::{CellDataChangeset, CellDataOperation}; + use crate::services::field::FieldBuilder; + use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; + use flowy_grid_data_model::revision::FieldRevision; + use strum::IntoEnumIterator; + + #[test] + fn date_type_option_invalid_input_test() { + let type_option = DateTypeOption::default(); + let field_type = FieldType::DateTime; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some("1e".to_string()), + time: Some("23:00".to_owned()), + }, + &field_type, + &field_rev, + "", + ); + } + + #[test] + fn date_type_option_date_format_test() { + let mut type_option = DateTypeOption::default(); + let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); + for date_format in DateFormat::iter() { + type_option.date_format = date_format; + match date_format { + DateFormat::Friendly => { + assert_decode_timestamp(1647251762, &type_option, &field_rev, "Mar 14,2022"); + } + DateFormat::US => { + assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022/03/14"); + } + DateFormat::ISO => { + assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022-03-14"); + } + DateFormat::Local => { + assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022/03/14"); + } + } + } + } + + #[test] + fn date_type_option_time_format_test() { + let mut type_option = DateTypeOption::default(); + let field_type = FieldType::DateTime; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + + for time_format in TimeFormat::iter() { + type_option.time_format = time_format; + type_option.include_time = true; + match time_format { + TimeFormat::TwentyFourHour => { + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(1653609600.to_string()), + time: None, + }, + &field_type, + &field_rev, + "May 27,2022", + ); + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(1653609600.to_string()), + time: Some("23:00".to_owned()), + }, + &field_type, + &field_rev, + "May 27,2022 23:00", + ); + } + TimeFormat::TwelveHour => { + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(1653609600.to_string()), + time: None, + }, + &field_type, + &field_rev, + "May 27,2022", + ); + // + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(1653609600.to_string()), + time: Some("".to_owned()), + }, + &field_type, + &field_rev, + "May 27,2022", + ); + + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(1653609600.to_string()), + time: Some("11:23 pm".to_owned()), + }, + &field_type, + &field_rev, + "May 27,2022 11:23 PM", + ); + } + } + } + } + + #[test] + fn date_type_option_apply_changeset_test() { + let mut type_option = DateTypeOption::new(); + let field_type = FieldType::DateTime; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + let date_timestamp = "1653609600".to_owned(); + + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(date_timestamp.clone()), + time: None, + }, + &field_type, + &field_rev, + "May 27,2022", + ); + + type_option.include_time = true; + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(date_timestamp.clone()), + time: None, + }, + &field_type, + &field_rev, + "May 27,2022", + ); + + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(date_timestamp.clone()), + time: Some("1:00".to_owned()), + }, + &field_type, + &field_rev, + "May 27,2022 01:00", + ); + + type_option.time_format = TimeFormat::TwelveHour; + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(date_timestamp), + time: Some("1:00 am".to_owned()), + }, + &field_type, + &field_rev, + "May 27,2022 01:00 AM", + ); + } + + #[test] + #[should_panic] + fn date_type_option_apply_changeset_error_test() { + let mut type_option = DateTypeOption::new(); + type_option.include_time = true; + let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); + let date_timestamp = "1653609600".to_owned(); + + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(date_timestamp.clone()), + time: Some("1:".to_owned()), + }, + &FieldType::DateTime, + &field_rev, + "May 27,2022 01:00", + ); + + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(date_timestamp), + time: Some("1:00".to_owned()), + }, + &FieldType::DateTime, + &field_rev, + "May 27,2022 01:00", + ); + } + + #[test] + #[should_panic] + fn date_type_option_twelve_hours_to_twenty_four_hours() { + let mut type_option = DateTypeOption::new(); + type_option.include_time = true; + let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); + let date_timestamp = "1653609600".to_owned(); + + assert_changeset_result( + &type_option, + DateCellChangeset { + date: Some(date_timestamp), + time: Some("1:00 am".to_owned()), + }, + &FieldType::DateTime, + &field_rev, + "May 27,2022 01:00", + ); + } + + fn assert_changeset_result( + type_option: &DateTypeOption, + changeset: DateCellChangeset, + _field_type: &FieldType, + field_rev: &FieldRevision, + expected: &str, + ) { + let changeset = CellDataChangeset(Some(changeset)); + let encoded_data = type_option.apply_changeset(changeset, None).unwrap(); + assert_eq!( + expected.to_owned(), + decode_cell_data(encoded_data, type_option, field_rev) + ); + } + + fn assert_decode_timestamp( + timestamp: i64, + type_option: &DateTypeOption, + field_rev: &FieldRevision, + expected: &str, + ) { + let s = serde_json::to_string(&DateCellChangeset { + date: Some(timestamp.to_string()), + time: None, + }) + .unwrap(); + let encoded_data = type_option.apply_changeset(s.into(), None).unwrap(); + + assert_eq!( + expected.to_owned(), + decode_cell_data(encoded_data, type_option, field_rev) + ); + } + + fn decode_cell_data(encoded_data: String, type_option: &DateTypeOption, field_rev: &FieldRevision) -> String { + let decoded_data = type_option + .decode_cell_data(encoded_data.into(), &FieldType::DateTime, field_rev) + .unwrap() + .parse::() + .unwrap(); + + if type_option.include_time { + format!("{}{}", decoded_data.date, decoded_data.time) + } else { + decoded_data.date + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs index 754e441876..32fd9ef0a4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs @@ -1,17 +1,14 @@ -mod checkbox_type_option; -mod date_type_option; -mod multi_select_type_option; -mod number_type_option; -mod single_select_type_option; -mod text_type_option; -mod url_type_option; +pub mod checkbox_type_option; +pub mod date_type_option; +pub mod number_type_option; +pub mod selection_type_option; +pub mod text_type_option; +pub mod url_type_option; mod util; pub use checkbox_type_option::*; pub use date_type_option::*; -pub use multi_select_type_option::*; -pub use multi_select_type_option::*; pub use number_type_option::*; -pub use single_select_type_option::*; +pub use selection_type_option::*; pub use text_type_option::*; pub use url_type_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs index fffbad97bf..8b4f9b2896 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs @@ -1,6 +1,9 @@ #![allow(clippy::module_inception)] mod format; -mod number_type_option; +mod number_option; +mod number_option_entities; +mod tests; pub use format::*; -pub use number_type_option::*; +pub use number_option::*; +pub use number_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs new file mode 100644 index 0000000000..001bb4a0bc --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs @@ -0,0 +1,149 @@ +use crate::impl_type_option; + +use crate::entities::FieldType; +use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation}; +use crate::services::field::number_currency::Currency; +use crate::services::field::type_options::number_type_option::format::*; +use crate::services::field::{BoxTypeOptionBuilder, NumberCellData, TypeOptionBuilder}; +use bytes::Bytes; +use flowy_derive::ProtoBuf; +use flowy_error::{FlowyError, FlowyResult}; +use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; + +use rust_decimal::Decimal; +use rusty_money::Money; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; + +#[derive(Default)] +pub struct NumberTypeOptionBuilder(NumberTypeOption); +impl_into_box_type_option_builder!(NumberTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(NumberTypeOptionBuilder, NumberTypeOption); + +impl NumberTypeOptionBuilder { + pub fn name(mut self, name: &str) -> Self { + self.0.name = name.to_string(); + self + } + + pub fn set_format(mut self, format: NumberFormat) -> Self { + self.0.set_format(format); + self + } + + pub fn scale(mut self, scale: u32) -> Self { + self.0.scale = scale; + self + } + + pub fn positive(mut self, positive: bool) -> Self { + self.0.sign_positive = positive; + self + } +} + +impl TypeOptionBuilder for NumberTypeOptionBuilder { + fn field_type(&self) -> FieldType { + FieldType::Number + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +// Number +#[derive(Clone, Debug, Serialize, Deserialize, ProtoBuf)] +pub struct NumberTypeOption { + #[pb(index = 1)] + pub format: NumberFormat, + + #[pb(index = 2)] + pub scale: u32, + + #[pb(index = 3)] + pub symbol: String, + + #[pb(index = 4)] + pub sign_positive: bool, + + #[pb(index = 5)] + pub name: String, +} +impl_type_option!(NumberTypeOption, FieldType::Number); + +impl NumberTypeOption { + pub fn new() -> Self { + Self::default() + } + + pub(crate) fn format_cell_data(&self, s: &str) -> FlowyResult { + match self.format { + NumberFormat::Num | NumberFormat::Percent => match Decimal::from_str(s) { + Ok(value, ..) => Ok(NumberCellData::from_decimal(value)), + Err(_) => Ok(NumberCellData::new()), + }, + _ => NumberCellData::from_format_str(s, self.sign_positive, &self.format), + } + } + + pub fn set_format(&mut self, format: NumberFormat) { + self.format = format; + self.symbol = format.symbol(); + } +} + +pub(crate) fn strip_currency_symbol(s: T) -> String { + let mut s = s.to_string(); + for symbol in CURRENCY_SYMBOL.iter() { + if s.starts_with(symbol) { + s = s.strip_prefix(symbol).unwrap_or("").to_string(); + break; + } + } + s +} + +impl CellDataOperation for NumberTypeOption { + fn decode_cell_data( + &self, + cell_data: CellData, + decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + if decoded_field_type.is_date() { + return Ok(CellBytes::default()); + } + + let cell_data: String = cell_data.try_into_inner()?; + match self.format_cell_data(&cell_data) { + Ok(num) => Ok(CellBytes::new(num.to_string())), + Err(_) => Ok(CellBytes::default()), + } + } + + fn apply_changeset( + &self, + changeset: CellDataChangeset, + _cell_rev: Option, + ) -> Result { + let changeset = changeset.try_into_inner()?; + let data = changeset.trim().to_string(); + let _ = self.format_cell_data(&data)?; + Ok(data) + } +} + +impl std::default::Default for NumberTypeOption { + fn default() -> Self { + let format = NumberFormat::default(); + let symbol = format.symbol(); + NumberTypeOption { + format, + scale: 0, + symbol, + sign_positive: true, + name: "Number".to_string(), + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs new file mode 100644 index 0000000000..e797165b03 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs @@ -0,0 +1,93 @@ +use crate::services::field::number_currency::Currency; +use crate::services::field::{strip_currency_symbol, NumberFormat, STRIP_SYMBOL}; +use flowy_error::{FlowyError, FlowyResult}; +use rust_decimal::Decimal; +use rusty_money::Money; +use std::str::FromStr; + +#[derive(Default)] +pub struct NumberCellData { + decimal: Option, + money: Option, +} + +impl NumberCellData { + pub fn new() -> Self { + Self { + decimal: Default::default(), + money: None, + } + } + + pub fn from_format_str(s: &str, sign_positive: bool, format: &NumberFormat) -> FlowyResult { + let mut num_str = strip_currency_symbol(s); + let currency = format.currency(); + if num_str.is_empty() { + return Ok(Self::default()); + } + match Decimal::from_str(&num_str) { + Ok(mut decimal) => { + decimal.set_sign_positive(sign_positive); + let money = Money::from_decimal(decimal, currency); + Ok(Self::from_money(money)) + } + Err(_) => match Money::from_str(&num_str, currency) { + Ok(money) => Ok(NumberCellData::from_money(money)), + Err(_) => { + num_str.retain(|c| !STRIP_SYMBOL.contains(&c.to_string())); + if num_str.chars().all(char::is_numeric) { + Self::from_format_str(&num_str, sign_positive, format) + } else { + Err(FlowyError::invalid_data().context("Should only contain numbers")) + } + } + }, + } + } + + pub fn from_decimal(decimal: Decimal) -> Self { + Self { + decimal: Some(decimal), + money: None, + } + } + + pub fn from_money(money: Money) -> Self { + Self { + decimal: Some(*money.amount()), + money: Some(money.to_string()), + } + } + + pub fn decimal(&self) -> &Option { + &self.decimal + } + + pub fn is_empty(&self) -> bool { + self.decimal.is_none() + } +} + +impl FromStr for NumberCellData { + type Err = rust_decimal::Error; + + fn from_str(s: &str) -> Result { + if s.is_empty() { + return Ok(Self::default()); + } + let decimal = Decimal::from_str(s)?; + Ok(Self::from_decimal(decimal)) + } +} + +impl ToString for NumberCellData { + fn to_string(&self) -> String { + match &self.money { + None => match self.decimal { + None => String::default(), + Some(decimal) => decimal.to_string(), + }, + Some(money) => money.to_string(), + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs deleted file mode 100644 index c1c3dbdae3..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs +++ /dev/null @@ -1,376 +0,0 @@ -use crate::impl_type_option; - -use crate::entities::FieldType; -use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation}; -use crate::services::field::number_currency::Currency; -use crate::services::field::type_options::number_type_option::format::*; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use bytes::Bytes; -use flowy_derive::ProtoBuf; -use flowy_error::{FlowyError, FlowyResult}; -use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; - -use rust_decimal::Decimal; -use rusty_money::Money; -use serde::{Deserialize, Serialize}; -use std::str::FromStr; - -#[derive(Default)] -pub struct NumberTypeOptionBuilder(NumberTypeOption); -impl_into_box_type_option_builder!(NumberTypeOptionBuilder); -impl_builder_from_json_str_and_from_bytes!(NumberTypeOptionBuilder, NumberTypeOption); - -impl NumberTypeOptionBuilder { - pub fn name(mut self, name: &str) -> Self { - self.0.name = name.to_string(); - self - } - - pub fn set_format(mut self, format: NumberFormat) -> Self { - self.0.set_format(format); - self - } - - pub fn scale(mut self, scale: u32) -> Self { - self.0.scale = scale; - self - } - - pub fn positive(mut self, positive: bool) -> Self { - self.0.sign_positive = positive; - self - } -} - -impl TypeOptionBuilder for NumberTypeOptionBuilder { - fn field_type(&self) -> FieldType { - FieldType::Number - } - - fn entry(&self) -> &dyn TypeOptionDataEntry { - &self.0 - } -} - -// Number -#[derive(Clone, Debug, Serialize, Deserialize, ProtoBuf)] -pub struct NumberTypeOption { - #[pb(index = 1)] - pub format: NumberFormat, - - #[pb(index = 2)] - pub scale: u32, - - #[pb(index = 3)] - pub symbol: String, - - #[pb(index = 4)] - pub sign_positive: bool, - - #[pb(index = 5)] - pub name: String, -} -impl_type_option!(NumberTypeOption, FieldType::Number); - -impl NumberTypeOption { - pub fn new() -> Self { - Self::default() - } - - pub(crate) fn format_cell_data(&self, s: &str) -> FlowyResult { - match self.format { - NumberFormat::Num | NumberFormat::Percent => match Decimal::from_str(s) { - Ok(value, ..) => Ok(NumberCellData::from_decimal(value)), - Err(_) => Ok(NumberCellData::new()), - }, - _ => NumberCellData::from_format_str(s, self.sign_positive, &self.format), - } - } - - pub fn set_format(&mut self, format: NumberFormat) { - self.format = format; - self.symbol = format.symbol(); - } -} - -pub(crate) fn strip_currency_symbol(s: T) -> String { - let mut s = s.to_string(); - for symbol in CURRENCY_SYMBOL.iter() { - if s.starts_with(symbol) { - s = s.strip_prefix(symbol).unwrap_or("").to_string(); - break; - } - } - s -} - -impl CellDataOperation for NumberTypeOption { - fn decode_cell_data( - &self, - cell_data: CellData, - decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { - if decoded_field_type.is_date() { - return Ok(CellBytes::default()); - } - - let cell_data: String = cell_data.try_into_inner()?; - match self.format_cell_data(&cell_data) { - Ok(num) => Ok(CellBytes::new(num.to_string())), - Err(_) => Ok(CellBytes::default()), - } - } - - fn apply_changeset( - &self, - changeset: CellDataChangeset, - _cell_rev: Option, - ) -> Result { - let changeset = changeset.try_into_inner()?; - let data = changeset.trim().to_string(); - let _ = self.format_cell_data(&data)?; - Ok(data) - } -} - -impl std::default::Default for NumberTypeOption { - fn default() -> Self { - let format = NumberFormat::default(); - let symbol = format.symbol(); - NumberTypeOption { - format, - scale: 0, - symbol, - sign_positive: true, - name: "Number".to_string(), - } - } -} - -#[derive(Default)] -pub struct NumberCellData { - decimal: Option, - money: Option, -} - -impl NumberCellData { - pub fn new() -> Self { - Self { - decimal: Default::default(), - money: None, - } - } - - pub fn from_format_str(s: &str, sign_positive: bool, format: &NumberFormat) -> FlowyResult { - let mut num_str = strip_currency_symbol(s); - let currency = format.currency(); - if num_str.is_empty() { - return Ok(Self::default()); - } - match Decimal::from_str(&num_str) { - Ok(mut decimal) => { - decimal.set_sign_positive(sign_positive); - let money = Money::from_decimal(decimal, currency); - Ok(Self::from_money(money)) - } - Err(_) => match Money::from_str(&num_str, currency) { - Ok(money) => Ok(NumberCellData::from_money(money)), - Err(_) => { - num_str.retain(|c| !STRIP_SYMBOL.contains(&c.to_string())); - if num_str.chars().all(char::is_numeric) { - Self::from_format_str(&num_str, sign_positive, format) - } else { - Err(FlowyError::invalid_data().context("Should only contain numbers")) - } - } - }, - } - } - - pub fn from_decimal(decimal: Decimal) -> Self { - Self { - decimal: Some(decimal), - money: None, - } - } - - pub fn from_money(money: Money) -> Self { - Self { - decimal: Some(*money.amount()), - money: Some(money.to_string()), - } - } - - pub fn decimal(&self) -> &Option { - &self.decimal - } - - pub fn is_empty(&self) -> bool { - self.decimal.is_none() - } -} - -impl FromStr for NumberCellData { - type Err = rust_decimal::Error; - - fn from_str(s: &str) -> Result { - if s.is_empty() { - return Ok(Self::default()); - } - let decimal = Decimal::from_str(s)?; - Ok(Self::from_decimal(decimal)) - } -} - -impl ToString for NumberCellData { - fn to_string(&self) -> String { - match &self.money { - None => match self.decimal { - None => String::default(), - Some(decimal) => decimal.to_string(), - }, - Some(money) => money.to_string(), - } - } -} - -#[cfg(test)] -mod tests { - use crate::entities::FieldType; - use crate::services::cell::CellDataOperation; - use crate::services::field::FieldBuilder; - use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOption}; - use flowy_grid_data_model::revision::FieldRevision; - use strum::IntoEnumIterator; - - #[test] - fn number_type_option_invalid_input_test() { - let type_option = NumberTypeOption::default(); - let field_type = FieldType::Number; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - assert_equal(&type_option, "", "", &field_type, &field_rev); - assert_equal(&type_option, "abc", "", &field_type, &field_rev); - } - - #[test] - fn number_type_option_strip_symbol_test() { - let mut type_option = NumberTypeOption::new(); - type_option.format = NumberFormat::USD; - assert_eq!(strip_currency_symbol("$18,443"), "18,443".to_owned()); - - type_option.format = NumberFormat::Yuan; - assert_eq!(strip_currency_symbol("$0.2"), "0.2".to_owned()); - } - - #[test] - fn number_type_option_format_number_test() { - let mut type_option = NumberTypeOption::default(); - let field_type = FieldType::Number; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - - for format in NumberFormat::iter() { - type_option.format = format; - match format { - NumberFormat::Num => { - assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); - } - NumberFormat::USD => { - assert_equal(&type_option, "18443", "$18,443", &field_type, &field_rev); - } - NumberFormat::Yen => { - assert_equal(&type_option, "18443", "¥18,443", &field_type, &field_rev); - } - NumberFormat::Yuan => { - assert_equal(&type_option, "18443", "CN¥18,443", &field_type, &field_rev); - } - NumberFormat::EUR => { - assert_equal(&type_option, "18443", "€18.443", &field_type, &field_rev); - } - _ => {} - } - } - } - - #[test] - fn number_type_option_format_str_test() { - let mut type_option = NumberTypeOption::default(); - let field_type = FieldType::Number; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - - for format in NumberFormat::iter() { - type_option.format = format; - match format { - NumberFormat::Num => { - assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); - assert_equal(&type_option, "0.2", "0.2", &field_type, &field_rev); - } - NumberFormat::USD => { - assert_equal(&type_option, "$18,44", "$1,844", &field_type, &field_rev); - assert_equal(&type_option, "$0.2", "$0.2", &field_type, &field_rev); - assert_equal(&type_option, "", "", &field_type, &field_rev); - assert_equal(&type_option, "abc", "", &field_type, &field_rev); - } - NumberFormat::Yen => { - assert_equal(&type_option, "¥18,44", "¥1,844", &field_type, &field_rev); - assert_equal(&type_option, "¥1844", "¥1,844", &field_type, &field_rev); - } - NumberFormat::Yuan => { - assert_equal(&type_option, "CN¥18,44", "CN¥1,844", &field_type, &field_rev); - assert_equal(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field_rev); - } - NumberFormat::EUR => { - assert_equal(&type_option, "€18.44", "€18,44", &field_type, &field_rev); - assert_equal(&type_option, "€0.5", "€0,5", &field_type, &field_rev); - assert_equal(&type_option, "€1844", "€1.844", &field_type, &field_rev); - } - _ => {} - } - } - } - - #[test] - fn number_description_sign_test() { - let mut type_option = NumberTypeOption { - sign_positive: false, - ..Default::default() - }; - let field_type = FieldType::Number; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - - for format in NumberFormat::iter() { - type_option.format = format; - match format { - NumberFormat::Num => { - assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); - } - NumberFormat::USD => { - assert_equal(&type_option, "18443", "-$18,443", &field_type, &field_rev); - } - NumberFormat::Yen => { - assert_equal(&type_option, "18443", "-¥18,443", &field_type, &field_rev); - } - NumberFormat::EUR => { - assert_equal(&type_option, "18443", "-€18.443", &field_type, &field_rev); - } - _ => {} - } - } - } - - fn assert_equal( - type_option: &NumberTypeOption, - cell_data: &str, - expected_str: &str, - field_type: &FieldType, - field_rev: &FieldRevision, - ) { - assert_eq!( - type_option - .decode_cell_data(cell_data.to_owned().into(), field_type, field_rev) - .unwrap() - .to_string(), - expected_str.to_owned() - ); - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/tests.rs new file mode 100644 index 0000000000..6ea1e8f302 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/tests.rs @@ -0,0 +1,139 @@ +#[cfg(test)] +mod tests { + use crate::entities::FieldType; + use crate::services::cell::CellDataOperation; + use crate::services::field::FieldBuilder; + use crate::services::field::{strip_currency_symbol, NumberFormat, NumberTypeOption}; + use flowy_grid_data_model::revision::FieldRevision; + use strum::IntoEnumIterator; + + #[test] + fn number_type_option_invalid_input_test() { + let type_option = NumberTypeOption::default(); + let field_type = FieldType::Number; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + assert_equal(&type_option, "", "", &field_type, &field_rev); + assert_equal(&type_option, "abc", "", &field_type, &field_rev); + } + + #[test] + fn number_type_option_strip_symbol_test() { + let mut type_option = NumberTypeOption::new(); + type_option.format = NumberFormat::USD; + assert_eq!(strip_currency_symbol("$18,443"), "18,443".to_owned()); + + type_option.format = NumberFormat::Yuan; + assert_eq!(strip_currency_symbol("$0.2"), "0.2".to_owned()); + } + + #[test] + fn number_type_option_format_number_test() { + let mut type_option = NumberTypeOption::default(); + let field_type = FieldType::Number; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + + for format in NumberFormat::iter() { + type_option.format = format; + match format { + NumberFormat::Num => { + assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); + } + NumberFormat::USD => { + assert_equal(&type_option, "18443", "$18,443", &field_type, &field_rev); + } + NumberFormat::Yen => { + assert_equal(&type_option, "18443", "¥18,443", &field_type, &field_rev); + } + NumberFormat::Yuan => { + assert_equal(&type_option, "18443", "CN¥18,443", &field_type, &field_rev); + } + NumberFormat::EUR => { + assert_equal(&type_option, "18443", "€18.443", &field_type, &field_rev); + } + _ => {} + } + } + } + + #[test] + fn number_type_option_format_str_test() { + let mut type_option = NumberTypeOption::default(); + let field_type = FieldType::Number; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + + for format in NumberFormat::iter() { + type_option.format = format; + match format { + NumberFormat::Num => { + assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); + assert_equal(&type_option, "0.2", "0.2", &field_type, &field_rev); + } + NumberFormat::USD => { + assert_equal(&type_option, "$18,44", "$1,844", &field_type, &field_rev); + assert_equal(&type_option, "$0.2", "$0.2", &field_type, &field_rev); + assert_equal(&type_option, "", "", &field_type, &field_rev); + assert_equal(&type_option, "abc", "", &field_type, &field_rev); + } + NumberFormat::Yen => { + assert_equal(&type_option, "¥18,44", "¥1,844", &field_type, &field_rev); + assert_equal(&type_option, "¥1844", "¥1,844", &field_type, &field_rev); + } + NumberFormat::Yuan => { + assert_equal(&type_option, "CN¥18,44", "CN¥1,844", &field_type, &field_rev); + assert_equal(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field_rev); + } + NumberFormat::EUR => { + assert_equal(&type_option, "€18.44", "€18,44", &field_type, &field_rev); + assert_equal(&type_option, "€0.5", "€0,5", &field_type, &field_rev); + assert_equal(&type_option, "€1844", "€1.844", &field_type, &field_rev); + } + _ => {} + } + } + } + + #[test] + fn number_description_sign_test() { + let mut type_option = NumberTypeOption { + sign_positive: false, + ..Default::default() + }; + let field_type = FieldType::Number; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + + for format in NumberFormat::iter() { + type_option.format = format; + match format { + NumberFormat::Num => { + assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); + } + NumberFormat::USD => { + assert_equal(&type_option, "18443", "-$18,443", &field_type, &field_rev); + } + NumberFormat::Yen => { + assert_equal(&type_option, "18443", "-¥18,443", &field_type, &field_rev); + } + NumberFormat::EUR => { + assert_equal(&type_option, "18443", "-€18.443", &field_type, &field_rev); + } + _ => {} + } + } + } + + fn assert_equal( + type_option: &NumberTypeOption, + cell_data: &str, + expected_str: &str, + field_type: &FieldType, + field_rev: &FieldRevision, + ) { + assert_eq!( + type_option + .decode_cell_data(cell_data.to_owned().into(), field_type, field_rev) + .unwrap() + .to_string(), + expected_str.to_owned() + ); + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/mod.rs new file mode 100644 index 0000000000..45d2b96e83 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/mod.rs @@ -0,0 +1,7 @@ +mod multi_select_type_option; +mod select_option; +mod single_select_type_option; + +pub use multi_select_type_option::*; +pub use select_option::*; +pub use single_select_type_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs similarity index 93% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs index 902170307b..050cf196f3 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/multi_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs @@ -1,19 +1,15 @@ use crate::entities::FieldType; - use crate::impl_type_option; use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; -use crate::services::field::select_option::{ - make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, - SelectOptionOperation, SELECTION_IDS_SEPARATOR, -}; use crate::services::field::type_options::util::get_cell_data; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; +use crate::services::field::{ + make_selected_select_options, BoxTypeOptionBuilder, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, + SelectOptionIds, SelectOptionOperation, TypeOptionBuilder, SELECTION_IDS_SEPARATOR, +}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; - use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; - use serde::{Deserialize, Serialize}; // Multiple select @@ -56,8 +52,7 @@ impl CellDataOperation for MultiSele return Ok(CellBytes::default()); } - let cell_data = self.display_data(cell_data, decoded_field_type, field_rev)?; - CellBytes::from(cell_data) + self.display_data(cell_data, decoded_field_type, field_rev) } fn apply_changeset( @@ -121,7 +116,7 @@ impl TypeOptionBuilder for MultiSelectTypeOptionBuilder { mod tests { use crate::entities::FieldType; use crate::services::cell::CellDataOperation; - use crate::services::field::select_option::*; + use crate::services::field::type_options::selection_type_option::*; use crate::services::field::FieldBuilder; use crate::services::field::{MultiSelectTypeOption, MultiSelectTypeOptionBuilder}; use flowy_grid_data_model::revision::FieldRevision; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs similarity index 97% rename from frontend/rust-lib/flowy-grid/src/services/field/select_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index d429899587..dcea1e209d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -1,5 +1,5 @@ use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType}; -use crate::services::cell::{AnyCellData, CellData, CellDisplayable, FromCellChangeset, FromCellString}; +use crate::services::cell::{AnyCellData, CellBytes, CellData, CellDisplayable, FromCellChangeset, FromCellString}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; @@ -106,7 +106,7 @@ pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync { fn mut_options(&mut self) -> &mut Vec; } -impl CellDisplayable for T +impl CellDisplayable for T where T: SelectOptionOperation, { @@ -115,8 +115,8 @@ where cell_data: CellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult { - Ok(self.selected_select_option(cell_data)) + ) -> FlowyResult { + CellBytes::from(self.selected_select_option(cell_data)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs similarity index 96% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs index 35a2ac4853..f92fbd73d0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/single_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs @@ -1,7 +1,7 @@ use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; -use crate::services::field::select_option::{ +use crate::services::field::{ make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, SelectOptionOperation, }; @@ -54,8 +54,7 @@ impl CellDataOperation for SingleSel return Ok(CellBytes::default()); } - let cell_data = self.display_data(cell_data, decoded_field_type, field_rev)?; - CellBytes::from(cell_data) + self.display_data(cell_data, decoded_field_type, field_rev) } fn apply_changeset( @@ -103,7 +102,7 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder { mod tests { use crate::entities::FieldType; use crate::services::cell::CellDataOperation; - use crate::services::field::select_option::*; + use crate::services::field::type_options::*; use crate::services::field::FieldBuilder; use flowy_grid_data_model::revision::FieldRevision; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs new file mode 100644 index 0000000000..9f41c61fdd --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs @@ -0,0 +1,2 @@ +mod text_option; +pub use text_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs similarity index 95% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs index 4d4b4e65fc..e2d77ddfde 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs @@ -32,15 +32,15 @@ pub struct RichTextTypeOption { } impl_type_option!(RichTextTypeOption, FieldType::RichText); -impl CellDisplayable for RichTextTypeOption { +impl CellDisplayable for RichTextTypeOption { fn display_data( &self, cell_data: CellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, - ) -> FlowyResult { + ) -> FlowyResult { let cell_str: String = cell_data.try_into_inner()?; - Ok(cell_str) + Ok(CellBytes::new(cell_str)) } } @@ -58,8 +58,7 @@ impl CellDataOperation for RichTextTypeOption { { try_decode_cell_data(cell_data, field_rev, decoded_field_type, decoded_field_type) } else { - let content = self.display_data(cell_data, decoded_field_type, field_rev)?; - Ok(CellBytes::new(content)) + self.display_data(cell_data, decoded_field_type, field_rev) } } @@ -96,7 +95,7 @@ impl std::convert::TryFrom for TextCellData { mod tests { use crate::entities::FieldType; use crate::services::cell::CellDataOperation; - use crate::services::field::select_option::*; + use crate::services::field::FieldBuilder; use crate::services::field::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs deleted file mode 100644 index 18144e3f2a..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option.rs +++ /dev/null @@ -1,206 +0,0 @@ -use crate::entities::FieldType; -use crate::impl_type_option; -use crate::services::cell::{ - AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, FromCellString, -}; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use bytes::Bytes; -use fancy_regex::Regex; -use flowy_derive::ProtoBuf; -use flowy_error::{internal_error, FlowyError, FlowyResult}; -use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; -use lazy_static::lazy_static; -use serde::{Deserialize, Serialize}; - -#[derive(Default)] -pub struct URLTypeOptionBuilder(URLTypeOption); -impl_into_box_type_option_builder!(URLTypeOptionBuilder); -impl_builder_from_json_str_and_from_bytes!(URLTypeOptionBuilder, URLTypeOption); - -impl TypeOptionBuilder for URLTypeOptionBuilder { - fn field_type(&self) -> FieldType { - FieldType::URL - } - - fn entry(&self) -> &dyn TypeOptionDataEntry { - &self.0 - } -} - -#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)] -pub struct URLTypeOption { - #[pb(index = 1)] - data: String, //It's not used yet. -} -impl_type_option!(URLTypeOption, FieldType::URL); - -impl CellDisplayable for URLTypeOption { - fn display_data( - &self, - cell_data: CellData, - _decoded_field_type: &FieldType, - _field_rev: &FieldRevision, - ) -> FlowyResult { - let cell_data: URLCellData = cell_data.try_into_inner()?; - Ok(cell_data) - } -} - -impl CellDataOperation for URLTypeOption { - fn decode_cell_data( - &self, - cell_data: CellData, - decoded_field_type: &FieldType, - field_rev: &FieldRevision, - ) -> FlowyResult { - if !decoded_field_type.is_url() { - return Ok(CellBytes::default()); - } - let cell_data = self.display_data(cell_data, decoded_field_type, field_rev)?; - CellBytes::from(cell_data) - } - - fn apply_changeset( - &self, - changeset: CellDataChangeset, - _cell_rev: Option, - ) -> Result { - let changeset = changeset.try_into_inner()?; - let mut url = "".to_string(); - if let Ok(Some(m)) = URL_REGEX.find(&changeset) { - url = auto_append_scheme(m.as_str()); - } - URLCellData { - url, - content: changeset, - } - .to_json() - } -} - -fn auto_append_scheme(s: &str) -> String { - // Only support https scheme by now - match url::Url::parse(s) { - Ok(url) => { - if url.scheme() == "https" { - url.into() - } else { - format!("https://{}", s) - } - } - Err(_) => { - format!("https://{}", s) - } - } -} - -#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] -pub struct URLCellData { - #[pb(index = 1)] - pub url: String, - - #[pb(index = 2)] - pub content: String, -} - -impl URLCellData { - pub fn new(s: &str) -> Self { - Self { - url: "".to_string(), - content: s.to_string(), - } - } - - fn to_json(&self) -> FlowyResult { - serde_json::to_string(self).map_err(internal_error) - } -} - -impl FromCellString for URLCellData { - fn from_cell_str(s: &str) -> FlowyResult { - serde_json::from_str::(s).map_err(internal_error) - } -} - -impl std::convert::TryFrom for URLCellData { - type Error = FlowyError; - - fn try_from(data: AnyCellData) -> Result { - serde_json::from_str::(&data.data).map_err(internal_error) - } -} - -lazy_static! { - static ref URL_REGEX: Regex = Regex::new( - "[(http(s)?):\\/\\/(www\\.)?a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)" - ) - .unwrap(); -} - -#[cfg(test)] -mod tests { - use crate::entities::FieldType; - use crate::services::cell::{CellData, CellDataOperation}; - use crate::services::field::FieldBuilder; - use crate::services::field::{URLCellData, URLTypeOption}; - use flowy_grid_data_model::revision::FieldRevision; - - #[test] - fn url_type_option_test_no_url() { - let type_option = URLTypeOption::default(); - let field_type = FieldType::URL; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - assert_changeset(&type_option, "123", &field_type, &field_rev, "123", ""); - } - - #[test] - fn url_type_option_test_contains_url() { - let type_option = URLTypeOption::default(); - let field_type = FieldType::URL; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - assert_changeset( - &type_option, - "AppFlowy website - https://www.appflowy.io", - &field_type, - &field_rev, - "AppFlowy website - https://www.appflowy.io", - "https://www.appflowy.io/", - ); - - assert_changeset( - &type_option, - "AppFlowy website appflowy.io", - &field_type, - &field_rev, - "AppFlowy website appflowy.io", - "https://appflowy.io", - ); - } - - fn assert_changeset( - type_option: &URLTypeOption, - cell_data: &str, - field_type: &FieldType, - field_rev: &FieldRevision, - expected: &str, - expected_url: &str, - ) { - let encoded_data = type_option.apply_changeset(cell_data.to_owned().into(), None).unwrap(); - let decode_cell_data = decode_cell_data(encoded_data, type_option, field_rev, field_type); - assert_eq!(expected.to_owned(), decode_cell_data.content); - assert_eq!(expected_url.to_owned(), decode_cell_data.url); - } - - fn decode_cell_data>>( - encoded_data: T, - type_option: &URLTypeOption, - field_rev: &FieldRevision, - field_type: &FieldType, - ) -> URLCellData { - type_option - .decode_cell_data(encoded_data.into(), field_type, field_rev) - .unwrap() - .parse::() - .unwrap() - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs new file mode 100644 index 0000000000..ee0e0848dd --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs @@ -0,0 +1,6 @@ +mod tests; +mod url_option; +mod url_option_entities; + +pub use url_option::*; +pub use url_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/tests.rs new file mode 100644 index 0000000000..91940fb83c --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/tests.rs @@ -0,0 +1,67 @@ +#[cfg(test)] +mod tests { + use crate::entities::FieldType; + use crate::services::cell::{CellData, CellDataOperation}; + use crate::services::field::FieldBuilder; + use crate::services::field::{URLCellData, URLTypeOption}; + use flowy_grid_data_model::revision::FieldRevision; + + #[test] + fn url_type_option_test_no_url() { + let type_option = URLTypeOption::default(); + let field_type = FieldType::URL; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + assert_changeset(&type_option, "123", &field_type, &field_rev, "123", ""); + } + + #[test] + fn url_type_option_test_contains_url() { + let type_option = URLTypeOption::default(); + let field_type = FieldType::URL; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); + assert_changeset( + &type_option, + "AppFlowy website - https://www.appflowy.io", + &field_type, + &field_rev, + "AppFlowy website - https://www.appflowy.io", + "https://www.appflowy.io/", + ); + + assert_changeset( + &type_option, + "AppFlowy website appflowy.io", + &field_type, + &field_rev, + "AppFlowy website appflowy.io", + "https://appflowy.io", + ); + } + + fn assert_changeset( + type_option: &URLTypeOption, + cell_data: &str, + field_type: &FieldType, + field_rev: &FieldRevision, + expected: &str, + expected_url: &str, + ) { + let encoded_data = type_option.apply_changeset(cell_data.to_owned().into(), None).unwrap(); + let decode_cell_data = decode_cell_data(encoded_data, type_option, field_rev, field_type); + assert_eq!(expected.to_owned(), decode_cell_data.content); + assert_eq!(expected_url.to_owned(), decode_cell_data.url); + } + + fn decode_cell_data>>( + encoded_data: T, + type_option: &URLTypeOption, + field_rev: &FieldRevision, + field_type: &FieldType, + ) -> URLCellData { + type_option + .decode_cell_data(encoded_data.into(), field_type, field_rev) + .unwrap() + .parse::() + .unwrap() + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs new file mode 100644 index 0000000000..d5fe0f287b --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs @@ -0,0 +1,101 @@ +use crate::entities::FieldType; +use crate::impl_type_option; +use crate::services::cell::{ + AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, FromCellString, +}; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder, URLCellData}; +use bytes::Bytes; +use fancy_regex::Regex; +use flowy_derive::ProtoBuf; +use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; + +#[derive(Default)] +pub struct URLTypeOptionBuilder(URLTypeOption); +impl_into_box_type_option_builder!(URLTypeOptionBuilder); +impl_builder_from_json_str_and_from_bytes!(URLTypeOptionBuilder, URLTypeOption); + +impl TypeOptionBuilder for URLTypeOptionBuilder { + fn field_type(&self) -> FieldType { + FieldType::URL + } + + fn entry(&self) -> &dyn TypeOptionDataEntry { + &self.0 + } +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default, ProtoBuf)] +pub struct URLTypeOption { + #[pb(index = 1)] + data: String, //It's not used yet. +} +impl_type_option!(URLTypeOption, FieldType::URL); + +impl CellDisplayable for URLTypeOption { + fn display_data( + &self, + cell_data: CellData, + _decoded_field_type: &FieldType, + _field_rev: &FieldRevision, + ) -> FlowyResult { + let cell_data: URLCellData = cell_data.try_into_inner()?; + CellBytes::from(cell_data) + } +} + +impl CellDataOperation for URLTypeOption { + fn decode_cell_data( + &self, + cell_data: CellData, + decoded_field_type: &FieldType, + field_rev: &FieldRevision, + ) -> FlowyResult { + if !decoded_field_type.is_url() { + return Ok(CellBytes::default()); + } + self.display_data(cell_data, decoded_field_type, field_rev) + } + + fn apply_changeset( + &self, + changeset: CellDataChangeset, + _cell_rev: Option, + ) -> Result { + let changeset = changeset.try_into_inner()?; + let mut url = "".to_string(); + if let Ok(Some(m)) = URL_REGEX.find(&changeset) { + url = auto_append_scheme(m.as_str()); + } + URLCellData { + url, + content: changeset, + } + .to_json() + } +} + +fn auto_append_scheme(s: &str) -> String { + // Only support https scheme by now + match url::Url::parse(s) { + Ok(url) => { + if url.scheme() == "https" { + url.into() + } else { + format!("https://{}", s) + } + } + Err(_) => { + format!("https://{}", s) + } + } +} + +lazy_static! { + static ref URL_REGEX: Regex = Regex::new( + "[(http(s)?):\\/\\/(www\\.)?a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)" + ) + .unwrap(); +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs new file mode 100644 index 0000000000..b78335349e --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs @@ -0,0 +1,40 @@ +use crate::services::cell::{AnyCellData, FromCellString}; +use flowy_derive::ProtoBuf; +use flowy_error::{internal_error, FlowyError, FlowyResult}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] +pub struct URLCellData { + #[pb(index = 1)] + pub url: String, + + #[pb(index = 2)] + pub content: String, +} + +impl URLCellData { + pub fn new(s: &str) -> Self { + Self { + url: "".to_string(), + content: s.to_string(), + } + } + + pub(crate) fn to_json(&self) -> FlowyResult { + serde_json::to_string(self).map_err(internal_error) + } +} + +impl FromCellString for URLCellData { + fn from_cell_str(s: &str) -> FlowyResult { + serde_json::from_str::(s).map_err(internal_error) + } +} + +impl std::convert::TryFrom for URLCellData { + type Error = FlowyError; + + fn try_from(data: AnyCellData) -> Result { + serde_json::from_str::(&data.data).map_err(internal_error) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/mod.rs index c7aa386fe9..dfadd1c5a0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/util/mod.rs @@ -1,4 +1,3 @@ mod cell_data_util; -pub use crate::services::field::select_option::*; pub use cell_data_util::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs index 3ef3a77b84..82d5ab6a0b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs @@ -2,8 +2,8 @@ use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; use crate::services::cell::{AnyCellData, CellFilterOperation}; -use crate::services::field::select_option::{SelectOptionOperation, SelectedSelectOptions}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; +use crate::services::field::{SelectOptionOperation, SelectedSelectOptions}; use flowy_error::FlowyResult; impl GridSelectOptionFilter { @@ -64,7 +64,7 @@ impl CellFilterOperation for SingleSelectTypeOption { mod tests { #![allow(clippy::all)] use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; - use crate::services::field::select_option::{SelectOption, SelectedSelectOptions}; + use crate::services::field::selection_type_option::{SelectOption, SelectedSelectOptions}; #[test] fn select_option_filter_is_test() { diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs index cc86fa3d9d..fb8c2550e4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs @@ -1,5 +1,5 @@ use crate::services::cell::apply_cell_data_changeset; -use crate::services::field::select_option::SelectOptionCellChangeset; +use crate::services::field::SelectOptionCellChangeset; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT}; use indexmap::IndexMap; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs index baf1bf6ae0..07db75161a 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs @@ -1,5 +1,5 @@ use flowy_grid::entities::FieldType; -use flowy_grid::services::field::select_option::{SelectOption, SELECTION_IDS_SEPARATOR}; +use flowy_grid::services::field::selection_type_option::{SelectOption, SELECTION_IDS_SEPARATOR}; use flowy_grid::services::field::{DateCellChangeset, MultiSelectTypeOption, SingleSelectTypeOption}; use flowy_grid::services::row::RowRevisionBuilder; use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs index 844a230036..ccdb8ea629 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs @@ -2,7 +2,7 @@ use crate::grid::cell_test::script::CellScript::*; use crate::grid::cell_test::script::GridCellTest; use crate::grid::field_test::util::make_date_cell_string; use flowy_grid::entities::{CellChangeset, FieldType}; -use flowy_grid::services::field::select_option::SelectOptionCellChangeset; +use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset; use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; #[tokio::test] diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs index 624979e940..c53ba2a2fc 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs @@ -1,7 +1,7 @@ use crate::grid::field_test::script::FieldScript::*; use crate::grid::field_test::script::GridFieldTest; use crate::grid::field_test::util::*; -use flowy_grid::services::field::select_option::SelectOption; +use flowy_grid::services::field::selection_type_option::SelectOption; use flowy_grid::services::field::SingleSelectTypeOption; use flowy_grid_data_model::revision::TypeOptionDataEntry; use flowy_sync::entities::grid::FieldChangesetParams; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs index d9055f93ea..42c04e41f9 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs @@ -1,5 +1,5 @@ use flowy_grid::entities::*; -use flowy_grid::services::field::select_option::SelectOption; +use flowy_grid::services::field::selection_type_option::SelectOption; use flowy_grid::services::field::*; use flowy_grid_data_model::revision::*; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index 85c81c4058..d5429623a3 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -3,7 +3,7 @@ #![allow(unused_imports)] use bytes::Bytes; use flowy_grid::entities::*; -use flowy_grid::services::field::select_option::SelectOption; +use flowy_grid::services::field::SelectOption; use flowy_grid::services::field::*; use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; use flowy_grid::services::row::{CreateRowRevisionPayload, RowRevisionBuilder}; From 602aab45e269a2dce1713adb91427ff116993263 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 13 Jul 2022 17:25:03 +0800 Subject: [PATCH 014/112] chore: unit test for cell content --- .../src/services/cell/any_cell_data.rs | 29 ++++++- .../src/services/cell/cell_operation.rs | 6 +- .../checkbox_type_option/checkbox_option.rs | 3 +- .../checkbox_option_entities.rs | 56 ++++++------ .../{tests.rs => checkbox_tests.rs} | 0 .../type_options/checkbox_type_option/mod.rs | 2 +- .../date_type_option/date_option.rs | 14 ++- .../date_type_option/date_option_entities.rs | 18 ++-- .../{tests.rs => date_tests.rs} | 6 +- .../type_options/date_type_option/mod.rs | 2 +- .../type_options/number_type_option/mod.rs | 2 +- .../number_type_option/number_option.rs | 6 +- .../number_option_entities.rs | 36 +++++--- .../{tests.rs => number_tests.rs} | 0 .../multi_select_type_option.rs | 2 +- .../selection_type_option/select_option.rs | 38 ++++---- .../single_select_type_option.rs | 4 +- .../text_type_option/text_option.rs | 31 +++++-- .../field/type_options/url_type_option/mod.rs | 2 +- .../url_type_option/url_option.rs | 16 ++-- .../url_type_option/url_option_entities.rs | 22 ++--- .../{tests.rs => url_tests.rs} | 4 +- .../services/filter/impls/checkbox_filter.rs | 5 +- .../src/services/filter/impls/date_filter.rs | 5 +- .../services/filter/impls/number_filter.rs | 8 +- .../src/services/filter/impls/text_filter.rs | 5 +- .../src/services/filter/impls/url_filter.rs | 5 +- .../flowy-grid/src/services/grid_editor.rs | 14 +-- .../tests/grid/block_test/row_test.rs | 46 ++++++++-- .../tests/grid/block_test/script.rs | 86 ++++++++++++++++--- .../flowy-grid/tests/grid/block_test/util.rs | 23 +++-- .../grid/filter_test/text_filter_test.rs | 10 +-- .../flowy-grid/tests/grid/grid_editor.rs | 7 +- 33 files changed, 338 insertions(+), 175 deletions(-) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/{tests.rs => checkbox_tests.rs} (100%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/{tests.rs => date_tests.rs} (97%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/{tests.rs => number_tests.rs} (100%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/{tests.rs => url_tests.rs} (95%) diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs b/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs index 1b85f3d1a9..8ebffcbedc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/any_cell_data.rs @@ -1,9 +1,11 @@ use crate::entities::FieldType; +use crate::services::cell::{CellData, FromCellString}; use bytes::Bytes; use flowy_error::{internal_error, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::CellRevision; use serde::{Deserialize, Serialize}; use std::str::FromStr; + /// AnyCellData is a generic CellData, you can parse the cell_data according to the field_type. /// When the type of field is changed, it's different from the field_type of AnyCellData. /// So it will return an empty data. You could check the CellDataOperation trait for more information. @@ -46,6 +48,15 @@ impl std::convert::TryFrom for AnyCellData { } } +impl std::convert::From for CellData +where + T: FromCellString, +{ + fn from(any_call_data: AnyCellData) -> Self { + CellData::from(any_call_data.data) + } +} + impl AnyCellData { pub fn new(content: String, field_type: FieldType) -> Self { AnyCellData { @@ -102,6 +113,11 @@ impl AnyCellData { #[derive(Default)] pub struct CellBytes(pub Bytes); +pub trait CellBytesParser { + type Object; + fn parse(&self, bytes: &Bytes) -> FlowyResult; +} + impl CellBytes { pub fn new>(data: T) -> Self { let bytes = Bytes::from(data.as_ref().to_vec()); @@ -116,12 +132,19 @@ impl CellBytes { Ok(Self(bytes)) } - pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult + pub fn with_parser

(&self, parser: P) -> FlowyResult where - >::Error: std::fmt::Debug, + P: CellBytesParser, { - T::try_from(self.0.as_ref()).map_err(internal_error) + parser.parse(&self.0) } + + // pub fn parse<'a, T: TryFrom<&'a [u8]>>(&'a self) -> FlowyResult + // where + // >::Error: std::fmt::Debug, + // { + // T::try_from(self.0.as_ref()).map_err(internal_error) + // } } impl ToString for CellBytes { diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs index 4bbeafa814..b4729c6925 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -163,9 +163,9 @@ where } } -impl std::convert::From for CellData { - fn from(s: String) -> Self { - CellData(Some(s)) +impl std::convert::From for CellData { + fn from(val: T) -> Self { + CellData(Some(val)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs index b6e1d39410..155965f409 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs @@ -7,6 +7,7 @@ use flowy_derive::ProtoBuf; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use serde::{Deserialize, Serialize}; +use std::str::FromStr; #[derive(Default)] pub struct CheckboxTypeOptionBuilder(CheckboxTypeOption); @@ -69,7 +70,7 @@ impl CellDataOperation for CheckboxTypeOption { _cell_rev: Option, ) -> Result { let changeset = changeset.try_into_inner()?; - let cell_data = CheckboxCellData::from_str(&changeset); + let cell_data = CheckboxCellData::from_str(&changeset)?; Ok(cell_data.to_string()) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs index 99f9866d41..5a8bf1e7a7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs @@ -1,5 +1,7 @@ -use crate::services::cell::{AnyCellData, FromCellString}; +use crate::services::cell::{CellBytesParser, FromCellString}; +use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; +use std::str::FromStr; pub const YES: &str = "Yes"; pub const NO: &str = "No"; @@ -7,7 +9,21 @@ pub const NO: &str = "No"; pub struct CheckboxCellData(pub String); impl CheckboxCellData { - pub fn from_str(s: &str) -> Self { + pub fn is_check(&self) -> bool { + self.0 == YES + } +} + +impl AsRef<[u8]> for CheckboxCellData { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl FromStr for CheckboxCellData { + type Err = FlowyError; + + fn from_str(s: &str) -> Result { let lower_case_str: &str = &s.to_lowercase(); let val = match lower_case_str { "1" => Some(true), @@ -20,29 +36,11 @@ impl CheckboxCellData { }; match val { - Some(true) => Self(YES.to_string()), - Some(false) => Self(NO.to_string()), - None => Self("".to_string()), + Some(true) => Ok(Self(YES.to_string())), + Some(false) => Ok(Self(NO.to_string())), + None => Ok(Self("".to_string())), } } - - pub fn is_check(&self) -> bool { - &self.0 == YES - } -} - -impl AsRef<[u8]> for CheckboxCellData { - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } -} - -impl std::convert::TryFrom for CheckboxCellData { - type Error = FlowyError; - - fn try_from(value: AnyCellData) -> Result { - Ok(Self::from_str(&value.data)) - } } impl FromCellString for CheckboxCellData { @@ -50,7 +48,7 @@ impl FromCellString for CheckboxCellData { where Self: Sized, { - Ok(Self::from_str(s)) + Self::from_str(s) } } @@ -59,3 +57,13 @@ impl ToString for CheckboxCellData { self.0.clone() } } +pub struct CheckboxCellDataParser; +impl CellBytesParser for CheckboxCellDataParser { + type Object = CheckboxCellData; + fn parse(&self, bytes: &Bytes) -> FlowyResult { + match String::from_utf8(bytes.to_vec()) { + Ok(s) => CheckboxCellData::from_str(&s), + Err(_) => Ok(CheckboxCellData("".to_string())), + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/tests.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs index 705b9bcdb0..35b6500a0d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs @@ -1,6 +1,6 @@ mod checkbox_option; mod checkbox_option_entities; -mod tests; +mod checkbox_tests; pub use checkbox_option::*; pub use checkbox_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs index 63ed4ee2a9..783b9faa7c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs @@ -1,22 +1,17 @@ -use crate::entities::{FieldType}; - +use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{ - AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, FromCellChangeset, - FromCellString, -}; +use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; use crate::services::field::{ BoxTypeOptionBuilder, DateCellChangeset, DateCellData, DateFormat, DateTimestamp, TimeFormat, TypeOptionBuilder, }; use bytes::Bytes; use chrono::format::strftime::StrftimeItems; use chrono::{NaiveDateTime, Timelike}; -use flowy_derive::{ProtoBuf}; +use flowy_derive::ProtoBuf; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use serde::{Deserialize, Serialize}; - // Date #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] pub struct DateTypeOption { @@ -129,7 +124,8 @@ impl CellDisplayable for DateTypeOption { _field_rev: &FieldRevision, ) -> FlowyResult { let timestamp = cell_data.try_into_inner()?; - CellBytes::from(self.today_desc_from_timestamp(timestamp)) + let date_cell_data = self.today_desc_from_timestamp(timestamp); + CellBytes::from(date_cell_data) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs index aa63eee9dd..b73c89a9b2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs @@ -1,6 +1,7 @@ use crate::entities::CellChangeset; use crate::entities::{CellIdentifier, CellIdentifierPayload}; -use crate::services::cell::{AnyCellData, FromCellChangeset, FromCellString}; +use crate::services::cell::{CellBytesParser, FromCellChangeset, FromCellString}; +use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{internal_error, ErrorCode, FlowyResult}; @@ -117,12 +118,6 @@ impl FromCellString for DateTimestamp { } } -impl std::convert::From for DateTimestamp { - fn from(data: AnyCellData) -> Self { - let num = data.data.parse::().unwrap_or(0); - DateTimestamp(num) - } -} #[derive(Clone, Debug, Copy, EnumIter, Serialize, Deserialize, ProtoBuf_Enum)] pub enum DateFormat { Local = 0, @@ -204,3 +199,12 @@ impl std::default::Default for TimeFormat { TimeFormat::TwentyFourHour } } + +pub struct DateCellDataParser(); +impl CellBytesParser for DateCellDataParser { + type Object = DateCellData; + + fn parse(&self, bytes: &Bytes) -> FlowyResult { + DateCellData::try_from(bytes.as_ref()).map_err(internal_error) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs similarity index 97% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/tests.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs index 22e6f08b49..0c81268f77 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs @@ -2,8 +2,8 @@ mod tests { use crate::entities::FieldType; use crate::services::cell::{CellDataChangeset, CellDataOperation}; - use crate::services::field::FieldBuilder; - use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; + use crate::services::field::*; + // use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; use flowy_grid_data_model::revision::FieldRevision; use strum::IntoEnumIterator; @@ -260,7 +260,7 @@ mod tests { let decoded_data = type_option .decode_cell_data(encoded_data.into(), &FieldType::DateTime, field_rev) .unwrap() - .parse::() + .with_parser(DateCellDataParser()) .unwrap(); if type_option.include_time { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs index 9785924a8c..fe00a14889 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs @@ -1,6 +1,6 @@ mod date_option; mod date_option_entities; -mod tests; +mod date_tests; pub use date_option::*; pub use date_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs index 8b4f9b2896..32a91961c9 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs @@ -2,7 +2,7 @@ mod format; mod number_option; mod number_option_entities; -mod tests; +mod number_tests; pub use format::*; pub use number_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs index 001bb4a0bc..26d1d64248 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs @@ -1,8 +1,6 @@ -use crate::impl_type_option; - use crate::entities::FieldType; +use crate::impl_type_option; use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation}; -use crate::services::field::number_currency::Currency; use crate::services::field::type_options::number_type_option::format::*; use crate::services::field::{BoxTypeOptionBuilder, NumberCellData, TypeOptionBuilder}; use bytes::Bytes; @@ -11,7 +9,7 @@ use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use rust_decimal::Decimal; -use rusty_money::Money; + use serde::{Deserialize, Serialize}; use std::str::FromStr; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs index e797165b03..7e47556fe5 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs @@ -1,6 +1,8 @@ +use crate::services::cell::CellBytesParser; use crate::services::field::number_currency::Currency; use crate::services::field::{strip_currency_symbol, NumberFormat, STRIP_SYMBOL}; -use flowy_error::{FlowyError, FlowyResult}; +use bytes::Bytes; +use flowy_error::{internal_error, FlowyError, FlowyResult}; use rust_decimal::Decimal; use rusty_money::Money; use std::str::FromStr; @@ -68,17 +70,17 @@ impl NumberCellData { } } -impl FromStr for NumberCellData { - type Err = rust_decimal::Error; - - fn from_str(s: &str) -> Result { - if s.is_empty() { - return Ok(Self::default()); - } - let decimal = Decimal::from_str(s)?; - Ok(Self::from_decimal(decimal)) - } -} +// impl FromStr for NumberCellData { +// type Err = FlowyError; +// +// fn from_str(s: &str) -> Result { +// if s.is_empty() { +// return Ok(Self::default()); +// } +// let decimal = Decimal::from_str(s).map_err(internal_error)?; +// Ok(Self::from_decimal(decimal)) +// } +// } impl ToString for NumberCellData { fn to_string(&self) -> String { @@ -91,3 +93,13 @@ impl ToString for NumberCellData { } } } +pub struct NumberCellDataParser(pub NumberFormat); +impl CellBytesParser for NumberCellDataParser { + type Object = NumberCellData; + fn parse(&self, bytes: &Bytes) -> FlowyResult { + match String::from_utf8(bytes.to_vec()) { + Ok(s) => NumberCellData::from_format_str(&s, true, &self.0), + Err(_) => Ok(NumberCellData::default()), + } + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/tests.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs index 050cf196f3..759114ca5a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs @@ -180,7 +180,7 @@ mod tests { type_option .decode_cell_data(cell_data.into(), &field_type, field_rev) .unwrap() - .parse::() + .with_parser(SelectOptionCellDataParser()) .unwrap() .select_options, ); diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index dcea1e209d..c06bf25957 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -1,8 +1,9 @@ use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType}; -use crate::services::cell::{AnyCellData, CellBytes, CellData, CellDisplayable, FromCellChangeset, FromCellString}; +use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; +use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; +use flowy_error::{internal_error, ErrorCode, FlowyResult}; use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry}; use nanoid::nanoid; @@ -160,20 +161,6 @@ impl SelectOptionIds { } } -impl std::convert::TryFrom for SelectOptionIds { - type Error = FlowyError; - - fn try_from(value: AnyCellData) -> Result { - Ok(Self::from(value.data)) - } -} - -impl std::convert::From for CellData { - fn from(any_cell_data: AnyCellData) -> Self { - any_cell_data.data.into() - } -} - impl FromCellString for SelectOptionIds { fn from_cell_str(s: &str) -> FlowyResult where @@ -215,6 +202,25 @@ impl std::ops::DerefMut for SelectOptionIds { &mut self.0 } } +pub struct SelectOptionIdsParser(); +impl CellBytesParser for SelectOptionIdsParser { + type Object = SelectOptionIds; + fn parse(&self, bytes: &Bytes) -> FlowyResult { + match String::from_utf8(bytes.to_vec()) { + Ok(s) => Ok(SelectOptionIds::from(s)), + Err(_) => Ok(SelectOptionIds::from("".to_owned())), + } + } +} + +pub struct SelectOptionCellDataParser(); +impl CellBytesParser for SelectOptionCellDataParser { + type Object = SelectOptionCellData; + + fn parse(&self, bytes: &Bytes) -> FlowyResult { + SelectOptionCellData::try_from(bytes.as_ref()).map_err(internal_error) + } +} #[derive(Clone, Debug, Default, ProtoBuf)] pub struct SelectOptionCellChangesetPayload { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs index f92fbd73d0..8aae4bf677 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs @@ -102,7 +102,7 @@ impl TypeOptionBuilder for SingleSelectTypeOptionBuilder { mod tests { use crate::entities::FieldType; use crate::services::cell::CellDataOperation; - + use crate::services::field::type_options::*; use crate::services::field::FieldBuilder; use flowy_grid_data_model::revision::FieldRevision; @@ -162,7 +162,7 @@ mod tests { type_option .decode_cell_data(cell_data.into(), &field_type, field_rev) .unwrap() - .parse::() + .with_parser(SelectOptionCellDataParser()) .unwrap() .select_options, ); diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs index e2d77ddfde..2716206dfd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs @@ -1,7 +1,8 @@ use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{ - try_decode_cell_data, AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, + try_decode_cell_data, CellBytes, CellBytesParser, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, + FromCellString, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; @@ -83,11 +84,23 @@ impl AsRef for TextCellData { } } -impl std::convert::TryFrom for TextCellData { - type Error = FlowyError; +impl FromCellString for TextCellData { + fn from_cell_str(s: &str) -> FlowyResult + where + Self: Sized, + { + Ok(TextCellData(s.to_owned())) + } +} - fn try_from(value: AnyCellData) -> Result { - Ok(TextCellData(value.data)) +pub struct TextCellDataParser(); +impl CellBytesParser for TextCellDataParser { + type Object = TextCellData; + fn parse(&self, bytes: &Bytes) -> FlowyResult { + match String::from_utf8(bytes.to_vec()) { + Ok(s) => Ok(TextCellData(s)), + Err(_) => Ok(TextCellData("".to_owned())), + } } } @@ -95,7 +108,7 @@ impl std::convert::TryFrom for TextCellData { mod tests { use crate::entities::FieldType; use crate::services::cell::CellDataOperation; - + use crate::services::field::FieldBuilder; use crate::services::field::*; @@ -111,7 +124,7 @@ mod tests { type_option .decode_cell_data(1647251762.to_string().into(), &field_type, &date_time_field_rev) .unwrap() - .parse::() + .with_parser(DateCellDataParser()) .unwrap() .date, "Mar 14,2022".to_owned() @@ -131,7 +144,7 @@ mod tests { &single_select_field_rev ) .unwrap() - .parse::() + .with_parser(SelectOptionCellDataParser()) .unwrap() .select_options, vec![done_option], @@ -154,7 +167,7 @@ mod tests { type_option .decode_cell_data(cell_data.into(), &FieldType::MultiSelect, &multi_select_field_rev) .unwrap() - .parse::() + .with_parser(SelectOptionCellDataParser()) .unwrap() .select_options, vec![google_option, facebook_option] diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs index ee0e0848dd..6c8dc96f88 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs @@ -1,6 +1,6 @@ -mod tests; mod url_option; mod url_option_entities; +mod url_tests; pub use url_option::*; pub use url_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs index d5fe0f287b..0d4ceb5caf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs @@ -1,13 +1,11 @@ use crate::entities::FieldType; use crate::impl_type_option; -use crate::services::cell::{ - AnyCellData, CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable, FromCellString, -}; +use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder, URLCellData}; use bytes::Bytes; use fancy_regex::Regex; use flowy_derive::ProtoBuf; -use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, FieldRevision, TypeOptionDataDeserializer, TypeOptionDataEntry}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; @@ -64,16 +62,12 @@ impl CellDataOperation for URLTypeOption { changeset: CellDataChangeset, _cell_rev: Option, ) -> Result { - let changeset = changeset.try_into_inner()?; + let content = changeset.try_into_inner()?; let mut url = "".to_string(); - if let Ok(Some(m)) = URL_REGEX.find(&changeset) { + if let Ok(Some(m)) = URL_REGEX.find(&content) { url = auto_append_scheme(m.as_str()); } - URLCellData { - url, - content: changeset, - } - .to_json() + URLCellData { url, content }.to_json() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs index b78335349e..ddb84cf9a7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs @@ -1,6 +1,7 @@ -use crate::services::cell::{AnyCellData, FromCellString}; +use crate::services::cell::{CellBytesParser, FromCellString}; +use bytes::Bytes; use flowy_derive::ProtoBuf; -use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_error::{internal_error, FlowyResult}; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] @@ -25,16 +26,17 @@ impl URLCellData { } } +pub struct URLCellDataParser(); +impl CellBytesParser for URLCellDataParser { + type Object = URLCellData; + + fn parse(&self, bytes: &Bytes) -> FlowyResult { + URLCellData::try_from(bytes.as_ref()).map_err(internal_error) + } +} + impl FromCellString for URLCellData { fn from_cell_str(s: &str) -> FlowyResult { serde_json::from_str::(s).map_err(internal_error) } } - -impl std::convert::TryFrom for URLCellData { - type Error = FlowyError; - - fn try_from(data: AnyCellData) -> Result { - serde_json::from_str::(&data.data).map_err(internal_error) - } -} diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs similarity index 95% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/tests.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs index 91940fb83c..6f74bdb4d4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs @@ -2,7 +2,7 @@ mod tests { use crate::entities::FieldType; use crate::services::cell::{CellData, CellDataOperation}; - use crate::services::field::FieldBuilder; + use crate::services::field::{FieldBuilder, URLCellDataParser}; use crate::services::field::{URLCellData, URLTypeOption}; use flowy_grid_data_model::revision::FieldRevision; @@ -61,7 +61,7 @@ mod tests { type_option .decode_cell_data(encoded_data.into(), field_type, field_rev) .unwrap() - .parse::() + .with_parser(URLCellDataParser()) .unwrap() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs index c5cf95d34b..ca67d7aeaf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs @@ -1,5 +1,5 @@ use crate::entities::{CheckboxCondition, GridCheckboxFilter}; -use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::cell::{AnyCellData, CellData, CellFilterOperation}; use crate::services::field::{CheckboxCellData, CheckboxTypeOption}; use flowy_error::FlowyResult; @@ -18,7 +18,8 @@ impl CellFilterOperation for CheckboxTypeOption { if !any_cell_data.is_checkbox() { return Ok(true); } - let checkbox_cell_data: CheckboxCellData = any_cell_data.try_into()?; + let cell_data: CellData = any_cell_data.into(); + let checkbox_cell_data = cell_data.try_into_inner()?; Ok(filter.is_visible(&checkbox_cell_data)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs index ae920c4edb..46e2571438 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/date_filter.rs @@ -1,5 +1,5 @@ use crate::entities::{DateFilterCondition, GridDateFilter}; -use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::cell::{AnyCellData, CellData, CellFilterOperation}; use crate::services::field::{DateTimestamp, DateTypeOption}; use flowy_error::FlowyResult; @@ -34,7 +34,8 @@ impl CellFilterOperation for DateTypeOption { if !any_cell_data.is_date() { return Ok(true); } - let timestamp: DateTimestamp = any_cell_data.into(); + let cell_data: CellData = any_cell_data.into(); + let timestamp = cell_data.try_into_inner()?; Ok(filter.is_visible(timestamp)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs index 7f3a5dd212..f44c1d2d62 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/number_filter.rs @@ -47,9 +47,7 @@ impl CellFilterOperation for NumberTypeOption { #[cfg(test)] mod tests { use crate::entities::{GridNumberFilter, NumberFilterCondition}; - use crate::services::field::{NumberCellData, NumberFormat}; - use std::str::FromStr; #[test] fn number_filter_equal_test() { let number_filter = GridNumberFilter { @@ -58,7 +56,7 @@ mod tests { }; for (num_str, visible) in [("123", true), ("1234", false), ("", false)] { - let data = NumberCellData::from_str(num_str).unwrap(); + let data = NumberCellData::from_format_str(num_str, true, &NumberFormat::Num).unwrap(); assert_eq!(number_filter.is_visible(&data), visible); } @@ -75,7 +73,7 @@ mod tests { content: Some("12".to_owned()), }; for (num_str, visible) in [("123", true), ("10", false), ("30", true), ("", false)] { - let data = NumberCellData::from_str(num_str).unwrap(); + let data = NumberCellData::from_format_str(num_str, true, &NumberFormat::Num).unwrap(); assert_eq!(number_filter.is_visible(&data), visible); } } @@ -87,7 +85,7 @@ mod tests { content: Some("100".to_owned()), }; for (num_str, visible) in [("12", true), ("1234", false), ("30", true), ("", true)] { - let data = NumberCellData::from_str(num_str).unwrap(); + let data = NumberCellData::from_format_str(num_str, true, &NumberFormat::Num).unwrap(); assert_eq!(number_filter.is_visible(&data), visible); } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs index 45165e35e2..25f3902ceb 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/text_filter.rs @@ -1,5 +1,5 @@ use crate::entities::{GridTextFilter, TextFilterCondition}; -use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::cell::{AnyCellData, CellData, CellFilterOperation}; use crate::services::field::{RichTextTypeOption, TextCellData}; use flowy_error::FlowyResult; @@ -30,7 +30,8 @@ impl CellFilterOperation for RichTextTypeOption { return Ok(true); } - let text_cell_data: TextCellData = any_cell_data.try_into()?; + let cell_data: CellData = any_cell_data.into(); + let text_cell_data = cell_data.try_into_inner()?; Ok(filter.is_visible(text_cell_data)) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs index 50f9c815fc..15254d4713 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/url_filter.rs @@ -1,5 +1,5 @@ use crate::entities::GridTextFilter; -use crate::services::cell::{AnyCellData, CellFilterOperation}; +use crate::services::cell::{AnyCellData, CellData, CellFilterOperation}; use crate::services::field::{TextCellData, URLTypeOption}; use flowy_error::FlowyResult; @@ -9,7 +9,8 @@ impl CellFilterOperation for URLTypeOption { return Ok(true); } - let text_cell_data: TextCellData = any_cell_data.try_into()?; + let cell_data: CellData = any_cell_data.into(); + let text_cell_data = cell_data.try_into_inner()?; Ok(filter.is_visible(&text_cell_data)) } } 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 919e24f2bf..f9a618d145 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -3,7 +3,7 @@ use crate::entities::CellIdentifier; use crate::entities::*; use crate::manager::{GridTaskSchedulerRwLock, GridUser}; use crate::services::block_manager::GridBlockManager; -use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data}; +use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellBytes}; use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder}; use crate::services::filter::{GridFilterChangeset, GridFilterService}; use crate::services::persistence::block_index::BlockIndexCache; @@ -340,16 +340,16 @@ impl GridRevisionEditor { } pub async fn get_cell(&self, params: &CellIdentifier) -> Option { + let cell_bytes = self.get_cell_bytes(params).await?; + Some(Cell::new(¶ms.field_id, cell_bytes.to_vec())) + } + + pub async fn get_cell_bytes(&self, params: &CellIdentifier) -> Option { let field_rev = self.get_field_rev(¶ms.field_id).await?; let row_rev = self.block_manager.get_row_rev(¶ms.row_id).await.ok()??; let cell_rev = row_rev.cells.get(¶ms.field_id)?.clone(); - let data = decode_any_cell_data(cell_rev.data, &field_rev).to_vec(); - Some(Cell::new(¶ms.field_id, data)) - } - - pub async fn get_cell_display(&self, _params: &CellIdentifier) -> Option { - todo!() + Some(decode_any_cell_data(cell_rev.data, &field_rev)) } pub async fn get_cell_rev(&self, row_id: &str, field_id: &str) -> FlowyResult> { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index ec57893d9b..0278a40090 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -1,5 +1,6 @@ use crate::grid::block_test::script::GridRowTest; use crate::grid::block_test::script::RowScript::*; +use flowy_grid::entities::FieldType; use flowy_grid_data_model::revision::RowMetaChangeset; #[tokio::test] @@ -67,15 +68,48 @@ async fn grid_row_add_cells_test() { let mut test = GridRowTest::new().await; let mut builder = test.row_builder(); - builder.insert_text_cell("hello world"); - builder.insert_number_cell("18,443"); - builder.insert_date_cell("1647251762"); - builder.insert_single_select_cell(|options| options.first().unwrap()); + let text_field_id = builder.insert_text_cell("hello world"); + let number_field_id = builder.insert_number_cell("18,443"); + let date_field_id = builder.insert_date_cell("1647251762"); + let single_select_field_id = builder.insert_single_select_cell(|options| options.first().unwrap()); builder.insert_multi_select_cell(|options| options); builder.insert_checkbox_cell("false"); - builder.insert_url_cell("1"); + let url_field_id = builder.insert_url_cell("https://appflowy.io"); let row_rev = builder.build(); - let scripts = vec![CreateRow { row_rev }]; + let row_id = row_rev.id.clone(); + let scripts = vec![ + CreateRow { row_rev }, + AssertCell { + row_id: row_id.clone(), + field_id: text_field_id, + field_type: FieldType::RichText, + expected: "hello world".to_owned(), + }, + AssertCell { + row_id: row_id.clone(), + field_id: number_field_id, + field_type: FieldType::Number, + expected: "$18,443.00".to_owned(), + }, + AssertCell { + row_id: row_id.clone(), + field_id: single_select_field_id, + field_type: FieldType::SingleSelect, + expected: "Completed".to_owned(), + }, + AssertCell { + row_id: row_id.clone(), + field_id: date_field_id, + field_type: FieldType::DateTime, + expected: "2022/03/14".to_owned(), + }, + AssertCell { + row_id: row_id.clone(), + field_id: url_field_id, + field_type: FieldType::URL, + expected: "https://appflowy.io/".to_owned(), + }, + ]; test.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 642cd51670..872748fd23 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -1,7 +1,11 @@ use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; -use flowy_grid::entities::{CellIdentifier, RowInfo}; +use flowy_grid::entities::{CellIdentifier, FieldType, RowInfo}; +use flowy_grid::services::field::{ + DateCellDataParser, NumberCellDataParser, NumberFormat, NumberTypeOption, SelectOptionCellDataParser, + SelectOptionIdsParser, SelectOptionOperation, SingleSelectTypeOption, TextCellDataParser, URLCellDataParser, +}; use flowy_grid_data_model::revision::{ GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, }; @@ -24,7 +28,8 @@ pub enum RowScript { AssertCell { row_id: String, field_id: String, - expected_display: Option, + field_type: FieldType, + expected: String, }, AssertRowCount(usize), CreateBlock { @@ -101,20 +106,15 @@ impl GridRowTest { RowScript::AssertCell { row_id, field_id, - expected_display, + field_type, + expected, } => { let id = CellIdentifier { grid_id: self.grid_id.clone(), field_id, row_id, }; - let display = self.editor.get_cell_display(&id).await; - match expected_display { - None => {} - Some(expected_display) => { - assert_eq!(display.unwrap(), expected_display); - } - } + self.compare_cell_content(id, field_type, expected).await; } RowScript::AssertRow { expected_row } => { let row = &*self @@ -153,6 +153,72 @@ impl GridRowTest { } } } + + async fn compare_cell_content(&self, cell_id: CellIdentifier, field_type: FieldType, expected: String) { + match field_type { + FieldType::RichText => { + let cell_data = self + .editor + .get_cell_bytes(&cell_id) + .await + .unwrap() + .with_parser(TextCellDataParser()) + .unwrap(); + + assert_eq!(cell_data.as_ref(), &expected); + } + FieldType::Number => { + let field_rev = self.editor.get_field_rev(&cell_id.field_id).await.unwrap(); + let number_type_option = field_rev + .get_type_option_entry::(FieldType::Number.into()) + .unwrap(); + let cell_data = self + .editor + .get_cell_bytes(&cell_id) + .await + .unwrap() + .with_parser(NumberCellDataParser(number_type_option.format.clone())) + .unwrap(); + assert_eq!(cell_data.to_string(), expected); + } + FieldType::DateTime => { + let cell_data = self + .editor + .get_cell_bytes(&cell_id) + .await + .unwrap() + .with_parser(DateCellDataParser()) + .unwrap(); + + assert_eq!(cell_data.date, expected); + } + FieldType::SingleSelect => { + let select_options = self + .editor + .get_cell_bytes(&cell_id) + .await + .unwrap() + .with_parser(SelectOptionCellDataParser()) + .unwrap(); + let select_option = select_options.select_options.first().unwrap(); + assert_eq!(select_option.name, expected); + } + FieldType::MultiSelect => {} + FieldType::Checkbox => {} + FieldType::URL => { + let cell_data = self + .editor + .get_cell_bytes(&cell_id) + .await + .unwrap() + .with_parser(URLCellDataParser()) + .unwrap(); + + assert_eq!(cell_data.content, expected); + assert_eq!(cell_data.url, expected); + } + } + } } impl std::ops::Deref for GridRowTest { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs index 07db75161a..397c7100db 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs @@ -23,21 +23,24 @@ impl<'a> GridRowTestBuilder<'a> { } } - pub fn insert_text_cell(&mut self, data: &str) { + pub fn insert_text_cell(&mut self, data: &str) -> String { let text_field = self.field_rev_with_type(&FieldType::RichText); self.inner_builder .insert_cell(&text_field.id, data.to_string()) .unwrap(); + + text_field.id.clone() } - pub fn insert_number_cell(&mut self, data: &str) { + pub fn insert_number_cell(&mut self, data: &str) -> String { let number_field = self.field_rev_with_type(&FieldType::Number); self.inner_builder .insert_cell(&number_field.id, data.to_string()) .unwrap(); + number_field.id.clone() } - pub fn insert_date_cell(&mut self, data: &str) { + pub fn insert_date_cell(&mut self, data: &str) -> String { let value = serde_json::to_string(&DateCellChangeset { date: Some(data.to_string()), time: None, @@ -45,6 +48,7 @@ impl<'a> GridRowTestBuilder<'a> { .unwrap(); let date_field = self.field_rev_with_type(&FieldType::DateTime); self.inner_builder.insert_cell(&date_field.id, value).unwrap(); + date_field.id.clone() } pub fn insert_checkbox_cell(&mut self, data: &str) { @@ -54,14 +58,13 @@ impl<'a> GridRowTestBuilder<'a> { .unwrap(); } - pub fn insert_url_cell(&mut self, data: &str) { - let number_field = self.field_rev_with_type(&FieldType::URL); - self.inner_builder - .insert_cell(&number_field.id, data.to_string()) - .unwrap(); + pub fn insert_url_cell(&mut self, data: &str) -> String { + let url_field = self.field_rev_with_type(&FieldType::URL); + self.inner_builder.insert_cell(&url_field.id, data.to_string()).unwrap(); + url_field.id.clone() } - pub fn insert_single_select_cell(&mut self, f: F) + pub fn insert_single_select_cell(&mut self, f: F) -> String where F: Fn(&Vec) -> &SelectOption, { @@ -71,6 +74,8 @@ impl<'a> GridRowTestBuilder<'a> { self.inner_builder .insert_select_option_cell(&single_select_field.id, option.id.clone()) .unwrap(); + + single_select_field.id.clone() } pub fn insert_multi_select_cell(&mut self, f: F) diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs index 29614b21b2..e954ebe512 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs @@ -1,12 +1,12 @@ use crate::grid::filter_test::script::FilterScript::*; use crate::grid::filter_test::script::*; -use flowy_grid::entities::{CreateGridFilterPayload, TextFilterCondition}; +use flowy_grid::entities::{CreateGridFilterPayload, FieldType, TextFilterCondition}; use flowy_grid_data_model::revision::FieldRevision; #[tokio::test] async fn grid_filter_create_test() { let mut test = GridFilterTest::new().await; - let field_rev = test.text_field(); + let field_rev = test.get_field_rev(FieldType::RichText); 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; @@ -16,7 +16,7 @@ async fn grid_filter_create_test() { #[should_panic] async fn grid_filter_invalid_condition_panic_test() { let mut test = GridFilterTest::new().await; - let field_rev = test.text_field().clone(); + let field_rev = test.get_field_rev(FieldType::RichText).clone(); // 100 is not a valid condition, so this test should be panic. let payload = CreateGridFilterPayload::new(&field_rev, 100, Some("".to_owned())); @@ -27,7 +27,7 @@ async fn grid_filter_invalid_condition_panic_test() { #[tokio::test] async fn grid_filter_delete_test() { let mut test = GridFilterTest::new().await; - let field_rev = test.text_field().clone(); + let field_rev = test.get_field_rev(FieldType::RichText).clone(); let payload = create_filter(&field_rev, TextFilterCondition::TextIsEmpty, "abc"); let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }]; test.run_scripts(scripts).await; @@ -36,7 +36,7 @@ async fn grid_filter_delete_test() { test.run_scripts(vec![ DeleteGridTableFilter { filter_id: filter.id, - field_rev, + field_rev: field_rev.as_ref().clone(), }, AssertTableFilterCount { count: 0 }, ]) diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index d5429623a3..3366264936 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -64,7 +64,7 @@ impl GridEditorTest { } } - pub(crate) async fn get_row_revs(&self) -> Vec> { + pub async fn get_row_revs(&self) -> Vec> { self.editor .grid_block_snapshots(None) .await @@ -79,12 +79,12 @@ impl GridEditorTest { self.editor.get_grid_filter(&layout_type).await.unwrap() } - pub fn text_field(&self) -> &FieldRevision { + pub fn get_field_rev(&self, field_type: FieldType) -> &Arc { self.field_revs .iter() .filter(|field_rev| { let t_field_type: FieldType = field_rev.field_type_rev.into(); - t_field_type == FieldType::RichText + t_field_type == field_type }) .collect::>() .pop() @@ -129,7 +129,6 @@ fn make_test_grid() -> BuildGridContext { FieldType::SingleSelect => { // Single Select let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Live")) .option(SelectOption::new("Completed")) .option(SelectOption::new("Planned")) .option(SelectOption::new("Paused")); From d02acbae6eb0292188ed83149183e52dd5c29a20 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 13 Jul 2022 22:56:34 +0800 Subject: [PATCH 015/112] chore: add more test --- .../grid/cell/cell_service/cell_service.dart | 4 +- .../application/grid/cell/date_cal_bloc.dart | 1 + .../application/grid/cell/date_cell_bloc.dart | 2 +- .../application/grid/cell/url_cell_bloc.dart | 2 +- .../grid/cell/url_cell_editor_bloc.dart | 2 +- .../grid/field/type_option/date_bloc.dart | 1 + .../src/widgets/header/type_option/date.dart | 2 +- ...kbox_option.rs => checkbox_type_option.rs} | 0 ...es.rs => checkbox_type_option_entities.rs} | 2 +- .../type_options/checkbox_type_option/mod.rs | 8 +- .../{date_option.rs => date_type_option.rs} | 0 ...tities.rs => date_type_option_entities.rs} | 0 .../type_options/date_type_option/mod.rs | 8 +- .../type_options/number_type_option/mod.rs | 8 +- ...number_option.rs => number_type_option.rs} | 0 ...ties.rs => number_type_option_entities.rs} | 2 +- .../type_options/text_type_option/mod.rs | 4 +- .../{text_option.rs => text_type_option.rs} | 0 .../field/type_options/url_type_option/mod.rs | 8 +- .../{url_option.rs => url_type_option.rs} | 0 ...ntities.rs => url_type_option_entities.rs} | 0 .../flowy-grid/src/services/grid_editor.rs | 6 +- .../src/services/row/row_builder.rs | 9 +- .../tests/grid/block_test/row_test.rs | 109 ++++++----- .../tests/grid/block_test/script.rs | 174 ++++++++++++++++-- .../flowy-grid/tests/grid/block_test/util.rs | 39 +++- .../flowy-grid/tests/grid/grid_editor.rs | 20 +- .../src/client_grid/grid_builder.rs | 4 + 28 files changed, 311 insertions(+), 104 deletions(-) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/{checkbox_option.rs => checkbox_type_option.rs} (100%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/{checkbox_option_entities.rs => checkbox_type_option_entities.rs} (97%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/{date_option.rs => date_type_option.rs} (100%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/{date_option_entities.rs => date_type_option_entities.rs} (100%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/{number_option.rs => number_type_option.rs} (100%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/{number_option_entities.rs => number_type_option_entities.rs} (98%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/{text_option.rs => text_type_option.rs} (100%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/{url_option.rs => url_type_option.rs} (100%) rename frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/{url_option_entities.rs => url_type_option_entities.rs} (100%) 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 5e406c0c26..bc5c683414 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 @@ -7,10 +7,10 @@ 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/cell_entities.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option_entities.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 28f8bf1b10..c5cfe397a3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -5,6 +5,7 @@ import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:table_calendar/table_calendar.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index 00780143cc..7c03354134 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -1,4 +1,4 @@ -import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart index e1fe39c3bf..6129f90f71 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart @@ -1,4 +1,4 @@ -import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart index 6e4990943f..dcb643d535 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart @@ -1,4 +1,4 @@ -import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart index 8784422c54..556b33d40f 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart index f4031dc9ce..b9b2f8e89d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart @@ -9,7 +9,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option.rs diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs similarity index 97% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs index 5a8bf1e7a7..54cde9b310 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs @@ -57,7 +57,7 @@ impl ToString for CheckboxCellData { self.0.clone() } } -pub struct CheckboxCellDataParser; +pub struct CheckboxCellDataParser(); impl CellBytesParser for CheckboxCellDataParser { type Object = CheckboxCellData; fn parse(&self, bytes: &Bytes) -> FlowyResult { diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs index 35b6500a0d..61013fac08 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs @@ -1,6 +1,6 @@ -mod checkbox_option; -mod checkbox_option_entities; mod checkbox_tests; +mod checkbox_type_option; +mod checkbox_type_option_entities; -pub use checkbox_option::*; -pub use checkbox_option_entities::*; +pub use checkbox_type_option::*; +pub use checkbox_type_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_option_entities.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs index fe00a14889..8ca49fdd15 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs @@ -1,6 +1,6 @@ -mod date_option; -mod date_option_entities; mod date_tests; +mod date_type_option; +mod date_type_option_entities; -pub use date_option::*; -pub use date_option_entities::*; +pub use date_type_option::*; +pub use date_type_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs index 32a91961c9..4b2bcc1ecd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/mod.rs @@ -1,9 +1,9 @@ #![allow(clippy::module_inception)] mod format; -mod number_option; -mod number_option_entities; mod number_tests; +mod number_type_option; +mod number_type_option_entities; pub use format::*; -pub use number_option::*; -pub use number_option_entities::*; +pub use number_type_option::*; +pub use number_type_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option.rs diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option_entities.rs similarity index 98% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option_entities.rs index 7e47556fe5..6297114a07 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_type_option_entities.rs @@ -2,7 +2,7 @@ use crate::services::cell::CellBytesParser; use crate::services::field::number_currency::Currency; use crate::services::field::{strip_currency_symbol, NumberFormat, STRIP_SYMBOL}; use bytes::Bytes; -use flowy_error::{internal_error, FlowyError, FlowyResult}; +use flowy_error::{FlowyError, FlowyResult}; use rust_decimal::Decimal; use rusty_money::Money; use std::str::FromStr; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs index 9f41c61fdd..3c1d2287cd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs @@ -1,2 +1,2 @@ -mod text_option; -pub use text_option::*; +mod text_type_option; +pub use text_type_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs index 6c8dc96f88..e3b2ae16bd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs @@ -1,6 +1,6 @@ -mod url_option; -mod url_option_entities; mod url_tests; +mod url_type_option; +mod url_type_option_entities; -pub use url_option::*; -pub use url_option_entities::*; +pub use url_type_option::*; +pub use url_type_option_entities::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs similarity index 100% rename from frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_option_entities.rs rename to frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs 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 f9a618d145..70804f1404 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -270,10 +270,14 @@ impl GridRevisionEditor { pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { let field_revs = self.grid_pad.read().await.get_field_revs(None)?; + let field_revs_ref = field_revs + .iter() + .map(|field_rev| field_rev.as_ref()) + .collect::>(); let block_id = self.block_id().await?; // insert empty row below the row whose id is upper_row_id - let row_rev = RowRevisionBuilder::new(&field_revs).build(&block_id); + let row_rev = RowRevisionBuilder::new(&field_revs_ref).build(&block_id); let row_order = RowInfo::from(&row_rev); // insert the row diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs index fb8c2550e4..6ccb553fc1 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs @@ -4,19 +4,18 @@ use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT}; use indexmap::IndexMap; use std::collections::HashMap; -use std::sync::Arc; pub struct RowRevisionBuilder<'a> { - field_rev_map: HashMap<&'a String, &'a Arc>, + field_rev_map: HashMap<&'a String, &'a FieldRevision>, payload: CreateRowRevisionPayload, } impl<'a> RowRevisionBuilder<'a> { - pub fn new(fields: &'a [Arc]) -> Self { + pub fn new(fields: &'a [&'a FieldRevision]) -> Self { let field_rev_map = fields .iter() - .map(|field| (&field.id, field)) - .collect::>>(); + .map(|field| (&field.id, *field)) + .collect::>(); let payload = CreateRowRevisionPayload { row_id: gen_row_id(), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index 0278a40090..02e7ccc050 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -1,6 +1,8 @@ -use crate::grid::block_test::script::GridRowTest; use crate::grid::block_test::script::RowScript::*; +use crate::grid::block_test::script::{CreateRowScriptBuilder, GridRowTest}; +use crate::grid::grid_editor::{COMPLETED, FACEBOOK, GOOGLE, PAUSED, TWITTER}; use flowy_grid::entities::FieldType; +use flowy_grid::services::field::{NO, SELECTION_IDS_SEPARATOR}; use flowy_grid_data_model::revision::RowMetaChangeset; #[tokio::test] @@ -66,50 +68,65 @@ async fn grid_delete_row() { #[tokio::test] async fn grid_row_add_cells_test() { let mut test = GridRowTest::new().await; - let mut builder = test.row_builder(); + let mut builder = CreateRowScriptBuilder::new(&test); + builder.insert(FieldType::RichText, "hello world", "hello world"); + builder.insert(FieldType::DateTime, "1647251762", "2022/03/14"); + builder.insert(FieldType::Number, "18,443", "$18,443.00"); + builder.insert(FieldType::Checkbox, "false", NO); + builder.insert(FieldType::URL, "https://appflowy.io", "https://appflowy.io"); + builder.insert_single_select_cell(|mut options| options.remove(0), COMPLETED); + builder.insert_multi_select_cell( + |options| options, + &vec![GOOGLE, FACEBOOK, TWITTER].join(SELECTION_IDS_SEPARATOR), + ); - let text_field_id = builder.insert_text_cell("hello world"); - let number_field_id = builder.insert_number_cell("18,443"); - let date_field_id = builder.insert_date_cell("1647251762"); - let single_select_field_id = builder.insert_single_select_cell(|options| options.first().unwrap()); - builder.insert_multi_select_cell(|options| options); - builder.insert_checkbox_cell("false"); - let url_field_id = builder.insert_url_cell("https://appflowy.io"); - - let row_rev = builder.build(); - let row_id = row_rev.id.clone(); - let scripts = vec![ - CreateRow { row_rev }, - AssertCell { - row_id: row_id.clone(), - field_id: text_field_id, - field_type: FieldType::RichText, - expected: "hello world".to_owned(), - }, - AssertCell { - row_id: row_id.clone(), - field_id: number_field_id, - field_type: FieldType::Number, - expected: "$18,443.00".to_owned(), - }, - AssertCell { - row_id: row_id.clone(), - field_id: single_select_field_id, - field_type: FieldType::SingleSelect, - expected: "Completed".to_owned(), - }, - AssertCell { - row_id: row_id.clone(), - field_id: date_field_id, - field_type: FieldType::DateTime, - expected: "2022/03/14".to_owned(), - }, - AssertCell { - row_id: row_id.clone(), - field_id: url_field_id, - field_type: FieldType::URL, - expected: "https://appflowy.io/".to_owned(), - }, - ]; - test.run_scripts(scripts).await; + test.run_scripts(builder.build()).await; +} + +#[tokio::test] +async fn grid_row_insert_number_test() { + let mut test = GridRowTest::new().await; + for (val, expected) in &[("1647251762", "2022/03/14"), ("2022/03/14", ""), ("", "")] { + let mut builder = CreateRowScriptBuilder::new(&test); + builder.insert(FieldType::DateTime, val, expected); + test.run_scripts(builder.build()).await; + } +} + +#[tokio::test] +async fn grid_row_insert_date_test() { + let mut test = GridRowTest::new().await; + for (val, expected) in &[ + ("18,443", "$18,443.00"), + ("0", "$0.00"), + ("100000", "$100,000.00"), + ("$100,000.00", "$100,000.00"), + ("", ""), + ] { + let mut builder = CreateRowScriptBuilder::new(&test); + builder.insert(FieldType::Number, val, expected); + test.run_scripts(builder.build()).await; + } +} +#[tokio::test] +async fn grid_row_insert_single_select_test() { + let mut test = GridRowTest::new().await; + let mut builder = CreateRowScriptBuilder::new(&test); + builder.insert_single_select_cell(|mut options| options.pop().unwrap(), PAUSED); + test.run_scripts(builder.build()).await; +} + +#[tokio::test] +async fn grid_row_insert_multi_select_test() { + let mut test = GridRowTest::new().await; + let mut builder = CreateRowScriptBuilder::new(&test); + builder.insert_multi_select_cell( + |mut options| { + options.remove(0); + options + }, + &vec![FACEBOOK, TWITTER].join(SELECTION_IDS_SEPARATOR), + ); + + test.run_scripts(builder.build()).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 872748fd23..366d1e6c80 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -1,15 +1,18 @@ +use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow}; use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; use flowy_grid::entities::{CellIdentifier, FieldType, RowInfo}; - use flowy_grid::services::field::{ - DateCellDataParser, NumberCellDataParser, NumberFormat, NumberTypeOption, SelectOptionCellDataParser, - SelectOptionIdsParser, SelectOptionOperation, SingleSelectTypeOption, TextCellDataParser, URLCellDataParser, + CheckboxCellDataParser, DateCellDataParser, MultiSelectTypeOption, NumberCellDataParser, NumberTypeOption, + SelectOption, SelectOptionCellDataParser, SelectOptionIdsParser, SingleSelectTypeOption, TextCellDataParser, + URLCellDataParser, SELECTION_IDS_SEPARATOR, }; use flowy_grid_data_model::revision::{ - GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, + FieldRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, }; +use std::collections::HashMap; use std::sync::Arc; +use strum::IntoEnumIterator; pub enum RowScript { CreateEmptyRow, @@ -71,7 +74,19 @@ impl GridRowTest { } pub fn row_builder(&self) -> GridRowTestBuilder { - GridRowTestBuilder::new(self.block_id(), &self.field_revs) + let field_revs_ref = self + .field_revs + .iter() + .map(|field_rev| field_rev.as_ref()) + .collect::>(); + GridRowTestBuilder::new( + self.block_id(), + &self + .field_revs + .iter() + .map(|field_rev| field_rev.as_ref()) + .collect::>(), + ) } pub async fn run_script(&mut self, script: RowScript) { @@ -177,7 +192,7 @@ impl GridRowTest { .get_cell_bytes(&cell_id) .await .unwrap() - .with_parser(NumberCellDataParser(number_type_option.format.clone())) + .with_parser(NumberCellDataParser(number_type_option.format)) .unwrap(); assert_eq!(cell_data.to_string(), expected); } @@ -193,18 +208,45 @@ impl GridRowTest { assert_eq!(cell_data.date, expected); } FieldType::SingleSelect => { - let select_options = self + let cell_data = self .editor .get_cell_bytes(&cell_id) .await .unwrap() .with_parser(SelectOptionCellDataParser()) .unwrap(); - let select_option = select_options.select_options.first().unwrap(); + let select_option = cell_data.select_options.first().unwrap(); assert_eq!(select_option.name, expected); } - FieldType::MultiSelect => {} - FieldType::Checkbox => {} + FieldType::MultiSelect => { + let cell_data = self + .editor + .get_cell_bytes(&cell_id) + .await + .unwrap() + .with_parser(SelectOptionCellDataParser()) + .unwrap(); + + let s = cell_data + .select_options + .into_iter() + .map(|option| option.name) + .collect::>() + .join(SELECTION_IDS_SEPARATOR); + + assert_eq!(s, expected); + } + + FieldType::Checkbox => { + let cell_data = self + .editor + .get_cell_bytes(&cell_id) + .await + .unwrap() + .with_parser(CheckboxCellDataParser()) + .unwrap(); + assert_eq!(cell_data.to_string(), expected); + } FieldType::URL => { let cell_data = self .editor @@ -215,7 +257,7 @@ impl GridRowTest { .unwrap(); assert_eq!(cell_data.content, expected); - assert_eq!(cell_data.url, expected); + // assert_eq!(cell_data.url, expected); } } } @@ -234,3 +276,113 @@ impl std::ops::DerefMut for GridRowTest { &mut self.inner } } + +pub struct CreateRowScriptBuilder<'a> { + builder: GridRowTestBuilder<'a>, + data_by_field_type: HashMap, + output_by_field_type: HashMap, +} + +impl<'a> CreateRowScriptBuilder<'a> { + pub fn new(test: &'a GridRowTest) -> Self { + Self { + builder: test.row_builder(), + data_by_field_type: HashMap::new(), + output_by_field_type: HashMap::new(), + } + } + + pub fn insert(&mut self, field_type: FieldType, input: &str, expected: &str) { + self.data_by_field_type.insert( + field_type, + CellTestData { + input: input.to_string(), + expected: expected.to_owned(), + }, + ); + } + + pub fn insert_single_select_cell(&mut self, f: F, expected: &str) + where + F: Fn(Vec) -> SelectOption, + { + let field_id = self.builder.insert_single_select_cell(f); + self.output_by_field_type.insert( + FieldType::SingleSelect, + CellTestOutput { + field_id, + expected: expected.to_owned(), + }, + ); + } + + pub fn insert_multi_select_cell(&mut self, f: F, expected: &str) + where + F: Fn(Vec) -> Vec, + { + let field_id = self.builder.insert_multi_select_cell(f); + self.output_by_field_type.insert( + FieldType::MultiSelect, + CellTestOutput { + field_id, + expected: expected.to_owned(), + }, + ); + } + + pub fn build(mut self) -> Vec { + let mut scripts = vec![]; + let output_by_field_type = &mut self.output_by_field_type; + + for field_type in FieldType::iter() { + let field_type: FieldType = field_type; + if let Some(data) = self.data_by_field_type.get(&field_type) { + let field_id = match field_type { + FieldType::RichText => self.builder.insert_text_cell(&data.input), + FieldType::Number => self.builder.insert_number_cell(&data.input), + FieldType::DateTime => self.builder.insert_date_cell(&data.input), + FieldType::Checkbox => self.builder.insert_checkbox_cell(&data.input), + FieldType::URL => self.builder.insert_url_cell(&data.input), + _ => "".to_owned(), + }; + + if !field_id.is_empty() { + output_by_field_type.insert( + field_type, + CellTestOutput { + field_id, + expected: data.expected.clone(), + }, + ); + } + } + } + + let row_rev = self.builder.build(); + let row_id = row_rev.id.clone(); + scripts.push(CreateRow { row_rev }); + + for field_type in FieldType::iter() { + if let Some(data) = output_by_field_type.get(&field_type) { + let script = AssertCell { + row_id: row_id.clone(), + field_id: data.field_id.clone(), + field_type, + expected: data.expected.clone(), + }; + scripts.push(script); + } + } + scripts + } +} + +pub struct CellTestData { + pub input: String, + pub expected: String, +} + +struct CellTestOutput { + field_id: String, + expected: String, +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs index 397c7100db..ca1e45465e 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs @@ -1,19 +1,21 @@ use flowy_grid::entities::FieldType; -use flowy_grid::services::field::selection_type_option::{SelectOption, SELECTION_IDS_SEPARATOR}; -use flowy_grid::services::field::{DateCellChangeset, MultiSelectTypeOption, SingleSelectTypeOption}; + +use flowy_grid::services::field::{ + DateCellChangeset, MultiSelectTypeOption, SelectOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, +}; use flowy_grid::services::row::RowRevisionBuilder; use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; -use std::sync::Arc; + use strum::EnumCount; pub struct GridRowTestBuilder<'a> { block_id: String, - field_revs: &'a [Arc], + field_revs: &'a [&'a FieldRevision], inner_builder: RowRevisionBuilder<'a>, } impl<'a> GridRowTestBuilder<'a> { - pub fn new(block_id: &str, field_revs: &'a [Arc]) -> Self { + pub fn new(block_id: &str, field_revs: &'a [&'a FieldRevision]) -> Self { assert_eq!(field_revs.len(), FieldType::COUNT); let inner_builder = RowRevisionBuilder::new(field_revs); Self { @@ -51,11 +53,13 @@ impl<'a> GridRowTestBuilder<'a> { date_field.id.clone() } - pub fn insert_checkbox_cell(&mut self, data: &str) { - let number_field = self.field_rev_with_type(&FieldType::Checkbox); + pub fn insert_checkbox_cell(&mut self, data: &str) -> String { + let checkbox_field = self.field_rev_with_type(&FieldType::Checkbox); self.inner_builder - .insert_cell(&number_field.id, data.to_string()) + .insert_cell(&checkbox_field.id, data.to_string()) .unwrap(); + + checkbox_field.id.clone() } pub fn insert_url_cell(&mut self, data: &str) -> String { @@ -64,6 +68,7 @@ impl<'a> GridRowTestBuilder<'a> { url_field.id.clone() } + #[allow(dead_code)] pub fn insert_single_select_cell(&mut self, f: F) -> String where F: Fn(&Vec) -> &SelectOption, @@ -78,7 +83,7 @@ impl<'a> GridRowTestBuilder<'a> { single_select_field.id.clone() } - pub fn insert_multi_select_cell(&mut self, f: F) + pub fn insert_multi_select_cell(&mut self, f: F) -> String where F: Fn(&Vec) -> &Vec, { @@ -93,6 +98,8 @@ impl<'a> GridRowTestBuilder<'a> { self.inner_builder .insert_select_option_cell(&multi_select_field.id, ops_ids) .unwrap(); + + multi_select_field.id.clone() } pub fn field_rev_with_type(&self, field_type: &FieldType) -> FieldRevision { @@ -111,3 +118,17 @@ impl<'a> GridRowTestBuilder<'a> { self.inner_builder.build(&self.block_id) } } + +impl<'a> std::ops::Deref for GridRowTestBuilder<'a> { + type Target = RowRevisionBuilder<'a>; + + fn deref(&self) -> &Self::Target { + &self.inner_builder + } +} + +impl<'a> std::ops::DerefMut for GridRowTestBuilder<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner_builder + } +} diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index 3366264936..8d6a2043d0 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -96,6 +96,14 @@ impl GridEditorTest { } } +pub const GOOGLE: &str = "Google"; +pub const FACEBOOK: &str = "Facebook"; +pub const TWITTER: &str = "Twitter"; + +pub const COMPLETED: &str = "Completed"; +pub const PLANNED: &str = "Planned"; +pub const PAUSED: &str = "Paused"; + // This grid is assumed to contain all the Fields. fn make_test_grid() -> BuildGridContext { let mut grid_builder = GridBuilder::new(); @@ -129,18 +137,18 @@ fn make_test_grid() -> BuildGridContext { FieldType::SingleSelect => { // Single Select let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Completed")) - .option(SelectOption::new("Planned")) - .option(SelectOption::new("Paused")); + .option(SelectOption::new(COMPLETED)) + .option(SelectOption::new(PLANNED)) + .option(SelectOption::new(PAUSED)); let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); grid_builder.add_field(single_select_field); } FieldType::MultiSelect => { // MultiSelect let multi_select = MultiSelectTypeOptionBuilder::default() - .option(SelectOption::new("Google")) - .option(SelectOption::new("Facebook")) - .option(SelectOption::new("Twitter")); + .option(SelectOption::new(GOOGLE)) + .option(SelectOption::new(FACEBOOK)) + .option(SelectOption::new(TWITTER)); let multi_select_field = FieldBuilder::new(multi_select) .name("Platform") .visibility(true) diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs index 1dffa6c0c6..b0cc2b7bb0 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -45,6 +45,10 @@ impl GridBuilder { self.add_row(row); } + // pub fn field_revs(&self) -> Vec { + // self.build_context.field_revs + // } + pub fn build(self) -> BuildGridContext { self.build_context } From ab80e9b0ed8ddb51cfc26f42a682e3be1e9eba09 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 14 Jul 2022 09:29:05 +0800 Subject: [PATCH 016/112] chore: add 5 rows in test grid --- .../type_options/checkbox_type_option/mod.rs | 1 + .../type_options/date_type_option/mod.rs | 1 + .../type_options/text_type_option/mod.rs | 1 + .../field/type_options/url_type_option/mod.rs | 1 + .../flowy-grid/src/services/grid_editor.rs | 8 +- .../src/services/row/row_builder.rs | 9 +- .../tests/grid/block_test/row_test.rs | 17 ++-- .../tests/grid/block_test/script.rs | 22 +---- .../flowy-grid/tests/grid/block_test/util.rs | 16 +-- .../flowy-grid/tests/grid/grid_editor.rs | 98 +++++++++++++++---- .../src/revision/grid_rev.rs | 4 +- .../src/client_grid/grid_builder.rs | 14 ++- 12 files changed, 124 insertions(+), 68 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs index 61013fac08..ebe5d1a6a8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/mod.rs @@ -1,3 +1,4 @@ +#![allow(clippy::module_inception)] mod checkbox_tests; mod checkbox_type_option; mod checkbox_type_option_entities; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs index 8ca49fdd15..395f2c9104 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/mod.rs @@ -1,3 +1,4 @@ +#![allow(clippy::module_inception)] mod date_tests; mod date_type_option; mod date_type_option_entities; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs index 3c1d2287cd..c7e518f103 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/mod.rs @@ -1,2 +1,3 @@ +#![allow(clippy::module_inception)] mod text_type_option; pub use text_type_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs index e3b2ae16bd..8f6cb884df 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/mod.rs @@ -1,3 +1,4 @@ +#![allow(clippy::module_inception)] mod url_tests; mod url_type_option; mod url_type_option_entities; 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 70804f1404..413f4812de 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -270,14 +270,10 @@ impl GridRevisionEditor { pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { let field_revs = self.grid_pad.read().await.get_field_revs(None)?; - let field_revs_ref = field_revs - .iter() - .map(|field_rev| field_rev.as_ref()) - .collect::>(); let block_id = self.block_id().await?; // insert empty row below the row whose id is upper_row_id - let row_rev = RowRevisionBuilder::new(&field_revs_ref).build(&block_id); + let row_rev = RowRevisionBuilder::new(&field_revs).build(&block_id); let row_order = RowInfo::from(&row_rev); // insert the row @@ -556,7 +552,7 @@ impl GridRevisionEditor { drop(grid_pad); Ok(BuildGridContext { - field_revs: duplicated_fields, + field_revs: duplicated_fields.into_iter().map(Arc::new).collect(), blocks: duplicated_blocks, blocks_meta_data, }) diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs index 6ccb553fc1..43153f1311 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs @@ -4,18 +4,19 @@ use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{gen_row_id, CellRevision, FieldRevision, RowRevision, DEFAULT_ROW_HEIGHT}; use indexmap::IndexMap; use std::collections::HashMap; +use std::sync::Arc; pub struct RowRevisionBuilder<'a> { - field_rev_map: HashMap<&'a String, &'a FieldRevision>, + field_rev_map: HashMap<&'a String, Arc>, payload: CreateRowRevisionPayload, } impl<'a> RowRevisionBuilder<'a> { - pub fn new(fields: &'a [&'a FieldRevision]) -> Self { + pub fn new(fields: &'a [Arc]) -> Self { let field_rev_map = fields .iter() - .map(|field| (&field.id, *field)) - .collect::>(); + .map(|field| (&field.id, field.clone())) + .collect::>>(); let payload = CreateRowRevisionPayload { row_id: gen_row_id(), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index 02e7ccc050..6dafb2973f 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -79,8 +79,8 @@ async fn grid_row_add_cells_test() { |options| options, &vec![GOOGLE, FACEBOOK, TWITTER].join(SELECTION_IDS_SEPARATOR), ); - - test.run_scripts(builder.build()).await; + let scripts = builder.build(); + test.run_scripts(scripts).await; } #[tokio::test] @@ -89,7 +89,8 @@ async fn grid_row_insert_number_test() { for (val, expected) in &[("1647251762", "2022/03/14"), ("2022/03/14", ""), ("", "")] { let mut builder = CreateRowScriptBuilder::new(&test); builder.insert(FieldType::DateTime, val, expected); - test.run_scripts(builder.build()).await; + let scripts = builder.build(); + test.run_scripts(scripts).await; } } @@ -105,7 +106,8 @@ async fn grid_row_insert_date_test() { ] { let mut builder = CreateRowScriptBuilder::new(&test); builder.insert(FieldType::Number, val, expected); - test.run_scripts(builder.build()).await; + let scripts = builder.build(); + test.run_scripts(scripts).await; } } #[tokio::test] @@ -113,7 +115,8 @@ async fn grid_row_insert_single_select_test() { let mut test = GridRowTest::new().await; let mut builder = CreateRowScriptBuilder::new(&test); builder.insert_single_select_cell(|mut options| options.pop().unwrap(), PAUSED); - test.run_scripts(builder.build()).await; + let scripts = builder.build(); + test.run_scripts(scripts).await; } #[tokio::test] @@ -127,6 +130,6 @@ async fn grid_row_insert_multi_select_test() { }, &vec![FACEBOOK, TWITTER].join(SELECTION_IDS_SEPARATOR), ); - - test.run_scripts(builder.build()).await; + let scripts = builder.build(); + test.run_scripts(scripts).await; } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 366d1e6c80..015dcfee88 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -2,13 +2,9 @@ use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow}; use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; use flowy_grid::entities::{CellIdentifier, FieldType, RowInfo}; -use flowy_grid::services::field::{ - CheckboxCellDataParser, DateCellDataParser, MultiSelectTypeOption, NumberCellDataParser, NumberTypeOption, - SelectOption, SelectOptionCellDataParser, SelectOptionIdsParser, SingleSelectTypeOption, TextCellDataParser, - URLCellDataParser, SELECTION_IDS_SEPARATOR, -}; +use flowy_grid::services::field::*; use flowy_grid_data_model::revision::{ - FieldRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, + GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, }; use std::collections::HashMap; use std::sync::Arc; @@ -74,19 +70,7 @@ impl GridRowTest { } pub fn row_builder(&self) -> GridRowTestBuilder { - let field_revs_ref = self - .field_revs - .iter() - .map(|field_rev| field_rev.as_ref()) - .collect::>(); - GridRowTestBuilder::new( - self.block_id(), - &self - .field_revs - .iter() - .map(|field_rev| field_rev.as_ref()) - .collect::>(), - ) + GridRowTestBuilder::new(self.block_id(), &self.field_revs) } pub async fn run_script(&mut self, script: RowScript) { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs index ca1e45465e..7aade54a08 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs @@ -1,4 +1,5 @@ use flowy_grid::entities::FieldType; +use std::sync::Arc; use flowy_grid::services::field::{ DateCellChangeset, MultiSelectTypeOption, SelectOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, @@ -10,12 +11,12 @@ use strum::EnumCount; pub struct GridRowTestBuilder<'a> { block_id: String, - field_revs: &'a [&'a FieldRevision], + field_revs: &'a [Arc], inner_builder: RowRevisionBuilder<'a>, } impl<'a> GridRowTestBuilder<'a> { - pub fn new(block_id: &str, field_revs: &'a [&'a FieldRevision]) -> Self { + pub fn new(block_id: &str, field_revs: &'a [Arc]) -> Self { assert_eq!(field_revs.len(), FieldType::COUNT); let inner_builder = RowRevisionBuilder::new(field_revs); Self { @@ -68,16 +69,15 @@ impl<'a> GridRowTestBuilder<'a> { url_field.id.clone() } - #[allow(dead_code)] pub fn insert_single_select_cell(&mut self, f: F) -> String where - F: Fn(&Vec) -> &SelectOption, + F: Fn(Vec) -> SelectOption, { let single_select_field = self.field_rev_with_type(&FieldType::SingleSelect); let type_option = SingleSelectTypeOption::from(&single_select_field); - let option = f(&type_option.options); + let option = f(type_option.options); self.inner_builder - .insert_select_option_cell(&single_select_field.id, option.id.clone()) + .insert_select_option_cell(&single_select_field.id, option.id) .unwrap(); single_select_field.id.clone() @@ -85,11 +85,11 @@ impl<'a> GridRowTestBuilder<'a> { pub fn insert_multi_select_cell(&mut self, f: F) -> String where - F: Fn(&Vec) -> &Vec, + F: Fn(Vec) -> Vec, { let multi_select_field = self.field_rev_with_type(&FieldType::MultiSelect); let type_option = MultiSelectTypeOption::from(&multi_select_field); - let options = f(&type_option.options); + let options = f(type_option.options); let ops_ids = options .iter() .map(|option| option.id.clone()) diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index 8d6a2043d0..2070bd6fce 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -1,6 +1,7 @@ #![allow(clippy::all)] #![allow(dead_code)] #![allow(unused_imports)] +use crate::grid::block_test::util::GridRowTestBuilder; use bytes::Bytes; use flowy_grid::entities::*; use flowy_grid::services::field::SelectOption; @@ -158,7 +159,7 @@ fn make_test_grid() -> BuildGridContext { FieldType::Checkbox => { // Checkbox let checkbox = CheckboxTypeOptionBuilder::default(); - let checkbox_field = FieldBuilder::new(checkbox).name("is done").visibility(true).build(); + let checkbox_field = FieldBuilder::new(checkbox).name("is urgent").visibility(true).build(); grid_builder.add_field(checkbox_field); } FieldType::URL => { @@ -171,24 +172,87 @@ fn make_test_grid() -> BuildGridContext { } // We have many assumptions base on the number of the rows, so do not change the number of the loop. - for _i in 0..10 { - for field_type in FieldType::iter() { - let field_type: FieldType = field_type; - // let mut row_builder = RowRevisionBuilder::new() - match field_type { - FieldType::RichText => {} - FieldType::Number => {} - FieldType::DateTime => {} - FieldType::SingleSelect => {} - FieldType::MultiSelect => {} - FieldType::Checkbox => {} - FieldType::URL => {} + for i in 0..5 { + let block_id = grid_builder.block_id().to_owned(); + let field_revs = grid_builder.field_revs(); + let mut row_builder = GridRowTestBuilder::new(&block_id, field_revs); + match i { + 0 => { + for field_type in FieldType::iter() { + match field_type { + FieldType::RichText => row_builder.insert_text_cell("A"), + FieldType::Number => row_builder.insert_number_cell("1"), + FieldType::DateTime => row_builder.insert_date_cell("1647251762"), + FieldType::SingleSelect => { + row_builder.insert_single_select_cell(|mut options| options.remove(0)) + } + FieldType::Checkbox => row_builder.insert_checkbox_cell("true"), + _ => "".to_owned(), + }; + } } + 1 => { + for field_type in FieldType::iter() { + match field_type { + FieldType::RichText => row_builder.insert_text_cell("B"), + FieldType::Number => row_builder.insert_number_cell("2"), + FieldType::DateTime => row_builder.insert_date_cell("1647251762"), + FieldType::SingleSelect => { + row_builder.insert_single_select_cell(|mut options| options.remove(0)) + } + FieldType::Checkbox => row_builder.insert_checkbox_cell("true"), + _ => "".to_owned(), + }; + } + } + 2 => { + for field_type in FieldType::iter() { + match field_type { + FieldType::RichText => row_builder.insert_text_cell("C"), + FieldType::Number => row_builder.insert_number_cell("3"), + FieldType::DateTime => row_builder.insert_date_cell("1647251762"), + FieldType::SingleSelect => { + row_builder.insert_single_select_cell(|mut options| options.remove(1)) + } + FieldType::Checkbox => row_builder.insert_checkbox_cell("false"), + _ => "".to_owned(), + }; + } + } + 3 => { + for field_type in FieldType::iter() { + match field_type { + FieldType::RichText => row_builder.insert_text_cell("D"), + FieldType::Number => row_builder.insert_number_cell("4"), + FieldType::DateTime => row_builder.insert_date_cell("1647251762"), + FieldType::SingleSelect => { + row_builder.insert_single_select_cell(|mut options| options.remove(1)) + } + FieldType::Checkbox => row_builder.insert_checkbox_cell("false"), + _ => "".to_owned(), + }; + } + } + 4 => { + for field_type in FieldType::iter() { + match field_type { + FieldType::RichText => row_builder.insert_text_cell("E"), + FieldType::Number => row_builder.insert_number_cell("5"), + FieldType::DateTime => row_builder.insert_date_cell("1647251762"), + FieldType::SingleSelect => { + row_builder.insert_single_select_cell(|mut options| options.remove(2)) + } + + FieldType::Checkbox => row_builder.insert_checkbox_cell("false"), + _ => "".to_owned(), + }; + } + } + _ => {} } + + let row_rev = row_builder.build(); + grid_builder.add_row(row_rev); } - // assert_eq!(row_revs.len(), 10); - // .add_empty_row() - // .add_empty_row() - // .add_empty_row() grid_builder.build() } 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 edceb25d9c..671f71563f 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 @@ -53,7 +53,7 @@ impl GridRevision { pub fn from_build_context(grid_id: &str, context: BuildGridContext) -> Self { Self { grid_id: grid_id.to_owned(), - fields: context.field_revs.into_iter().map(Arc::new).collect(), + fields: context.field_revs, blocks: context.blocks.into_iter().map(Arc::new).collect(), setting: Default::default(), } @@ -245,7 +245,7 @@ impl CellRevision { #[derive(Clone, Default, Deserialize, Serialize)] pub struct BuildGridContext { - pub field_revs: Vec, + pub field_revs: Vec>, pub blocks: Vec, pub blocks_meta_data: Vec, } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs index b0cc2b7bb0..ea5d5a9332 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_builder.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_builder.rs @@ -30,7 +30,7 @@ impl GridBuilder { Self::default() } pub fn add_field(&mut self, field: FieldRevision) { - self.build_context.field_revs.push(field); + self.build_context.field_revs.push(Arc::new(field)); } pub fn add_row(&mut self, row_rev: RowRevision) { @@ -41,13 +41,17 @@ impl GridBuilder { } pub fn add_empty_row(&mut self) { - let row = RowRevision::new(&self.build_context.blocks.first().unwrap().block_id); + let row = RowRevision::new(self.block_id()); self.add_row(row); } - // pub fn field_revs(&self) -> Vec { - // self.build_context.field_revs - // } + pub fn field_revs(&self) -> &Vec> { + &self.build_context.field_revs + } + + pub fn block_id(&self) -> &str { + &self.build_context.blocks.first().unwrap().block_id + } pub fn build(self) -> BuildGridContext { self.build_context From 3844d6aad1c95829f08f1e29db79886e35932cb0 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 14 Jul 2022 20:07:47 +0800 Subject: [PATCH 017/112] refactor: add documentation to GridCellContext --- .../application/grid/block/block_service.dart | 6 +- .../grid/cell/cell_service/cache.dart | 60 ++------- .../cell/cell_service/cell_data_loader.dart | 33 ----- .../cell_service/cell_data_persistence.dart | 6 +- .../cell_service/cell_field_notifier.dart | 56 ++++++++ .../grid/cell/cell_service/cell_service.dart | 1 - .../cell/cell_service/context_builder.dart | 126 ++++++++++++------ .../workspace/application/grid/grid_bloc.dart | 2 +- .../application/grid/grid_service.dart | 2 +- .../application/grid/row/row_bloc.dart | 4 +- .../application/grid/row/row_detail_bloc.dart | 4 +- .../application/grid/row/row_service.dart | 17 +-- .../grid/src/widgets/cell/cell_builder.dart | 51 ++++++- .../grid/src/widgets/row/grid_row.dart | 32 +++-- .../grid/src/widgets/row/row_detail.dart | 18 +-- 15 files changed, 254 insertions(+), 164 deletions(-) create mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart 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 index 3fb734db70..a531e65d2e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart @@ -9,18 +9,18 @@ import 'block_listener.dart'; class GridBlockCacheService { final String gridId; final GridBlock block; - late GridRowCacheService _rowCache; + late GridRowsCache _rowCache; late GridBlockListener _listener; List get rows => _rowCache.rows; - GridRowCacheService get rowCache => _rowCache; + GridRowsCache get rowCache => _rowCache; GridBlockCacheService({ required this.gridId, required this.block, required GridFieldCache fieldCache, }) { - _rowCache = GridRowCacheService( + _rowCache = GridRowsCache( gridId: gridId, block: block, delegate: GridRowCacheDelegateImpl(fieldCache), diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart index ccf47fddb3..e10c73c7bb 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart @@ -3,7 +3,7 @@ part of 'cell_service.dart'; typedef GridCellMap = LinkedHashMap; class _GridCellCacheObject { - _GridCellCacheKey key; + GridCellCacheKey key; dynamic object; _GridCellCacheObject({ required this.key, @@ -11,67 +11,26 @@ class _GridCellCacheObject { }); } -class _GridCellCacheKey { +class GridCellCacheKey { final String fieldId; final String rowId; - _GridCellCacheKey({ + GridCellCacheKey({ required this.fieldId, required this.rowId, }); } -abstract class GridCellCacheDelegate { - void onFieldUpdated(void Function(Field) callback); -} - -class GridCellCacheService { +class GridCellsCache { final String gridId; - final GridCellCacheDelegate delegate; - - /// fieldId: {objectId: callback} - final Map>> _fieldListenerByFieldId = {}; /// fieldId: {cacheKey: cacheData} final Map> _cellDataByFieldId = {}; - GridCellCacheService({ + GridCellsCache({ required this.gridId, - required this.delegate, - }) { - delegate.onFieldUpdated((field) { - _cellDataByFieldId.remove(field.id); - final map = _fieldListenerByFieldId[field.id]; - if (map != null) { - for (final callbacks in map.values) { - for (final callback in callbacks) { - callback(); - } - } - } - }); - } + }); - void addFieldListener(_GridCellCacheKey cacheKey, VoidCallback onFieldChanged) { - var map = _fieldListenerByFieldId[cacheKey.fieldId]; - if (map == null) { - _fieldListenerByFieldId[cacheKey.fieldId] = {}; - map = _fieldListenerByFieldId[cacheKey.fieldId]; - map![cacheKey.rowId] = [onFieldChanged]; - } else { - var objects = map[cacheKey.rowId]; - if (objects == null) { - map[cacheKey.rowId] = [onFieldChanged]; - } else { - objects.add(onFieldChanged); - } - } - } - - 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 remove(String fieldId) { + _cellDataByFieldId.remove(fieldId); } void insert(T item) { @@ -84,7 +43,7 @@ class GridCellCacheService { map![item.key.rowId] = item.object; } - T? get(_GridCellCacheKey key) { + T? get(GridCellCacheKey key) { final map = _cellDataByFieldId[key.fieldId]; if (map == null) { return null; @@ -103,7 +62,6 @@ class GridCellCacheService { } Future dispose() async { - _fieldListenerByFieldId.clear(); _cellDataByFieldId.clear(); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart index 676e3f66d0..95b7b77b61 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart @@ -3,23 +3,13 @@ part of 'cell_service.dart'; abstract class IGridCellDataConfig { // The cell data will reload if it receives the field's change notification. bool get reloadOnFieldChanged; - - // When the reloadOnCellChanged is true, it will load the cell data after user input. - // For example: The number cell reload the cell data that carries the format - // user input: 12 - // cell display: $12 - bool get reloadOnCellChanged; } class GridCellDataConfig implements IGridCellDataConfig { - @override - final bool reloadOnCellChanged; - @override final bool reloadOnFieldChanged; const GridCellDataConfig({ - this.reloadOnCellChanged = false, this.reloadOnFieldChanged = false, }); } @@ -72,29 +62,6 @@ class GridCellDataLoader extends IGridCellDataLoader { } } -class SelectOptionCellDataLoader extends IGridCellDataLoader { - final SelectOptionService service; - final GridCell gridCell; - SelectOptionCellDataLoader({ - required this.gridCell, - }) : service = SelectOptionService(gridCell: gridCell); - @override - Future loadData() async { - return service.getOpitonContext().then((result) { - return result.fold( - (data) => data, - (err) { - Log.error(err); - return null; - }, - ); - }); - } - - @override - IGridCellDataConfig get config => const GridCellDataConfig(reloadOnFieldChanged: true); -} - class StringCellDataParser implements ICellDataParser { @override String? parserData(List data) { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart index 2ad217e062..9e2f577d7c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart @@ -1,10 +1,10 @@ part of 'cell_service.dart'; -abstract class _GridCellDataPersistence { +abstract class IGridCellDataPersistence { Future> save(D data); } -class CellDataPersistence implements _GridCellDataPersistence { +class CellDataPersistence implements IGridCellDataPersistence { final GridCell gridCell; CellDataPersistence({ @@ -35,7 +35,7 @@ class CalendarData with _$CalendarData { const factory CalendarData({required DateTime date, String? time}) = _CalendarData; } -class DateCellDataPersistence implements _GridCellDataPersistence { +class DateCellDataPersistence implements IGridCellDataPersistence { final GridCell gridCell; DateCellDataPersistence({ required this.gridCell, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart new file mode 100644 index 0000000000..18dae774d7 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart @@ -0,0 +1,56 @@ +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flutter/foundation.dart'; + +import 'cell_service.dart'; + +abstract class GridFieldChangedNotifier { + void onFieldChanged(void Function(Field) callback); +} + +class GridCellFieldNotifier { + /// fieldId: {objectId: callback} + final Map>> _fieldListenerByFieldId = {}; + + GridCellFieldNotifier({required GridFieldChangedNotifier notifier}) { + notifier.onFieldChanged( + (field) { + final map = _fieldListenerByFieldId[field.id]; + if (map != null) { + for (final callbacks in map.values) { + for (final callback in callbacks) { + callback(); + } + } + } + }, + ); + } + + void addFieldListener(GridCellCacheKey cacheKey, VoidCallback onFieldChanged) { + var map = _fieldListenerByFieldId[cacheKey.fieldId]; + if (map == null) { + _fieldListenerByFieldId[cacheKey.fieldId] = {}; + map = _fieldListenerByFieldId[cacheKey.fieldId]; + map![cacheKey.rowId] = [onFieldChanged]; + } else { + var objects = map[cacheKey.rowId]; + if (objects == null) { + map[cacheKey.rowId] = [onFieldChanged]; + } else { + objects.add(onFieldChanged); + } + } + } + + 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); + } + } + + Future dispose() async { + _fieldListenerByFieldId.clear(); + } +} 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 5e406c0c26..02561f80f8 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 @@ -14,7 +14,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; -import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'dart:convert' show utf8; part 'cell_service.freezed.dart'; 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 00264ad4b0..2ff3e60c3e 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 @@ -6,15 +6,19 @@ typedef GridDateCellContext = _GridCellContext; typedef GridURLCellContext = _GridCellContext; class GridCellContextBuilder { - final GridCellCacheService _cellCache; final GridCell _gridCell; - GridCellContextBuilder({ - required GridCellCacheService cellCache, - required GridCell gridCell, - }) : _cellCache = cellCache, + final GridCellsCache _cellCache; + final GridFieldCache _fieldCache; + + GridCellContextBuilder( + {required GridCell gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache}) + : _cellCache = cellCache, + _fieldCache = fieldCache, _gridCell = gridCell; _GridCellContext build() { + final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache)); + switch (_gridCell.field.fieldType) { case FieldType.Checkbox: final cellDataLoader = GridCellDataLoader( @@ -25,6 +29,7 @@ class GridCellContextBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, + cellFieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); case FieldType.DateTime: @@ -38,18 +43,20 @@ class GridCellContextBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, + cellFieldNotifier: cellFieldNotifier, cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell), ); case FieldType.Number: final cellDataLoader = GridCellDataLoader( gridCell: _gridCell, parser: StringCellDataParser(), - config: const GridCellDataConfig(reloadOnCellChanged: true, reloadOnFieldChanged: true), + config: const GridCellDataConfig(reloadOnFieldChanged: true), ); return GridCellContext( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, + cellFieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); case FieldType.RichText: @@ -61,6 +68,7 @@ class GridCellContextBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, + cellFieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); case FieldType.MultiSelect: @@ -75,6 +83,7 @@ class GridCellContextBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, + cellFieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); @@ -87,6 +96,7 @@ class GridCellContextBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, + cellFieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); } @@ -99,14 +109,17 @@ class GridCellContextBuilder { // ignore: must_be_immutable class _GridCellContext extends Equatable { final GridCell gridCell; - final GridCellCacheService cellCache; - final _GridCellCacheKey _cacheKey; - final IGridCellDataLoader cellDataLoader; - final _GridCellDataPersistence cellDataPersistence; + final GridCellsCache _cellsCache; + final GridCellCacheKey _cacheKey; final FieldService _fieldService; + final GridCellFieldNotifier _cellFieldNotifier; + // final GridCellFieldNotifier _fieldNotifier; + final IGridCellDataLoader _cellDataLoader; + final IGridCellDataPersistence _cellDataPersistence; late final CellListener _cellListener; late final ValueNotifier? _cellDataNotifier; + bool isListening = false; VoidCallback? _onFieldChangedFn; Timer? _loadDataOperation; @@ -114,18 +127,25 @@ class _GridCellContext extends Equatable { _GridCellContext({ required this.gridCell, - required this.cellCache, - required this.cellDataLoader, - required this.cellDataPersistence, - }) : _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), - _cacheKey = _GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id); + required GridCellsCache cellCache, + required GridCellFieldNotifier cellFieldNotifier, + required IGridCellDataLoader cellDataLoader, + required IGridCellDataPersistence cellDataPersistence, + // required GridFieldChangedNotifier notifierDelegate, + }) : _cellsCache = cellCache, + _cellDataLoader = cellDataLoader, + _cellDataPersistence = cellDataPersistence, + _cellFieldNotifier = cellFieldNotifier, + _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), + _cacheKey = GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id); _GridCellContext clone() { return _GridCellContext( gridCell: gridCell, - cellDataLoader: cellDataLoader, - cellCache: cellCache, - cellDataPersistence: cellDataPersistence); + cellDataLoader: _cellDataLoader, + cellCache: _cellsCache, + cellFieldNotifier: _cellFieldNotifier, + cellDataPersistence: _cellDataPersistence); } String get gridId => gridCell.gridId; @@ -145,10 +165,18 @@ class _GridCellContext extends Equatable { Log.error("Already started. It seems like you should call clone first"); return null; } - isListening = true; - _cellDataNotifier = ValueNotifier(cellCache.get(_cacheKey)); + + /// The cell data will be changed by two reasons: + /// 1. User edit the cell + /// 2. User edit the field + /// For example: The number cell reload the cell data that carries the format + /// user input: 12 + /// cell display: $12 + _cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey)); _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); + + /// Listen on user edit event and load the new cell data if needed. _cellListener.start(onCellChanged: (result) { result.fold( (_) => _loadData(), @@ -156,21 +184,14 @@ class _GridCellContext extends Equatable { ); }); - if (cellDataLoader.config.reloadOnFieldChanged) { - _onFieldChangedFn = () { - _loadData(); - }; - cellCache.addFieldListener(_cacheKey, _onFieldChangedFn!); - } - - onCellChangedFn() { - onCellChanged(_cellDataNotifier?.value); - - if (cellDataLoader.config.reloadOnCellChanged) { - _loadData(); - } + /// Listen on the field event and load the cell data if needed. + if (_cellDataLoader.config.reloadOnFieldChanged) { + _onFieldChangedFn = () => _loadData(); + _cellFieldNotifier.addFieldListener(_cacheKey, _onFieldChangedFn!); } + /// Notify the listener, the cell data was changed. + onCellChangedFn() => onCellChanged(_cellDataNotifier?.value); _cellDataNotifier?.addListener(onCellChangedFn); return onCellChangedFn; } @@ -180,7 +201,7 @@ class _GridCellContext extends Equatable { } T? getCellData({bool loadIfNoCache = true}) { - final data = cellCache.get(_cacheKey); + final data = _cellsCache.get(_cacheKey); if (data == null && loadIfNoCache) { _loadData(); } @@ -195,13 +216,13 @@ class _GridCellContext extends Equatable { if (deduplicate) { _loadDataOperation?.cancel(); _loadDataOperation = Timer(const Duration(milliseconds: 300), () async { - final result = await cellDataPersistence.save(data); + final result = await _cellDataPersistence.save(data); if (resultCallback != null) { resultCallback(result); } }); } else { - final result = await cellDataPersistence.save(data); + final result = await _cellDataPersistence.save(data); if (resultCallback != null) { resultCallback(result); } @@ -211,9 +232,9 @@ class _GridCellContext extends Equatable { void _loadData() { _loadDataOperation?.cancel(); _loadDataOperation = Timer(const Duration(milliseconds: 10), () { - cellDataLoader.loadData().then((data) { + _cellDataLoader.loadData().then((data) { _cellDataNotifier?.value = data; - cellCache.insert(_GridCellCacheObject(key: _cacheKey, object: data)); + _cellsCache.insert(_GridCellCacheObject(key: _cacheKey, object: data)); }); }); } @@ -224,11 +245,36 @@ class _GridCellContext extends Equatable { _saveDataOperation?.cancel(); if (_onFieldChangedFn != null) { - cellCache.removeFieldListener(_cacheKey, _onFieldChangedFn!); + _cellFieldNotifier.removeFieldListener(_cacheKey, _onFieldChangedFn!); _onFieldChangedFn = null; } } @override - List get props => [cellCache.get(_cacheKey) ?? "", cellId]; + List get props => [_cellsCache.get(_cacheKey) ?? "", cellId]; +} + +class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier { + final GridFieldCache _cache; + FieldChangesetCallback? _onChangesetFn; + + _GridFieldChangedNotifierImpl(GridFieldCache cache) : _cache = cache; + + @override + void dispose() { + if (_onChangesetFn != null) { + _cache.removeListener(onChangsetListener: _onChangesetFn!); + _onChangesetFn = null; + } + } + + @override + void onFieldChanged(void Function(Field p1) callback) { + _onChangesetFn = (GridFieldChangeset changeset) { + for (final updatedField in changeset.updatedFields) { + callback(updatedField); + } + }; + _cache.addListener(onChangeset: _onChangesetFn); + } } 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 49e90b6a9e..e6fff41317 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -68,7 +68,7 @@ class GridBloc extends Bloc { return super.close(); } - GridRowCacheService? getRowCache(String blockId, String rowId) { + GridRowsCache? getRowCache(String blockId, String rowId) { final GridBlockCacheService? blockCache = _blocks[blockId]; return blockCache?.rowCache; } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index 391a5d13a2..3e9cbc2eee 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -202,7 +202,7 @@ class GridRowCacheDelegateImpl extends GridRowCacheDelegate { } @override - void onFieldUpdated(void Function(Field) callback) { + void onFieldChanged(void Function(Field) callback) { _onChangesetFn = (GridFieldChangeset changeset) { for (final updatedField in changeset.updatedFields) { callback(updatedField); diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 7f565b500a..5af7c02a5d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart @@ -11,12 +11,12 @@ part 'row_bloc.freezed.dart'; class RowBloc extends Bloc { final RowService _rowService; - final GridRowCacheService _rowCache; + final GridRowsCache _rowCache; void Function()? _rowListenFn; RowBloc({ required GridRow rowData, - required GridRowCacheService rowCache, + required GridRowsCache rowCache, }) : _rowService = RowService( gridId: rowData.gridId, blockId: rowData.blockId, diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart index f17f0f4cb6..0613b388a4 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart @@ -8,12 +8,12 @@ part 'row_detail_bloc.freezed.dart'; class RowDetailBloc extends Bloc { final GridRow rowData; - final GridRowCacheService _rowCache; + final GridRowsCache _rowCache; void Function()? _rowListenFn; RowDetailBloc({ required this.rowData, - required GridRowCacheService rowCache, + required GridRowsCache rowCache, }) : _rowCache = rowCache, super(RowDetailState.initial()) { on( 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 78e4e6715f..27749083b4 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 @@ -1,5 +1,4 @@ import 'dart:collection'; - import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; @@ -15,34 +14,36 @@ part 'row_service.freezed.dart'; typedef RowUpdateCallback = void Function(); -abstract class GridRowCacheDelegate with GridCellCacheDelegate { +abstract class GridRowCacheDelegate { UnmodifiableListView get fields; - void onFieldsChanged(void Function() callback); + void onFieldsChanged(VoidCallback callback); + void onFieldChanged(void Function(Field) callback); void dispose(); } -class GridRowCacheService { +class GridRowsCache { final String gridId; final GridBlock block; final _Notifier _notifier; List _rows = []; final HashMap _rowByRowId; final GridRowCacheDelegate _delegate; - final GridCellCacheService _cellCache; + final GridCellsCache _cellCache; List get rows => _rows; - GridCellCacheService get cellCache => _cellCache; + GridCellsCache get cellCache => _cellCache; - GridRowCacheService({ + GridRowsCache({ required this.gridId, required this.block, required GridRowCacheDelegate delegate, - }) : _cellCache = GridCellCacheService(gridId: gridId, delegate: delegate), + }) : _cellCache = GridCellsCache(gridId: gridId), _rowByRowId = HashMap(), _notifier = _Notifier(), _delegate = delegate { // delegate.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange())); + delegate.onFieldChanged((field) => _cellCache.remove(field.id)); _rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index 9f3c7a632e..0267ed74b4 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -1,4 +1,5 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; @@ -12,10 +13,56 @@ import 'select_option_cell/select_option_cell.dart'; import 'text_cell.dart'; import 'url_cell/url_cell.dart'; -GridCellWidget buildGridCellWidget(GridCell gridCell, GridCellCacheService cellCache, {GridCellStyle? style}) { +class GridCellBuilder { + final GridCellsCache cellCache; + final GridFieldCache fieldCache; + GridCellBuilder({ + required this.cellCache, + required this.fieldCache, + }); + + GridCellWidget build(GridCell cell, {GridCellStyle? style}) { + final key = ValueKey(gridCell.cellId()); + + final cellContextBuilder = GridCellContextBuilder( + gridCell: gridCell, + cellCache: cellCache, + fieldCache: fieldCache, + ); + + switch (gridCell.field.fieldType) { + case FieldType.Checkbox: + return CheckboxCell(cellContextBuilder: cellContextBuilder, key: key); + case FieldType.DateTime: + return DateCell(cellContextBuilder: cellContextBuilder, key: key, style: style); + case FieldType.SingleSelect: + return SingleSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key); + case FieldType.MultiSelect: + return MultiSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key); + case FieldType.Number: + return NumberCell(cellContextBuilder: cellContextBuilder, key: key); + case FieldType.RichText: + return GridTextCell(cellContextBuilder: cellContextBuilder, style: style, key: key); + case FieldType.URL: + return GridURLCell(cellContextBuilder: cellContextBuilder, style: style, key: key); + } + throw UnimplementedError; + } +} + +GridCellWidget buildGridCellWidget( + GridCell gridCell, { + required GridCellsCache cellCache, + required GridFieldCache fieldCache, + GridCellStyle? style, +}) { final key = ValueKey(gridCell.cellId()); - final cellContextBuilder = GridCellContextBuilder(gridCell: gridCell, cellCache: cellCache); + final cellContextBuilder = GridCellContextBuilder( + gridCell: gridCell, + cellCache: cellCache, + fieldCache: fieldCache, + ); switch (gridCell.field.fieldType) { case FieldType.Checkbox: diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart index de7f117d51..0e1c6a0041 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart @@ -10,19 +10,25 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:provider/provider.dart'; -import 'row_action_sheet.dart'; +import 'row_action_sheet.dart'; import 'row_detail.dart'; class GridRowWidget extends StatefulWidget { final GridRow rowData; - final GridRowCacheService rowCache; + final GridRowsCache rowCache; + final GridCellBuilder cellBuilder; - const GridRowWidget({ + GridRowWidget({ required this.rowData, required this.rowCache, + required GridFieldCache fieldCache, Key? key, - }) : super(key: key); + }) : cellBuilder = GridCellBuilder( + cellCache: rowCache.cellCache, + fieldCache: fieldCache, + ), + super(key: key); @override State createState() => _GridRowWidgetState(); @@ -52,7 +58,11 @@ class _GridRowWidgetState extends State { return Row( children: [ const _RowLeading(), - Expanded(child: _RowCells(cellCache: widget.rowCache.cellCache, onExpand: () => _expandRow(context))), + Expanded( + child: _RowCells( + builder: widget.cellBuilder, + onExpand: () => _expandRow(context), + )), const _RowTrailing(), ], ); @@ -72,6 +82,7 @@ class _GridRowWidgetState extends State { final page = RowDetailPage( rowData: widget.rowData, rowCache: widget.rowCache, + cellBuilder: widget.cellBuilder, ); page.show(context); } @@ -146,9 +157,13 @@ class _DeleteRowButton extends StatelessWidget { } class _RowCells extends StatelessWidget { - final GridCellCacheService cellCache; final VoidCallback onExpand; - const _RowCells({required this.cellCache, required this.onExpand, Key? key}) : super(key: key); + final GridCellBuilder builder; + const _RowCells({ + required this.builder, + required this.onExpand, + Key? key, + }) : super(key: key); @override Widget build(BuildContext context) { @@ -169,8 +184,7 @@ class _RowCells extends StatelessWidget { List _makeCells(BuildContext context, GridCellMap gridCellMap) { return gridCellMap.values.map( (gridCell) { - final GridCellWidget child = buildGridCellWidget(gridCell, cellCache); - + final GridCellWidget child = builder.build(gridCell); accessoryBuilder(GridCellAccessoryBuildContext buildContext) { final builder = child.accessoryBuilder; List accessories = []; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart index c4ccc32a1a..45dd63eb7f 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -22,11 +22,13 @@ import 'package:flutter_bloc/flutter_bloc.dart'; class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate { final GridRow rowData; - final GridRowCacheService rowCache; + final GridRowsCache rowCache; + final GridCellBuilder cellBuilder; const RowDetailPage({ required this.rowData, required this.rowCache, + required this.cellBuilder, Key? key, }) : super(key: key); @@ -74,7 +76,7 @@ class _RowDetailPageState extends State { children: const [Spacer(), _CloseButton()], ), ), - Expanded(child: _PropertyList(cellCache: widget.rowCache.cellCache)), + Expanded(child: _PropertyList(cellBuilder: widget.cellBuilder)), ], ), ), @@ -98,10 +100,10 @@ class _CloseButton extends StatelessWidget { } class _PropertyList extends StatelessWidget { - final GridCellCacheService cellCache; + final GridCellBuilder cellBuilder; final ScrollController _scrollController; _PropertyList({ - required this.cellCache, + required this.cellBuilder, Key? key, }) : _scrollController = ScrollController(), super(key: key); @@ -121,7 +123,7 @@ class _PropertyList extends StatelessWidget { itemBuilder: (BuildContext context, int index) { return _RowDetailCell( gridCell: state.gridCells[index], - cellCache: cellCache, + cellBuilder: cellBuilder, ); }, separatorBuilder: (BuildContext context, int index) { @@ -136,10 +138,10 @@ class _PropertyList extends StatelessWidget { class _RowDetailCell extends StatelessWidget { final GridCell gridCell; - final GridCellCacheService cellCache; + final GridCellBuilder cellBuilder; const _RowDetailCell({ required this.gridCell, - required this.cellCache, + required this.cellBuilder, Key? key, }) : super(key: key); @@ -147,7 +149,7 @@ class _RowDetailCell extends StatelessWidget { Widget build(BuildContext context) { final theme = context.watch(); final style = _customCellStyle(theme, gridCell.field.fieldType); - final cell = buildGridCellWidget(gridCell, cellCache, style: style); + final cell = cellBuilder.build(gridCell, style: style); final gesture = GestureDetector( behavior: HitTestBehavior.translucent, From 8ac75af8752eef599f4120304d8acfadef3702ba Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 14 Jul 2022 20:40:01 +0800 Subject: [PATCH 018/112] refactor: rename GridCellContext to GridCellController --- .../app_flowy/lib/startup/deps_resolver.dart | 10 +-- .../grid/cell/cell_service/cache.dart | 14 ++-- .../cell_service/cell_field_notifier.dart | 5 +- .../grid/cell/cell_service/cell_service.dart | 3 + .../cell/cell_service/context_builder.dart | 72 +++++++++++-------- .../grid/cell/checkbox_cell_bloc.dart | 4 +- .../application/grid/cell/date_cal_bloc.dart | 2 +- .../application/grid/cell/date_cell_bloc.dart | 4 +- .../grid/cell/number_cell_bloc.dart | 4 +- .../grid/cell/select_option_cell_bloc.dart | 4 +- .../grid/cell/select_option_editor_bloc.dart | 37 +++------- .../application/grid/cell/text_cell_bloc.dart | 4 +- .../application/grid/cell/url_cell_bloc.dart | 4 +- .../grid/cell/url_cell_editor_bloc.dart | 4 +- .../plugins/grid/src/grid_page.dart | 2 + .../grid/src/widgets/cell/cell_builder.dart | 55 +++----------- .../grid/src/widgets/cell/checkbox_cell.dart | 6 +- .../src/widgets/cell/date_cell/date_cell.dart | 6 +- .../widgets/cell/date_cell/date_editor.dart | 4 +- .../grid/src/widgets/cell/number_cell.dart | 6 +- .../select_option_cell.dart | 22 +++--- .../select_option_editor.dart | 10 +-- .../grid/src/widgets/cell/text_cell.dart | 6 +- .../widgets/cell/url_cell/cell_editor.dart | 4 +- .../src/widgets/cell/url_cell/url_cell.dart | 16 ++--- 25 files changed, 139 insertions(+), 169 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 0cf248e7e4..bd9c259575 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -153,31 +153,31 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => TextCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => SelectOptionCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => NumberCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => DateCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => CheckboxCellBloc( service: CellService(), cellContext: cellData, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart index e10c73c7bb..a6079bae6d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart @@ -2,19 +2,19 @@ part of 'cell_service.dart'; typedef GridCellMap = LinkedHashMap; -class _GridCellCacheObject { - GridCellCacheKey key; +class _GridCellCacheItem { + GridCellId key; dynamic object; - _GridCellCacheObject({ + _GridCellCacheItem({ required this.key, required this.object, }); } -class GridCellCacheKey { +class GridCellId { final String fieldId; final String rowId; - GridCellCacheKey({ + GridCellId({ required this.fieldId, required this.rowId, }); @@ -33,7 +33,7 @@ class GridCellsCache { _cellDataByFieldId.remove(fieldId); } - void insert(T item) { + void insert(T item) { var map = _cellDataByFieldId[item.key.fieldId]; if (map == null) { _cellDataByFieldId[item.key.fieldId] = {}; @@ -43,7 +43,7 @@ class GridCellsCache { map![item.key.rowId] = item.object; } - T? get(GridCellCacheKey key) { + T? get(GridCellId key) { final map = _cellDataByFieldId[key.fieldId]; if (map == null) { return null; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart index 18dae774d7..1c043e2096 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart @@ -5,6 +5,7 @@ import 'cell_service.dart'; abstract class GridFieldChangedNotifier { void onFieldChanged(void Function(Field) callback); + void dispose(); } class GridCellFieldNotifier { @@ -26,7 +27,7 @@ class GridCellFieldNotifier { ); } - void addFieldListener(GridCellCacheKey cacheKey, VoidCallback onFieldChanged) { + void addFieldListener(GridCellId cacheKey, VoidCallback onFieldChanged) { var map = _fieldListenerByFieldId[cacheKey.fieldId]; if (map == null) { _fieldListenerByFieldId[cacheKey.fieldId] = {}; @@ -42,7 +43,7 @@ class GridCellFieldNotifier { } } - void removeFieldListener(GridCellCacheKey cacheKey, VoidCallback fn) { + void removeFieldListener(GridCellId cacheKey, VoidCallback fn) { var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId]; final index = callbacks?.indexWhere((callback) => callback == fn); if (index != null && index != -1) { 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 02561f80f8..6c7791af92 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 @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:collection'; +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:dartz/dartz.dart'; import 'package:equatable/equatable.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; @@ -16,6 +17,8 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'dart:convert' show utf8; + +import 'cell_field_notifier.dart'; part 'cell_service.freezed.dart'; part 'cell_data_loader.dart'; part 'context_builder.dart'; 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 2ff3e60c3e..f45520c602 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 @@ -1,22 +1,22 @@ part of 'cell_service.dart'; -typedef GridCellContext = _GridCellContext; -typedef GridSelectOptionCellContext = _GridCellContext; -typedef GridDateCellContext = _GridCellContext; -typedef GridURLCellContext = _GridCellContext; +typedef GridCellController = IGridCellController; +typedef GridSelectOptionCellController = IGridCellController; +typedef GridDateCellController = IGridCellController; +typedef GridURLCellController = IGridCellController; -class GridCellContextBuilder { +class GridCellControllerBuilder { final GridCell _gridCell; final GridCellsCache _cellCache; final GridFieldCache _fieldCache; - GridCellContextBuilder( + GridCellControllerBuilder( {required GridCell gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache}) : _cellCache = cellCache, _fieldCache = fieldCache, _gridCell = gridCell; - _GridCellContext build() { + IGridCellController build() { final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache)); switch (_gridCell.field.fieldType) { @@ -25,7 +25,7 @@ class GridCellContextBuilder { gridCell: _gridCell, parser: StringCellDataParser(), ); - return GridCellContext( + return GridCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, @@ -39,7 +39,7 @@ class GridCellContextBuilder { config: const GridCellDataConfig(reloadOnFieldChanged: true), ); - return GridDateCellContext( + return GridDateCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, @@ -52,7 +52,7 @@ class GridCellContextBuilder { parser: StringCellDataParser(), config: const GridCellDataConfig(reloadOnFieldChanged: true), ); - return GridCellContext( + return GridCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, @@ -64,7 +64,7 @@ class GridCellContextBuilder { gridCell: _gridCell, parser: StringCellDataParser(), ); - return GridCellContext( + return GridCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, @@ -79,7 +79,7 @@ class GridCellContextBuilder { config: const GridCellDataConfig(reloadOnFieldChanged: true), ); - return GridSelectOptionCellContext( + return GridSelectOptionCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, @@ -92,7 +92,7 @@ class GridCellContextBuilder { gridCell: _gridCell, parser: URLCellDataParser(), ); - return GridURLCellContext( + return GridURLCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, @@ -105,12 +105,12 @@ class GridCellContextBuilder { } // T: the type of the CellData -// D: the type of the data that will be save to disk +// D: the type of the data that will be saved to disk // ignore: must_be_immutable -class _GridCellContext extends Equatable { +class IGridCellController extends Equatable { final GridCell gridCell; final GridCellsCache _cellsCache; - final GridCellCacheKey _cacheKey; + final GridCellId _cacheKey; final FieldService _fieldService; final GridCellFieldNotifier _cellFieldNotifier; // final GridCellFieldNotifier _fieldNotifier; @@ -118,14 +118,15 @@ class _GridCellContext extends Equatable { final IGridCellDataPersistence _cellDataPersistence; late final CellListener _cellListener; - late final ValueNotifier? _cellDataNotifier; + ValueNotifier? _cellDataNotifier; bool isListening = false; VoidCallback? _onFieldChangedFn; Timer? _loadDataOperation; Timer? _saveDataOperation; + bool isDispose = false; - _GridCellContext({ + IGridCellController({ required this.gridCell, required GridCellsCache cellCache, required GridCellFieldNotifier cellFieldNotifier, @@ -137,10 +138,10 @@ class _GridCellContext extends Equatable { _cellDataPersistence = cellDataPersistence, _cellFieldNotifier = cellFieldNotifier, _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), - _cacheKey = GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id); + _cacheKey = GridCellId(rowId: gridCell.rowId, fieldId: gridCell.field.id); - _GridCellContext clone() { - return _GridCellContext( + IGridCellController clone() { + return IGridCellController( gridCell: gridCell, cellDataLoader: _cellDataLoader, cellCache: _cellsCache, @@ -160,7 +161,7 @@ class _GridCellContext extends Equatable { FieldType get fieldType => gridCell.field.fieldType; - VoidCallback? startListening({required void Function(T?) onCellChanged}) { + VoidCallback? startListening({required void Function(T?) onCellChanged, VoidCallback? onCellFieldChanged}) { if (isListening) { Log.error("Already started. It seems like you should call clone first"); return null; @@ -176,7 +177,7 @@ class _GridCellContext extends Equatable { _cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey)); _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); - /// Listen on user edit event and load the new cell data if needed. + /// 1.Listen on user edit event and load the new cell data if needed. _cellListener.start(onCellChanged: (result) { result.fold( (_) => _loadData(), @@ -184,11 +185,18 @@ class _GridCellContext extends Equatable { ); }); - /// Listen on the field event and load the cell data if needed. - if (_cellDataLoader.config.reloadOnFieldChanged) { - _onFieldChangedFn = () => _loadData(); - _cellFieldNotifier.addFieldListener(_cacheKey, _onFieldChangedFn!); - } + /// 2.Listen on the field event and load the cell data if needed. + _onFieldChangedFn = () { + if (onCellFieldChanged != null) { + onCellFieldChanged(); + } + + if (_cellDataLoader.config.reloadOnFieldChanged) { + _loadData(); + } + }; + + _cellFieldNotifier.addFieldListener(_cacheKey, _onFieldChangedFn!); /// Notify the listener, the cell data was changed. onCellChangedFn() => onCellChanged(_cellDataNotifier?.value); @@ -234,15 +242,21 @@ class _GridCellContext extends Equatable { _loadDataOperation = Timer(const Duration(milliseconds: 10), () { _cellDataLoader.loadData().then((data) { _cellDataNotifier?.value = data; - _cellsCache.insert(_GridCellCacheObject(key: _cacheKey, object: data)); + _cellsCache.insert(_GridCellCacheItem(key: _cacheKey, object: data)); }); }); } void dispose() { + if (isDispose) { + Log.error("$this should only dispose once"); + return; + } + isDispose = true; _cellListener.stop(); _loadDataOperation?.cancel(); _saveDataOperation?.cancel(); + _cellDataNotifier = null; if (_onFieldChangedFn != null) { _cellFieldNotifier.removeFieldListener(_cacheKey, _onFieldChangedFn!); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart index b8e2b13bbc..041e687c9b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart @@ -6,7 +6,7 @@ import 'cell_service/cell_service.dart'; part 'checkbox_cell_bloc.freezed.dart'; class CheckboxCellBloc extends Bloc { - final GridCellContext cellContext; + final GridCellController cellContext; void Function()? _onCellChangedFn; CheckboxCellBloc({ @@ -67,7 +67,7 @@ class CheckboxCellState with _$CheckboxCellState { required bool isSelected, }) = _CheckboxCellState; - factory CheckboxCellState.initial(GridCellContext context) { + factory CheckboxCellState.initial(GridCellController context) { return CheckboxCellState(isSelected: _isSelected(context.getCellData())); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 28f8bf1b10..84a71f7d05 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -16,7 +16,7 @@ import 'package:fixnum/fixnum.dart' as $fixnum; part 'date_cal_bloc.freezed.dart'; class DateCalBloc extends Bloc { - final GridDateCellContext cellContext; + final GridDateCellController cellContext; void Function()? _onCellChangedFn; DateCalBloc({ diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index 00780143cc..6e98091a90 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -7,7 +7,7 @@ import 'cell_service/cell_service.dart'; part 'date_cell_bloc.freezed.dart'; class DateCellBloc extends Bloc { - final GridDateCellContext cellContext; + final GridDateCellController cellContext; void Function()? _onCellChangedFn; DateCellBloc({required this.cellContext}) : super(DateCellState.initial(cellContext)) { @@ -60,7 +60,7 @@ class DateCellState with _$DateCellState { required Field field, }) = _DateCellState; - factory DateCellState.initial(GridDateCellContext context) { + factory DateCellState.initial(GridDateCellController context) { final cellData = context.getCellData(); return DateCellState( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart index adcfee71e6..65eec13e6c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart @@ -8,7 +8,7 @@ import 'cell_service/cell_service.dart'; part 'number_cell_bloc.freezed.dart'; class NumberCellBloc extends Bloc { - final GridCellContext cellContext; + final GridCellController cellContext; void Function()? _onCellChangedFn; NumberCellBloc({ @@ -72,7 +72,7 @@ class NumberCellState with _$NumberCellState { required Either content, }) = _NumberCellState; - factory NumberCellState.initial(GridCellContext context) { + factory NumberCellState.initial(GridCellController context) { final cellContent = context.getCellData() ?? ""; return NumberCellState( content: left(cellContent), diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart index a6e140f707..a8a9a435e8 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart @@ -7,7 +7,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_serv part 'select_option_cell_bloc.freezed.dart'; class SelectOptionCellBloc extends Bloc { - final GridSelectOptionCellContext cellContext; + final GridSelectOptionCellController cellContext; void Function()? _onCellChangedFn; SelectOptionCellBloc({ @@ -66,7 +66,7 @@ class SelectOptionCellState with _$SelectOptionCellState { required List selectedOptions, }) = _SelectOptionCellState; - factory SelectOptionCellState.initial(GridSelectOptionCellContext context) { + factory SelectOptionCellState.initial(GridSelectOptionCellController context) { final data = context.getCellData(); return SelectOptionCellState( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart index 9ce003b154..139d29141b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; @@ -13,16 +12,13 @@ part 'select_option_editor_bloc.freezed.dart'; class SelectOptionCellEditorBloc extends Bloc { final SelectOptionService _selectOptionService; - final GridSelectOptionCellContext cellContext; - late final GridFieldsListener _fieldListener; - void Function()? _onCellChangedFn; + final GridSelectOptionCellController cellController; Timer? _delayOperation; SelectOptionCellEditorBloc({ - required this.cellContext, - }) : _selectOptionService = SelectOptionService(gridCell: cellContext.gridCell), - _fieldListener = GridFieldsListener(gridId: cellContext.gridId), - super(SelectOptionEditorState.initial(cellContext)) { + required this.cellController, + }) : _selectOptionService = SelectOptionService(gridCell: cellController.gridCell), + super(SelectOptionEditorState.initial(cellController)) { on( (event, emit) async { await event.map( @@ -64,13 +60,8 @@ class SelectOptionCellEditorBloc extends Bloc close() async { - if (_onCellChangedFn != null) { - cellContext.removeListener(_onCellChangedFn!); - _onCellChangedFn = null; - } _delayOperation?.cancel(); - await _fieldListener.stop(); - cellContext.dispose(); + cellController.dispose(); return super.close(); } @@ -157,24 +148,16 @@ class SelectOptionCellEditorBloc extends Bloc Log.error(err), - ); - }); } } @@ -200,7 +183,7 @@ class SelectOptionEditorState with _$SelectOptionEditorState { required Option filter, }) = _SelectOptionEditorState; - factory SelectOptionEditorState.initial(GridSelectOptionCellContext context) { + factory SelectOptionEditorState.initial(GridSelectOptionCellController context) { final data = context.getCellData(loadIfNoCache: false); return SelectOptionEditorState( options: data?.options ?? [], diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart index e3b7fd2dca..783564b5fa 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart @@ -6,7 +6,7 @@ import 'cell_service/cell_service.dart'; part 'text_cell_bloc.freezed.dart'; class TextCellBloc extends Bloc { - final GridCellContext cellContext; + final GridCellController cellContext; void Function()? _onCellChangedFn; TextCellBloc({ required this.cellContext, @@ -63,7 +63,7 @@ class TextCellState with _$TextCellState { required String content, }) = _TextCellState; - factory TextCellState.initial(GridCellContext context) => TextCellState( + factory TextCellState.initial(GridCellController context) => TextCellState( content: context.getCellData() ?? "", ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart index e1fe39c3bf..3811c90ea5 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart @@ -7,7 +7,7 @@ import 'cell_service/cell_service.dart'; part 'url_cell_bloc.freezed.dart'; class URLCellBloc extends Bloc { - final GridURLCellContext cellContext; + final GridURLCellController cellContext; void Function()? _onCellChangedFn; URLCellBloc({ required this.cellContext, @@ -67,7 +67,7 @@ class URLCellState with _$URLCellState { required String url, }) = _URLCellState; - factory URLCellState.initial(GridURLCellContext context) { + factory URLCellState.initial(GridURLCellController context) { final cellData = context.getCellData(); return URLCellState( content: cellData?.content ?? "", diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart index 6e4990943f..59435b6a38 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart @@ -7,7 +7,7 @@ import 'cell_service/cell_service.dart'; part 'url_cell_editor_bloc.freezed.dart'; class URLCellEditorBloc extends Bloc { - final GridURLCellContext cellContext; + final GridURLCellController cellContext; void Function()? _onCellChangedFn; URLCellEditorBloc({ required this.cellContext, @@ -64,7 +64,7 @@ class URLCellEditorState with _$URLCellEditorState { required String content, }) = _URLCellEditorState; - factory URLCellEditorState.initial(GridURLCellContext context) { + factory URLCellEditorState.initial(GridURLCellController context) { final cellData = context.getCellData(); return URLCellEditorState( content: cellData?.content ?? "", diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index 6daf2c50fa..6b980e468f 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -228,12 +228,14 @@ class _GridRowsState extends State<_GridRows> { Animation animation, ) { final rowCache = context.read().getRowCache(rowData.blockId, rowData.rowId); + final fieldCache = context.read().fieldCache; if (rowCache != null) { return SizeTransition( sizeFactor: animation, child: GridRowWidget( rowData: rowData, rowCache: rowCache, + fieldCache: fieldCache, key: ValueKey(rowData.rowId), ), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index 0267ed74b4..a17384dd59 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -22,67 +22,34 @@ class GridCellBuilder { }); GridCellWidget build(GridCell cell, {GridCellStyle? style}) { - final key = ValueKey(gridCell.cellId()); + final key = ValueKey(cell.cellId()); - final cellContextBuilder = GridCellContextBuilder( - gridCell: gridCell, + final cellControllerBuilder = GridCellControllerBuilder( + gridCell: cell, cellCache: cellCache, fieldCache: fieldCache, ); - switch (gridCell.field.fieldType) { + switch (cell.field.fieldType) { case FieldType.Checkbox: - return CheckboxCell(cellContextBuilder: cellContextBuilder, key: key); + return CheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key); case FieldType.DateTime: - return DateCell(cellContextBuilder: cellContextBuilder, key: key, style: style); + return DateCell(cellControllerBuilder: cellControllerBuilder, key: key, style: style); case FieldType.SingleSelect: - return SingleSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key); + return SingleSelectCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); case FieldType.MultiSelect: - return MultiSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key); + return MultiSelectCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); case FieldType.Number: - return NumberCell(cellContextBuilder: cellContextBuilder, key: key); + return NumberCell(cellContorllerBuilder: cellControllerBuilder, key: key); case FieldType.RichText: - return GridTextCell(cellContextBuilder: cellContextBuilder, style: style, key: key); + return GridTextCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); case FieldType.URL: - return GridURLCell(cellContextBuilder: cellContextBuilder, style: style, key: key); + return GridURLCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); } throw UnimplementedError; } } -GridCellWidget buildGridCellWidget( - GridCell gridCell, { - required GridCellsCache cellCache, - required GridFieldCache fieldCache, - GridCellStyle? style, -}) { - final key = ValueKey(gridCell.cellId()); - - final cellContextBuilder = GridCellContextBuilder( - gridCell: gridCell, - cellCache: cellCache, - fieldCache: fieldCache, - ); - - switch (gridCell.field.fieldType) { - case FieldType.Checkbox: - return CheckboxCell(cellContextBuilder: cellContextBuilder, key: key); - case FieldType.DateTime: - return DateCell(cellContextBuilder: cellContextBuilder, key: key, style: style); - case FieldType.SingleSelect: - return SingleSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key); - case FieldType.MultiSelect: - return MultiSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key); - case FieldType.Number: - return NumberCell(cellContextBuilder: cellContextBuilder, key: key); - case FieldType.RichText: - return GridTextCell(cellContextBuilder: cellContextBuilder, style: style, key: key); - case FieldType.URL: - return GridURLCell(cellContextBuilder: cellContextBuilder, style: style, key: key); - } - throw UnimplementedError; -} - class BlankCell extends StatelessWidget { const BlankCell({Key? key}) : super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart index 384d85737f..ac2a2fb979 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart @@ -7,9 +7,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_builder.dart'; class CheckboxCell extends GridCellWidget { - final GridCellContextBuilder cellContextBuilder; + final GridCellControllerBuilder cellControllerBuilder; CheckboxCell({ - required this.cellContextBuilder, + required this.cellControllerBuilder, Key? key, }) : super(key: key); @@ -22,7 +22,7 @@ class _CheckboxCellState extends GridCellState { @override void initState() { - final cellContext = widget.cellContextBuilder.build(); + final cellContext = widget.cellControllerBuilder.build(); _cellBloc = getIt(param1: cellContext)..add(const CheckboxCellEvent.initial()); super.initState(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart index 3e7d40c796..efcb107e55 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart @@ -19,12 +19,12 @@ abstract class GridCellDelegate { } class DateCell extends GridCellWidget { - final GridCellContextBuilder cellContextBuilder; + final GridCellControllerBuilder cellControllerBuilder; late final DateCellStyle? cellStyle; DateCell({ GridCellStyle? style, - required this.cellContextBuilder, + required this.cellControllerBuilder, Key? key, }) : super(key: key) { if (style != null) { @@ -43,7 +43,7 @@ class _DateCellState extends GridCellState { @override void initState() { - final cellContext = widget.cellContextBuilder.build(); + final cellContext = widget.cellControllerBuilder.build(); _cellBloc = getIt(param1: cellContext)..add(const DateCellEvent.initial()); super.initState(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart index 93d304cd1a..5dcd552fef 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart @@ -31,7 +31,7 @@ class DateCellEditor with FlowyOverlayDelegate { Future show( BuildContext context, { - required GridDateCellContext cellContext, + required GridDateCellController cellContext, }) async { DateCellEditor.remove(context); @@ -75,7 +75,7 @@ class DateCellEditor with FlowyOverlayDelegate { } class _CellCalendarWidget extends StatelessWidget { - final GridDateCellContext cellContext; + final GridDateCellController cellContext; final DateTypeOption dateTypeOption; const _CellCalendarWidget({ diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart index 7d16b16ef0..6b1cf4ceae 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart @@ -7,10 +7,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_builder.dart'; class NumberCell extends GridCellWidget { - final GridCellContextBuilder cellContextBuilder; + final GridCellControllerBuilder cellContorllerBuilder; NumberCell({ - required this.cellContextBuilder, + required this.cellContorllerBuilder, Key? key, }) : super(key: key); @@ -25,7 +25,7 @@ class _NumberCellState extends GridFocusNodeCellState { @override void initState() { - final cellContext = widget.cellContextBuilder.build(); + final cellContext = widget.cellContorllerBuilder.build(); _cellBloc = getIt(param1: cellContext)..add(const NumberCellEvent.initial()); _controller = TextEditingController(text: contentFromState(_cellBloc.state)); super.initState(); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart index 63f7e0fc28..4068507f5a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart @@ -21,11 +21,11 @@ class SelectOptionCellStyle extends GridCellStyle { } class SingleSelectCell extends GridCellWidget { - final GridCellContextBuilder cellContextBuilder; + final GridCellControllerBuilder cellContorllerBuilder; late final SelectOptionCellStyle? cellStyle; SingleSelectCell({ - required this.cellContextBuilder, + required this.cellContorllerBuilder, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -45,7 +45,7 @@ class _SingleSelectCellState extends State { @override void initState() { - final cellContext = widget.cellContextBuilder.build() as GridSelectOptionCellContext; + final cellContext = widget.cellContorllerBuilder.build() as GridSelectOptionCellController; _cellBloc = getIt(param1: cellContext)..add(const SelectOptionCellEvent.initial()); super.initState(); } @@ -60,7 +60,7 @@ class _SingleSelectCellState extends State { selectOptions: state.selectedOptions, cellStyle: widget.cellStyle, onFocus: (value) => widget.onCellEditing.value = value, - cellContextBuilder: widget.cellContextBuilder); + cellContorllerBuilder: widget.cellContorllerBuilder); }, ), ); @@ -75,11 +75,11 @@ class _SingleSelectCellState extends State { //---------------------------------------------------------------- class MultiSelectCell extends GridCellWidget { - final GridCellContextBuilder cellContextBuilder; + final GridCellControllerBuilder cellContorllerBuilder; late final SelectOptionCellStyle? cellStyle; MultiSelectCell({ - required this.cellContextBuilder, + required this.cellContorllerBuilder, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -99,7 +99,7 @@ class _MultiSelectCellState extends State { @override void initState() { - final cellContext = widget.cellContextBuilder.build() as GridSelectOptionCellContext; + final cellContext = widget.cellContorllerBuilder.build() as GridSelectOptionCellController; _cellBloc = getIt(param1: cellContext)..add(const SelectOptionCellEvent.initial()); super.initState(); } @@ -114,7 +114,7 @@ class _MultiSelectCellState extends State { selectOptions: state.selectedOptions, cellStyle: widget.cellStyle, onFocus: (value) => widget.onCellEditing.value = value, - cellContextBuilder: widget.cellContextBuilder); + cellContorllerBuilder: widget.cellContorllerBuilder); }, ), ); @@ -131,12 +131,12 @@ class _SelectOptionCell extends StatelessWidget { final List selectOptions; final void Function(bool) onFocus; final SelectOptionCellStyle? cellStyle; - final GridCellContextBuilder cellContextBuilder; + final GridCellControllerBuilder cellContorllerBuilder; const _SelectOptionCell({ required this.selectOptions, required this.onFocus, required this.cellStyle, - required this.cellContextBuilder, + required this.cellContorllerBuilder, Key? key, }) : super(key: key); @@ -172,7 +172,7 @@ class _SelectOptionCell extends StatelessWidget { InkWell( onTap: () { onFocus(true); - final cellContext = cellContextBuilder.build() as GridSelectOptionCellContext; + final cellContext = cellContorllerBuilder.build() as GridSelectOptionCellController; SelectOptionCellEditor.show(context, cellContext, () => onFocus(false)); }, ), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_editor.dart index 76d9a379d7..45a641c39c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_editor.dart @@ -24,11 +24,11 @@ import 'text_field.dart'; const double _editorPannelWidth = 300; class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { - final GridSelectOptionCellContext cellContext; + final GridSelectOptionCellController cellController; final VoidCallback onDismissed; const SelectOptionCellEditor({ - required this.cellContext, + required this.cellController, required this.onDismissed, Key? key, }) : super(key: key); @@ -37,7 +37,7 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { Widget build(BuildContext context) { return BlocProvider( create: (context) => SelectOptionCellEditorBloc( - cellContext: cellContext, + cellController: cellController, )..add(const SelectOptionEditorEvent.initial()), child: BlocBuilder( builder: (context, state) { @@ -59,12 +59,12 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { static void show( BuildContext context, - GridSelectOptionCellContext cellContext, + GridSelectOptionCellController cellContext, VoidCallback onDismissed, ) { SelectOptionCellEditor.remove(context); final editor = SelectOptionCellEditor( - cellContext: cellContext, + cellController: cellContext, onDismissed: onDismissed, ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart index 1bece5a3d7..55bf757ba4 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart @@ -14,10 +14,10 @@ class GridTextCellStyle extends GridCellStyle { } class GridTextCell extends GridCellWidget { - final GridCellContextBuilder cellContextBuilder; + final GridCellControllerBuilder cellContorllerBuilder; late final GridTextCellStyle? cellStyle; GridTextCell({ - required this.cellContextBuilder, + required this.cellContorllerBuilder, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -39,7 +39,7 @@ class _GridTextCellState extends GridFocusNodeCellState { @override void initState() { - final cellContext = widget.cellContextBuilder.build(); + final cellContext = widget.cellContorllerBuilder.build(); _cellBloc = getIt(param1: cellContext); _cellBloc.add(const TextCellEvent.initial()); _controller = TextEditingController(text: _cellBloc.state.content); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/cell_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/cell_editor.dart index f4da18be86..f756bceb32 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/cell_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/cell_editor.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; class URLCellEditor extends StatefulWidget with FlowyOverlayDelegate { - final GridURLCellContext cellContext; + final GridURLCellController cellContext; final VoidCallback completed; const URLCellEditor({required this.cellContext, required this.completed, Key? key}) : super(key: key); @@ -16,7 +16,7 @@ class URLCellEditor extends StatefulWidget with FlowyOverlayDelegate { static void show( BuildContext context, - GridURLCellContext cellContext, + GridURLCellController cellContext, VoidCallback completed, ) { FlowyOverlay.of(context).remove(identifier()); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart index e37dca6632..0edb65a7dc 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart @@ -31,10 +31,10 @@ enum GridURLCellAccessoryType { } class GridURLCell extends GridCellWidget { - final GridCellContextBuilder cellContextBuilder; + final GridCellControllerBuilder cellContorllerBuilder; late final GridURLCellStyle? cellStyle; GridURLCell({ - required this.cellContextBuilder, + required this.cellContorllerBuilder, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -51,11 +51,11 @@ class GridURLCell extends GridCellWidget { GridCellAccessory accessoryFromType(GridURLCellAccessoryType ty, GridCellAccessoryBuildContext buildContext) { switch (ty) { case GridURLCellAccessoryType.edit: - final cellContext = cellContextBuilder.build() as GridURLCellContext; + final cellContext = cellContorllerBuilder.build() as GridURLCellController; return _EditURLAccessory(cellContext: cellContext, anchorContext: buildContext.anchorContext); case GridURLCellAccessoryType.copyURL: - final cellContext = cellContextBuilder.build() as GridURLCellContext; + final cellContext = cellContorllerBuilder.build() as GridURLCellController; return _CopyURLAccessory(cellContext: cellContext); } } @@ -83,7 +83,7 @@ class _GridURLCellState extends GridCellState { @override void initState() { - final cellContext = widget.cellContextBuilder.build() as GridURLCellContext; + final cellContext = widget.cellContorllerBuilder.build() as GridURLCellController; _cellBloc = URLCellBloc(cellContext: cellContext); _cellBloc.add(const URLCellEvent.initial()); super.initState(); @@ -132,7 +132,7 @@ class _GridURLCellState extends GridCellState { if (url.isNotEmpty && await canLaunchUrl(uri)) { await launchUrl(uri); } else { - final cellContext = widget.cellContextBuilder.build() as GridURLCellContext; + final cellContext = widget.cellContorllerBuilder.build() as GridURLCellController; widget.onCellEditing.value = true; URLCellEditor.show(context, cellContext, () { widget.onCellEditing.value = false; @@ -155,7 +155,7 @@ class _GridURLCellState extends GridCellState { } class _EditURLAccessory extends StatelessWidget with GridCellAccessory { - final GridURLCellContext cellContext; + final GridURLCellController cellContext; final BuildContext anchorContext; const _EditURLAccessory({ required this.cellContext, @@ -176,7 +176,7 @@ class _EditURLAccessory extends StatelessWidget with GridCellAccessory { } class _CopyURLAccessory extends StatelessWidget with GridCellAccessory { - final GridURLCellContext cellContext; + final GridURLCellController cellContext; const _CopyURLAccessory({required this.cellContext, Key? key}) : super(key: key); @override From eda54719b127861d29605c9ebe0d5ef49223b065 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Thu, 14 Jul 2022 14:23:06 -0400 Subject: [PATCH 019/112] chore: remove pubspec.lock generated by libraries. Keep the one in the application --- .gitignore | 6 +- .../packages/flowy_infra/pubspec.lock | 231 -------- .../flowy_infra_ui/example/pubspec.lock | 334 ------------ .../pubspec.lock | 168 ------ .../flowy_infra_ui_web/pubspec.lock | 187 ------- .../packages/flowy_infra_ui/pubspec.lock | 320 ----------- .../packages/flowy_sdk/example/pubspec.lock | 309 ----------- .../app_flowy/packages/flowy_sdk/pubspec.lock | 504 ------------------ 8 files changed, 5 insertions(+), 2054 deletions(-) delete mode 100644 frontend/app_flowy/packages/flowy_infra/pubspec.lock delete mode 100644 frontend/app_flowy/packages/flowy_infra_ui/example/pubspec.lock delete mode 100644 frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_platform_interface/pubspec.lock delete mode 100644 frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_web/pubspec.lock delete mode 100644 frontend/app_flowy/packages/flowy_infra_ui/pubspec.lock delete mode 100644 frontend/app_flowy/packages/flowy_sdk/example/pubspec.lock delete mode 100644 frontend/app_flowy/packages/flowy_sdk/pubspec.lock diff --git a/.gitignore b/.gitignore index ab5f64486f..c956a0ad13 100644 --- a/.gitignore +++ b/.gitignore @@ -27,4 +27,8 @@ frontend/.vscode/* !frontend/.vscode/tasks.json !frontend/.vscode/launch.json !frontend/.vscode/extensions.json -!frontend/.vscode/*.code-snippets \ No newline at end of file +!frontend/.vscode/*.code-snippets + +# Commit the highest level pubspec.lock, but ignore the others +pubspec.lock +!frontend/app_flowy/pubspec.lock diff --git a/frontend/app_flowy/packages/flowy_infra/pubspec.lock b/frontend/app_flowy/packages/flowy_infra/pubspec.lock deleted file mode 100644 index 256c2dac3a..0000000000 --- a/frontend/app_flowy/packages/flowy_infra/pubspec.lock +++ /dev/null @@ -1,231 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - url: "https://pub.dartlang.org" - source: hosted - version: "0.22.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.3" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "0.5.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.1" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.8" - textstyle_extensions: - dependency: "direct main" - description: - name: textstyle_extensions - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0-nullsafety" - time: - dependency: "direct main" - description: - name: time - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - uuid: - dependency: "direct main" - description: - name: uuid - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.4" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "5.2.0" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=1.24.0-7.0" diff --git a/frontend/app_flowy/packages/flowy_infra_ui/example/pubspec.lock b/frontend/app_flowy/packages/flowy_infra_ui/example/pubspec.lock deleted file mode 100644 index 0a91c0b58c..0000000000 --- a/frontend/app_flowy/packages/flowy_infra_ui/example/pubspec.lock +++ /dev/null @@ -1,334 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - animations: - dependency: transitive - description: - name: animations - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - dartz: - dependency: transitive - description: - name: dartz - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.0-nullsafety.2" - equatable: - dependency: transitive - description: - name: equatable - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flowy_infra: - dependency: transitive - description: - path: "../../flowy_infra" - relative: true - source: path - version: "0.0.1" - flowy_infra_ui: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "0.0.1" - flowy_infra_ui_platform_interface: - dependency: transitive - description: - path: "../flowy_infra_ui_platform_interface" - relative: true - source: path - version: "0.0.1" - flowy_infra_ui_web: - dependency: transitive - description: - path: "../flowy_infra_ui_web" - relative: true - source: path - version: "0.0.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_svg: - dependency: transitive - description: - name: flutter_svg - url: "https://pub.dartlang.org" - source: hosted - version: "0.22.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - lint: - dependency: transitive - description: - name: lint - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.3" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - loading_indicator: - dependency: transitive - description: - name: loading_indicator - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - nested: - dependency: transitive - description: - name: nested - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "0.5.1+1" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.1" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "4.4.0" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - provider: - dependency: transitive - description: - name: provider - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - styled_widget: - dependency: transitive - description: - name: styled_widget - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.1+2" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.3" - textstyle_extensions: - dependency: transitive - description: - name: textstyle_extensions - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0-nullsafety" - time: - dependency: transitive - description: - name: time - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - uuid: - dependency: transitive - description: - name: uuid - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.4" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "5.3.1" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=2.0.0" diff --git a/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_platform_interface/pubspec.lock b/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_platform_interface/pubspec.lock deleted file mode 100644 index a2ed8a8fe8..0000000000 --- a/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_platform_interface/pubspec.lock +++ /dev/null @@ -1,168 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.6.1" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - plugin_platform_interface: - dependency: "direct main" - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" -sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" diff --git a/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_web/pubspec.lock b/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_web/pubspec.lock deleted file mode 100644 index 804b67b5b9..0000000000 --- a/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_web/pubspec.lock +++ /dev/null @@ -1,187 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.6.1" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flowy_infra_ui_platform_interface: - dependency: "direct main" - description: - path: "../flowy_infra_ui_platform_interface" - relative: true - source: path - version: "0.0.1" - flutter: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" -sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" diff --git a/frontend/app_flowy/packages/flowy_infra_ui/pubspec.lock b/frontend/app_flowy/packages/flowy_infra_ui/pubspec.lock deleted file mode 100644 index 8ff7b9870b..0000000000 --- a/frontend/app_flowy/packages/flowy_infra_ui/pubspec.lock +++ /dev/null @@ -1,320 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - animations: - dependency: "direct main" - description: - name: animations - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - dartz: - dependency: "direct main" - description: - name: dartz - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.0-nullsafety.2" - equatable: - dependency: "direct main" - description: - name: equatable - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flowy_infra: - dependency: "direct main" - description: - path: "../flowy_infra" - relative: true - source: path - version: "0.0.1" - flowy_infra_ui_platform_interface: - dependency: "direct main" - description: - path: flowy_infra_ui_platform_interface - relative: true - source: path - version: "0.0.1" - flowy_infra_ui_web: - dependency: "direct main" - description: - path: flowy_infra_ui_web - relative: true - source: path - version: "0.0.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.4" - flutter_svg: - dependency: transitive - description: - name: flutter_svg - url: "https://pub.dartlang.org" - source: hosted - version: "0.22.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - lint: - dependency: transitive - description: - name: lint - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.3" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - loading_indicator: - dependency: "direct main" - description: - name: loading_indicator - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - nested: - dependency: transitive - description: - name: nested - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - path_drawing: - dependency: transitive - description: - name: path_drawing - url: "https://pub.dartlang.org" - source: hosted - version: "0.5.1+1" - path_parsing: - dependency: transitive - description: - name: path_parsing - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.1" - petitparser: - dependency: transitive - description: - name: petitparser - url: "https://pub.dartlang.org" - source: hosted - version: "4.4.0" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - provider: - dependency: "direct main" - description: - name: provider - url: "https://pub.dartlang.org" - source: hosted - version: "6.0.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - styled_widget: - dependency: "direct main" - description: - name: styled_widget - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.1+2" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.3" - textstyle_extensions: - dependency: "direct main" - description: - name: textstyle_extensions - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0-nullsafety" - time: - dependency: transitive - description: - name: time - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - uuid: - dependency: transitive - description: - name: uuid - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.4" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - xml: - dependency: transitive - description: - name: xml - url: "https://pub.dartlang.org" - source: hosted - version: "5.3.1" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=2.0.0" diff --git a/frontend/app_flowy/packages/flowy_sdk/example/pubspec.lock b/frontend/app_flowy/packages/flowy_sdk/example/pubspec.lock deleted file mode 100644 index 921bd4fb2b..0000000000 --- a/frontend/app_flowy/packages/flowy_sdk/example/pubspec.lock +++ /dev/null @@ -1,309 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - archive: - dependency: transitive - description: - name: archive - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.6" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - dartz: - dependency: transitive - description: - name: dartz - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.0-nullsafety.2" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - ffi: - dependency: transitive - description: - name: ffi - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.2" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - flowy_sdk: - dependency: "direct main" - description: - path: ".." - relative: true - source: path - version: "0.0.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_driver: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.1" - fuchsia_remote_debug_protocol: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - integration_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - isolates: - dependency: transitive - description: - name: isolates - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.3+8" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.1" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - logger: - dependency: transitive - description: - name: logger - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.3" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - platform: - dependency: transitive - description: - name: platform - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" - process: - dependency: transitive - description: - name: process - url: "https://pub.dartlang.org" - source: hosted - version: "4.2.4" - protobuf: - dependency: transitive - description: - name: protobuf - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - sync_http: - dependency: transitive - description: - name: sync_http - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.8" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - vm_service: - dependency: transitive - description: - name: vm_service - url: "https://pub.dartlang.org" - source: hosted - version: "7.5.0" - webdriver: - dependency: transitive - description: - name: webdriver - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=1.17.0" diff --git a/frontend/app_flowy/packages/flowy_sdk/pubspec.lock b/frontend/app_flowy/packages/flowy_sdk/pubspec.lock deleted file mode 100644 index 1f5af870d9..0000000000 --- a/frontend/app_flowy/packages/flowy_sdk/pubspec.lock +++ /dev/null @@ -1,504 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - _fe_analyzer_shared: - dependency: transitive - description: - name: _fe_analyzer_shared - url: "https://pub.dartlang.org" - source: hosted - version: "20.0.0" - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.dartlang.org" - source: hosted - version: "1.4.0" - args: - dependency: transitive - description: - name: args - url: "https://pub.dartlang.org" - source: hosted - version: "1.6.0" - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.8.2" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - build: - dependency: transitive - description: - name: build - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - build_config: - dependency: transitive - description: - name: build_config - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.7" - build_daemon: - dependency: transitive - description: - name: build_daemon - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.10" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - build_runner: - dependency: "direct dev" - description: - name: build_runner - url: "https://pub.dartlang.org" - source: hosted - version: "1.12.2" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.12" - built_collection: - dependency: transitive - description: - name: built_collection - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.0" - built_value: - dependency: transitive - description: - name: built_value - url: "https://pub.dartlang.org" - source: hosted - version: "8.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.0" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - code_builder: - dependency: transitive - description: - name: code_builder - url: "https://pub.dartlang.org" - source: hosted - version: "3.6.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.0" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.1" - dart_style: - dependency: transitive - description: - name: dart_style - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - dartz: - dependency: "direct main" - description: - name: dartz - url: "https://pub.dartlang.org" - source: hosted - version: "0.10.0-nullsafety.2" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - ffi: - dependency: "direct main" - description: - name: ffi - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - file: - dependency: transitive - description: - name: file - url: "https://pub.dartlang.org" - source: hosted - version: "6.1.0" - fixnum: - dependency: transitive - description: - name: fixnum - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - freezed: - dependency: "direct dev" - description: - name: freezed - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.1+2" - freezed_annotation: - dependency: "direct main" - description: - name: freezed_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.1" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.1" - graphs: - dependency: transitive - description: - name: graphs - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.4" - io: - dependency: transitive - description: - name: io - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.4" - isolates: - dependency: "direct main" - description: - name: isolates - url: "https://pub.dartlang.org" - source: hosted - version: "3.0.3+8" - js: - dependency: transitive - description: - name: js - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.3" - json_annotation: - dependency: transitive - description: - name: json_annotation - url: "https://pub.dartlang.org" - source: hosted - version: "4.0.1" - lints: - dependency: transitive - description: - name: lints - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - logger: - dependency: "direct main" - description: - name: logger - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.11" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.3" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.7.0" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.dartlang.org" - source: hosted - version: "0.9.7" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.0" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.dartlang.org" - source: hosted - version: "1.5.0" - protobuf: - dependency: "direct main" - description: - name: protobuf - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - pubspec_parse: - dependency: transitive - description: - name: pubspec_parse - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.dartlang.org" - source: hosted - version: "0.7.9" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.3" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_gen: - dependency: transitive - description: - name: source_gen - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - stream_transform: - dependency: transitive - description: - name: stream_transform - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.8" - timing: - dependency: transitive - description: - name: timing - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.1+3" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.0" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" -sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=1.17.0" From a8b560ed935820e7a3df75c6c4998db73182e701 Mon Sep 17 00:00:00 2001 From: Ian Su Date: Fri, 15 Jul 2022 09:09:56 +0800 Subject: [PATCH 020/112] debug: rerender username properly --- .../lib/workspace/presentation/home/menu/menu_user.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart index e819a0ed40..4bc2ce29c2 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart @@ -67,6 +67,7 @@ class MenuUser extends StatelessWidget { Widget _renderSettingsButton(BuildContext context) { final theme = context.watch(); + final userProfile = context.read().state.userProfile; return Tooltip( message: LocaleKeys.settings_menu_open.tr(), child: IconButton( @@ -74,7 +75,7 @@ class MenuUser extends StatelessWidget { showDialog( context: context, builder: (context) { - return SettingsDialog(user); + return SettingsDialog(userProfile); }, ); }, From 4825d83d2f95e68c43e7a0675b4e1794d09df466 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 15 Jul 2022 11:19:24 +0800 Subject: [PATCH 021/112] chore: rename classes --- ....dart => field_type_option_edit_bloc.dart} | 26 +- .../grid/field/type_option/date_bloc.dart | 4 +- .../type_option/multi_select_type_option.dart | 7 +- .../grid/field/type_option/number_bloc.dart | 4 +- .../single_select_type_option.dart | 6 +- .../type_option/type_option_service.dart | 10 +- .../workspace/application/grid/prelude.dart | 2 +- .../grid/src/widgets/header/field_editor.dart | 16 +- .../widgets/header/field_editor_pannel.dart | 243 ------------------ .../header/field_type_option_editor.dart | 126 +++++++++ .../widgets/header/type_option/builder.dart | 108 ++++++++ .../widgets/header/type_option/checkbox.dart | 12 +- .../src/widgets/header/type_option/date.dart | 11 +- .../header/type_option/multi_select.dart | 9 +- .../widgets/header/type_option/number.dart | 10 +- .../widgets/header/type_option/rich_text.dart | 13 +- .../header/type_option/select_option.dart | 2 +- .../header/type_option/single_select.dart | 9 +- .../src/widgets/header/type_option/url.dart | 12 +- 19 files changed, 314 insertions(+), 316 deletions(-) rename frontend/app_flowy/lib/workspace/application/grid/field/{field_editor_pannel_bloc.dart => field_type_option_edit_bloc.dart} (51%) delete mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart similarity index 51% rename from frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart index 6310452d48..c92ad41d56 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_pannel_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart @@ -5,21 +5,21 @@ import 'dart:async'; import 'field_service.dart'; -part 'field_editor_pannel_bloc.freezed.dart'; +part 'field_type_option_edit_bloc.freezed.dart'; -class FieldEditorPannelBloc extends Bloc { +class FieldTypeOptionEditBloc extends Bloc { final GridFieldContext _fieldContext; void Function()? _fieldListenFn; - FieldEditorPannelBloc(GridFieldContext fieldContext) + FieldTypeOptionEditBloc(GridFieldContext fieldContext) : _fieldContext = fieldContext, - super(FieldEditorPannelState.initial(fieldContext)) { - on( + super(FieldTypeOptionEditState.initial(fieldContext)) { + on( (event, emit) async { event.when( initial: () { _fieldListenFn = fieldContext.addFieldListener((field) { - add(FieldEditorPannelEvent.didReceiveFieldUpdated(field)); + add(FieldTypeOptionEditEvent.didReceiveFieldUpdated(field)); }); }, didReceiveFieldUpdated: (field) { @@ -40,18 +40,18 @@ class FieldEditorPannelBloc extends Bloc FieldEditorPannelState( + factory FieldTypeOptionEditState.initial(GridFieldContext fieldContext) => FieldTypeOptionEditState( field: fieldContext.field, ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart index 8784422c54..73be8a427e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart @@ -6,9 +6,9 @@ import 'dart:async'; import 'package:protobuf/protobuf.dart'; part 'date_bloc.freezed.dart'; -typedef DateTypeOptionContext = TypeOptionContext; +typedef DateTypeOptionContext = TypeOptionWidgetContext; -class DateTypeOptionDataBuilder extends TypeOptionDataBuilder { +class DateTypeOptionDataParser extends TypeOptionWidgetDataParser { @override DateTypeOption fromBuffer(List buffer) { return DateTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart index 0a6e2de14c..f36974f8e3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart @@ -7,11 +7,12 @@ import 'package:protobuf/protobuf.dart'; import 'select_option_type_option_bloc.dart'; import 'type_option_service.dart'; -class MultiSelectTypeOptionContext extends TypeOptionContext with SelectOptionTypeOptionAction { +class MultiSelectTypeOptionContext extends TypeOptionWidgetContext + with SelectOptionTypeOptionAction { final TypeOptionService service; MultiSelectTypeOptionContext({ - required MultiSelectTypeOptionDataBuilder dataBuilder, + required MultiSelectTypeOptionWidgetDataParser dataBuilder, required GridFieldContext fieldContext, }) : service = TypeOptionService( gridId: fieldContext.gridId, @@ -70,7 +71,7 @@ class MultiSelectTypeOptionContext extends TypeOptionContext { +class MultiSelectTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { @override MultiSelectTypeOption fromBuffer(List buffer) { return MultiSelectTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart index a708668066..ea51970b32 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart @@ -8,9 +8,9 @@ import 'package:protobuf/protobuf.dart'; part 'number_bloc.freezed.dart'; -typedef NumberTypeOptionContext = TypeOptionContext; +typedef NumberTypeOptionContext = TypeOptionWidgetContext; -class NumberTypeOptionDataBuilder extends TypeOptionDataBuilder { +class NumberTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { @override NumberTypeOption fromBuffer(List buffer) { return NumberTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart index c09d17f11e..0dc05e8e1f 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart @@ -7,12 +7,12 @@ import 'package:protobuf/protobuf.dart'; import 'select_option_type_option_bloc.dart'; import 'type_option_service.dart'; -class SingleSelectTypeOptionContext extends TypeOptionContext +class SingleSelectTypeOptionContext extends TypeOptionWidgetContext with SelectOptionTypeOptionAction { final TypeOptionService service; SingleSelectTypeOptionContext({ - required SingleSelectTypeOptionDataBuilder dataBuilder, + required SingleSelectTypeOptionWidgetDataParser dataBuilder, required GridFieldContext fieldContext, }) : service = TypeOptionService( gridId: fieldContext.gridId, @@ -71,7 +71,7 @@ class SingleSelectTypeOptionContext extends TypeOptionContext { +class SingleSelectTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { @override SingleSelectTypeOption fromBuffer(List buffer) { return SingleSelectTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart index 3a30ef30ca..84faa3c35a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart @@ -33,16 +33,16 @@ class TypeOptionService { } } -abstract class TypeOptionDataBuilder { +abstract class TypeOptionWidgetDataParser { T fromBuffer(List buffer); } -class TypeOptionContext { +class TypeOptionWidgetContext { T? _typeOptionObject; final GridFieldContext _fieldContext; - final TypeOptionDataBuilder dataBuilder; + final TypeOptionWidgetDataParser dataBuilder; - TypeOptionContext({ + TypeOptionWidgetContext({ required this.dataBuilder, required GridFieldContext fieldContext, }) : _fieldContext = fieldContext; @@ -77,7 +77,7 @@ class TypeOptionContext2 { final Field field; final FieldService _fieldService; T? _data; - final TypeOptionDataBuilder dataBuilder; + final TypeOptionWidgetDataParser dataBuilder; TypeOptionContext2({ required this.gridId, diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 6ea198f303..9c09a038e1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -8,7 +8,7 @@ export 'grid_header_bloc.dart'; export 'field/field_service.dart'; export 'field/field_action_sheet_bloc.dart'; export 'field/field_editor_bloc.dart'; -export 'field/field_editor_pannel_bloc.dart'; +export 'field/field_type_option_edit_bloc.dart'; // Field Type Option export 'field/type_option/date_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart index 3390351663..148727752c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; import 'field_name_input.dart'; -import 'field_editor_pannel.dart'; +import 'field_type_option_editor.dart'; class FieldEditor extends StatelessWidget with FlowyOverlayDelegate { final String gridId; @@ -38,9 +38,9 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate { children: [ FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12), const VSpace(10), - const _FieldNameTextField(), + const _FieldNameCell(), const VSpace(10), - const _FieldPannel(), + const _FieldTypeOptionCell(), ], ); }, @@ -74,8 +74,8 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate { bool asBarrier() => true; } -class _FieldPannel extends StatelessWidget { - const _FieldPannel({Key? key}) : super(key: key); +class _FieldTypeOptionCell extends StatelessWidget { + const _FieldTypeOptionCell({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -84,15 +84,15 @@ class _FieldPannel extends StatelessWidget { builder: (context, state) { return state.fieldContext.fold( () => const SizedBox(), - (fieldContext) => FieldEditorPannel(fieldContext: fieldContext), + (fieldContext) => FieldTypeOptionEditor(fieldContext: fieldContext), ); }, ); } } -class _FieldNameTextField extends StatelessWidget { - const _FieldNameTextField({Key? key}) : super(key: key); +class _FieldNameCell extends StatelessWidget { + const _FieldNameCell({Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart deleted file mode 100644 index 7ec5144458..0000000000 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart +++ /dev/null @@ -1,243 +0,0 @@ -import 'dart:typed_data'; - -import 'package:app_flowy/workspace/application/grid/field/type_option/multi_select_type_option.dart'; -import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart'; -import 'package:dartz/dartz.dart' show Either; -import 'package:flowy_infra/image.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:flowy_infra_ui/flowy_infra_ui.dart'; -import 'package:flowy_infra_ui/style_widget/button.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:app_flowy/workspace/application/grid/prelude.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart'; -import 'field_type_extension.dart'; -import 'type_option/multi_select.dart'; -import 'type_option/number.dart'; -import 'type_option/rich_text.dart'; -import 'type_option/single_select.dart'; -import 'type_option/url.dart'; - -typedef UpdateFieldCallback = void Function(Field, Uint8List); -typedef SwitchToFieldCallback = Future> Function( - String fieldId, - FieldType fieldType, -); - -class FieldEditorPannel extends StatefulWidget { - final GridFieldContext fieldContext; - - const FieldEditorPannel({ - required this.fieldContext, - Key? key, - }) : super(key: key); - - @override - State createState() => _FieldEditorPannelState(); -} - -class _FieldEditorPannelState extends State { - String? currentOverlayIdentifier; - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => FieldEditorPannelBloc(widget.fieldContext)..add(const FieldEditorPannelEvent.initial()), - child: BlocBuilder( - builder: (context, state) { - List children = [_switchFieldTypeButton(context, widget.fieldContext.field)]; - final typeOptionWidget = _typeOptionWidget(context: context, state: state); - - if (typeOptionWidget != null) { - children.add(typeOptionWidget); - } - - return ListView( - shrinkWrap: true, - children: children, - ); - }, - ), - ); - } - - Widget _switchFieldTypeButton(BuildContext context, Field field) { - final theme = context.watch(); - return SizedBox( - height: GridSize.typeOptionItemHeight, - child: FlowyButton( - text: FlowyText.medium(field.fieldType.title(), fontSize: 12), - margin: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), - hoverColor: theme.hover, - onTap: () { - final list = FieldTypeList(onSelectField: (newFieldType) { - widget.fieldContext.switchToField(newFieldType); - }); - _showOverlay(context, list); - }, - leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), - rightIcon: svgWidget("grid/more", color: theme.iconColor), - ), - ); - } - - Widget? _typeOptionWidget({ - required BuildContext context, - required FieldEditorPannelState state, - }) { - final overlayDelegate = TypeOptionOverlayDelegate( - showOverlay: _showOverlay, - hideOverlay: _hideOverlay, - ); - - final builder = _makeTypeOptionBuild( - typeOptionContext: _makeTypeOptionContext(widget.fieldContext), - overlayDelegate: overlayDelegate, - ); - - return builder.customWidget; - } - - void _showOverlay(BuildContext context, Widget child, {VoidCallback? onRemoved}) { - final identifier = child.toString(); - if (currentOverlayIdentifier != null) { - FlowyOverlay.of(context).remove(currentOverlayIdentifier!); - } - - currentOverlayIdentifier = identifier; - FlowyOverlay.of(context).insertWithAnchor( - widget: OverlayContainer( - child: child, - constraints: BoxConstraints.loose(const Size(460, 440)), - ), - identifier: identifier, - anchorContext: context, - anchorDirection: AnchorDirection.leftWithCenterAligned, - style: FlowyOverlayStyle(blur: false), - anchorOffset: const Offset(-20, 0), - ); - } - - void _hideOverlay(BuildContext context) { - if (currentOverlayIdentifier != null) { - FlowyOverlay.of(context).remove(currentOverlayIdentifier!); - } - } -} - -abstract class TypeOptionBuilder { - Widget? get customWidget; -} - -TypeOptionBuilder _makeTypeOptionBuild({ - required TypeOptionContext typeOptionContext, - required TypeOptionOverlayDelegate overlayDelegate, -}) { - switch (typeOptionContext.field.fieldType) { - case FieldType.Checkbox: - return CheckboxTypeOptionBuilder( - typeOptionContext as CheckboxTypeOptionContext, - ); - case FieldType.DateTime: - return DateTypeOptionBuilder( - typeOptionContext as DateTypeOptionContext, - overlayDelegate, - ); - case FieldType.SingleSelect: - return SingleSelectTypeOptionBuilder( - typeOptionContext as SingleSelectTypeOptionContext, - overlayDelegate, - ); - case FieldType.MultiSelect: - return MultiSelectTypeOptionBuilder( - typeOptionContext as MultiSelectTypeOptionContext, - overlayDelegate, - ); - case FieldType.Number: - return NumberTypeOptionBuilder( - typeOptionContext as NumberTypeOptionContext, - overlayDelegate, - ); - case FieldType.RichText: - return RichTextTypeOptionBuilder( - typeOptionContext as RichTextTypeOptionContext, - ); - - case FieldType.URL: - return URLTypeOptionBuilder( - typeOptionContext as URLTypeOptionContext, - ); - } - throw UnimplementedError; -} - -TypeOptionContext _makeTypeOptionContext(GridFieldContext fieldContext) { - switch (fieldContext.field.fieldType) { - case FieldType.Checkbox: - return CheckboxTypeOptionContext( - fieldContext: fieldContext, - dataBuilder: CheckboxTypeOptionDataBuilder(), - ); - case FieldType.DateTime: - return DateTypeOptionContext( - fieldContext: fieldContext, - dataBuilder: DateTypeOptionDataBuilder(), - ); - case FieldType.MultiSelect: - return MultiSelectTypeOptionContext( - fieldContext: fieldContext, - dataBuilder: MultiSelectTypeOptionDataBuilder(), - ); - case FieldType.Number: - return NumberTypeOptionContext( - fieldContext: fieldContext, - dataBuilder: NumberTypeOptionDataBuilder(), - ); - case FieldType.RichText: - return RichTextTypeOptionContext( - fieldContext: fieldContext, - dataBuilder: RichTextTypeOptionDataBuilder(), - ); - case FieldType.SingleSelect: - return SingleSelectTypeOptionContext( - fieldContext: fieldContext, - dataBuilder: SingleSelectTypeOptionDataBuilder(), - ); - - case FieldType.URL: - return URLTypeOptionContext( - fieldContext: fieldContext, - dataBuilder: URLTypeOptionDataBuilder(), - ); - } - - throw UnimplementedError(); -} - -abstract class TypeOptionWidget extends StatelessWidget { - const TypeOptionWidget({Key? key}) : super(key: key); -} - -typedef TypeOptionData = Uint8List; -typedef TypeOptionDataCallback = void Function(TypeOptionData typeOptionData); -typedef ShowOverlayCallback = void Function( - BuildContext anchorContext, - Widget child, { - VoidCallback? onRemoved, -}); -typedef HideOverlayCallback = void Function(BuildContext anchorContext); - -class TypeOptionOverlayDelegate { - ShowOverlayCallback showOverlay; - HideOverlayCallback hideOverlay; - TypeOptionOverlayDelegate({ - required this.showOverlay, - required this.hideOverlay, - }); -} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart new file mode 100644 index 0000000000..bca9b8e2f7 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart @@ -0,0 +1,126 @@ +import 'dart:typed_data'; +import 'package:dartz/dartz.dart' show Either; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart'; +import 'field_type_extension.dart'; +import 'type_option/builder.dart'; + +typedef UpdateFieldCallback = void Function(Field, Uint8List); +typedef SwitchToFieldCallback = Future> Function( + String fieldId, + FieldType fieldType, +); + +class FieldTypeOptionEditor extends StatefulWidget { + final GridFieldContext fieldContext; + + const FieldTypeOptionEditor({ + required this.fieldContext, + Key? key, + }) : super(key: key); + + @override + State createState() => _FieldTypeOptionEditorState(); +} + +class _FieldTypeOptionEditorState extends State { + String? currentOverlayIdentifier; + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => FieldTypeOptionEditBloc(widget.fieldContext)..add(const FieldTypeOptionEditEvent.initial()), + child: BlocBuilder( + builder: (context, state) { + List children = [_switchFieldTypeButton(context, widget.fieldContext.field)]; + final typeOptionWidget = _typeOptionWidget(context: context, state: state); + + if (typeOptionWidget != null) { + children.add(typeOptionWidget); + } + + return ListView( + shrinkWrap: true, + children: children, + ); + }, + ), + ); + } + + Widget _switchFieldTypeButton(BuildContext context, Field field) { + final theme = context.watch(); + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(field.fieldType.title(), fontSize: 12), + margin: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + hoverColor: theme.hover, + onTap: () { + final list = FieldTypeList(onSelectField: (newFieldType) { + widget.fieldContext.switchToField(newFieldType); + }); + _showOverlay(context, list); + }, + leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), + rightIcon: svgWidget("grid/more", color: theme.iconColor), + ), + ); + } + + Widget? _typeOptionWidget({ + required BuildContext context, + required FieldTypeOptionEditState state, + }) { + final overlayDelegate = TypeOptionOverlayDelegate( + showOverlay: _showOverlay, + hideOverlay: _hideOverlay, + ); + + return makeTypeOptionWidget( + context: context, + fieldContext: widget.fieldContext, + overlayDelegate: overlayDelegate, + ); + } + + void _showOverlay(BuildContext context, Widget child, {VoidCallback? onRemoved}) { + final identifier = child.toString(); + if (currentOverlayIdentifier != null) { + FlowyOverlay.of(context).remove(currentOverlayIdentifier!); + } + + currentOverlayIdentifier = identifier; + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: child, + constraints: BoxConstraints.loose(const Size(460, 440)), + ), + identifier: identifier, + anchorContext: context, + anchorDirection: AnchorDirection.leftWithCenterAligned, + style: FlowyOverlayStyle(blur: false), + anchorOffset: const Offset(-20, 0), + ); + } + + void _hideOverlay(BuildContext context) { + if (currentOverlayIdentifier != null) { + FlowyOverlay.of(context).remove(currentOverlayIdentifier!); + } + } +} + +abstract class TypeOptionWidget extends StatelessWidget { + const TypeOptionWidget({Key? key}) : super(key: key); +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart new file mode 100644 index 0000000000..872a501f90 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart @@ -0,0 +1,108 @@ +import 'dart:typed_data'; + +import 'package:app_flowy/workspace/application/grid/field/type_option/multi_select_type_option.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flutter/material.dart'; +import 'date.dart'; +import 'multi_select.dart'; +import 'number.dart'; +import 'rich_text.dart'; +import 'single_select.dart'; +import 'url.dart'; + +typedef TypeOptionData = Uint8List; +typedef TypeOptionDataCallback = void Function(TypeOptionData typeOptionData); +typedef ShowOverlayCallback = void Function( + BuildContext anchorContext, + Widget child, { + VoidCallback? onRemoved, +}); +typedef HideOverlayCallback = void Function(BuildContext anchorContext); + +class TypeOptionOverlayDelegate { + ShowOverlayCallback showOverlay; + HideOverlayCallback hideOverlay; + TypeOptionOverlayDelegate({ + required this.showOverlay, + required this.hideOverlay, + }); +} + +abstract class TypeOptionWidgetBuilder { + Widget? build(BuildContext context); +} + +Widget? makeTypeOptionWidget({ + required BuildContext context, + required GridFieldContext fieldContext, + required TypeOptionOverlayDelegate overlayDelegate, +}) { + final builder = makeTypeOptionWidgetBuilder(fieldContext, overlayDelegate); + return builder.build(context); +} + +TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( + GridFieldContext fieldContext, + TypeOptionOverlayDelegate overlayDelegate, +) { + switch (fieldContext.field.fieldType) { + case FieldType.Checkbox: + final context = CheckboxTypeOptionContext( + fieldContext: fieldContext, + dataBuilder: CheckboxTypeOptionWidgetDataParser(), + ); + return CheckboxTypeOptionWidgetBuilder(context); + case FieldType.DateTime: + final context = DateTypeOptionContext( + fieldContext: fieldContext, + dataBuilder: DateTypeOptionDataParser(), + ); + return DateTypeOptionWidgetBuilder( + context, + overlayDelegate, + ); + case FieldType.SingleSelect: + final context = SingleSelectTypeOptionContext( + fieldContext: fieldContext, + dataBuilder: SingleSelectTypeOptionWidgetDataParser(), + ); + return SingleSelectTypeOptionWidgetBuilder( + context, + overlayDelegate, + ); + case FieldType.MultiSelect: + final context = MultiSelectTypeOptionContext( + fieldContext: fieldContext, + dataBuilder: MultiSelectTypeOptionWidgetDataParser(), + ); + return MultiSelectTypeOptionWidgetBuilder( + context, + overlayDelegate, + ); + case FieldType.Number: + final context = NumberTypeOptionContext( + fieldContext: fieldContext, + dataBuilder: NumberTypeOptionWidgetDataParser(), + ); + return NumberTypeOptionWidgetBuilder( + context, + overlayDelegate, + ); + case FieldType.RichText: + final context = RichTextTypeOptionContext( + fieldContext: fieldContext, + dataBuilder: RichTextTypeOptionWidgetDataParser(), + ); + return RichTextTypeOptionWidgetBuilder(context); + + case FieldType.URL: + final context = URLTypeOptionContext( + fieldContext: fieldContext, + dataBuilder: URLTypeOptionWidgetDataParser(), + ); + return URLTypeOptionWidgetBuilder(context); + } + throw UnimplementedError; +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart index c1e202f358..79622a6731 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart @@ -1,20 +1,20 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pb.dart'; import 'package:flutter/material.dart'; +import 'builder.dart'; -typedef CheckboxTypeOptionContext = TypeOptionContext; +typedef CheckboxTypeOptionContext = TypeOptionWidgetContext; -class CheckboxTypeOptionDataBuilder extends TypeOptionDataBuilder { +class CheckboxTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { @override CheckboxTypeOption fromBuffer(List buffer) { return CheckboxTypeOption.fromBuffer(buffer); } } -class CheckboxTypeOptionBuilder extends TypeOptionBuilder { - CheckboxTypeOptionBuilder(CheckboxTypeOptionContext typeOptionContext); +class CheckboxTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder { + CheckboxTypeOptionWidgetBuilder(CheckboxTypeOptionContext typeOptionContext); @override - Widget? get customWidget => null; + Widget? build(BuildContext context) => null; } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart index f4031dc9ce..f15b73f75c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart @@ -1,6 +1,6 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/date_bloc.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart'; import 'package:easy_localization/easy_localization.dart' hide DateFormat; import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:flowy_infra/image.dart'; @@ -12,11 +12,12 @@ import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'builder.dart'; -class DateTypeOptionBuilder extends TypeOptionBuilder { +class DateTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder { final DateTypeOptionWidget _widget; - DateTypeOptionBuilder( + DateTypeOptionWidgetBuilder( DateTypeOptionContext typeOptionContext, TypeOptionOverlayDelegate overlayDelegate, ) : _widget = DateTypeOptionWidget( @@ -25,7 +26,9 @@ class DateTypeOptionBuilder extends TypeOptionBuilder { ); @override - Widget? get customWidget => _widget; + Widget? build(BuildContext context) { + return _widget; + } } class DateTypeOptionWidget extends TypeOptionWidget { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart index fc310410f9..8c7ab40a6f 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart @@ -1,13 +1,14 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/multi_select_type_option.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart'; import 'package:flutter/material.dart'; +import 'builder.dart'; import 'select_option.dart'; -class MultiSelectTypeOptionBuilder extends TypeOptionBuilder { +class MultiSelectTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder { final MultiSelectTypeOptionWidget _widget; - MultiSelectTypeOptionBuilder( + MultiSelectTypeOptionWidgetBuilder( MultiSelectTypeOptionContext typeOptionContext, TypeOptionOverlayDelegate overlayDelegate, ) : _widget = MultiSelectTypeOptionWidget( @@ -16,7 +17,7 @@ class MultiSelectTypeOptionBuilder extends TypeOptionBuilder { ); @override - Widget? get customWidget => _widget; + Widget? build(BuildContext context) => _widget; } class MultiSelectTypeOptionWidget extends TypeOptionWidget { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart index bca17e1cd8..e15abb1728 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart @@ -2,7 +2,7 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/number_bl import 'package:app_flowy/workspace/application/grid/field/type_option/number_format_bloc.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart'; import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; @@ -15,10 +15,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:easy_localization/easy_localization.dart' hide NumberFormat; import 'package:app_flowy/generated/locale_keys.g.dart'; -class NumberTypeOptionBuilder extends TypeOptionBuilder { +import 'builder.dart'; + +class NumberTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder { final NumberTypeOptionWidget _widget; - NumberTypeOptionBuilder( + NumberTypeOptionWidgetBuilder( NumberTypeOptionContext typeOptionContext, TypeOptionOverlayDelegate overlayDelegate, ) : _widget = NumberTypeOptionWidget( @@ -27,7 +29,7 @@ class NumberTypeOptionBuilder extends TypeOptionBuilder { ); @override - Widget? get customWidget => _widget; + Widget? build(BuildContext context) => _widget; } class NumberTypeOptionWidget extends TypeOptionWidget { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/rich_text.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/rich_text.dart index 03f9ed347c..f79fb2dd9d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/rich_text.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/rich_text.dart @@ -1,21 +1,20 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart'; - import 'package:flutter/material.dart'; +import 'builder.dart'; -typedef RichTextTypeOptionContext = TypeOptionContext; +typedef RichTextTypeOptionContext = TypeOptionWidgetContext; -class RichTextTypeOptionDataBuilder extends TypeOptionDataBuilder { +class RichTextTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { @override RichTextTypeOption fromBuffer(List buffer) { return RichTextTypeOption.fromBuffer(buffer); } } -class RichTextTypeOptionBuilder extends TypeOptionBuilder { - RichTextTypeOptionBuilder(RichTextTypeOptionContext typeOptionContext); +class RichTextTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder { + RichTextTypeOptionWidgetBuilder(RichTextTypeOptionContext typeOptionContext); @override - Widget? get customWidget => null; + Widget? build(BuildContext context) => null; } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart index 60c1bfcdd6..fea3e5df43 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart @@ -2,7 +2,6 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/select_op import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/extension.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart'; import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; @@ -14,6 +13,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'builder.dart'; import 'select_option_editor.dart'; class SelectOptionTypeOptionWidget extends StatelessWidget { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart index fedddec11d..a1ed4e857a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart @@ -1,12 +1,13 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/single_select_type_option.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart'; import 'package:flutter/material.dart'; +import 'builder.dart'; import 'select_option.dart'; -class SingleSelectTypeOptionBuilder extends TypeOptionBuilder { +class SingleSelectTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder { final SingleSelectTypeOptionWidget _widget; - SingleSelectTypeOptionBuilder( + SingleSelectTypeOptionWidgetBuilder( SingleSelectTypeOptionContext typeOptionContext, TypeOptionOverlayDelegate overlayDelegate, ) : _widget = SingleSelectTypeOptionWidget( @@ -15,7 +16,7 @@ class SingleSelectTypeOptionBuilder extends TypeOptionBuilder { ); @override - Widget? get customWidget => _widget; + Widget? build(BuildContext context) => _widget; } class SingleSelectTypeOptionWidget extends TypeOptionWidget { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/url.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/url.dart index f4e73f7fdc..a55711bd05 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/url.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/url.dart @@ -1,20 +1,20 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart'; import 'package:flutter/material.dart'; +import 'builder.dart'; -typedef URLTypeOptionContext = TypeOptionContext; +typedef URLTypeOptionContext = TypeOptionWidgetContext; -class URLTypeOptionDataBuilder extends TypeOptionDataBuilder { +class URLTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { @override URLTypeOption fromBuffer(List buffer) { return URLTypeOption.fromBuffer(buffer); } } -class URLTypeOptionBuilder extends TypeOptionBuilder { - URLTypeOptionBuilder(URLTypeOptionContext typeOptionContext); +class URLTypeOptionWidgetBuilder extends TypeOptionWidgetBuilder { + URLTypeOptionWidgetBuilder(URLTypeOptionContext typeOptionContext); @override - Widget? get customWidget => null; + Widget? build(BuildContext context) => null; } From a73987456ec75ba467e31d73b926bcdab507b151 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 16 Jul 2022 11:53:39 +0800 Subject: [PATCH 022/112] chore: add documentation --- .../application/grid/block/block_service.dart | 6 +- .../grid/cell/cell_service/cache.dart | 39 ++++---- .../cell/cell_service/cell_data_loader.dart | 26 +---- .../cell_service/cell_data_persistence.dart | 8 +- .../cell_service/cell_field_notifier.dart | 7 +- .../grid/cell/cell_service/cell_service.dart | 15 +-- .../cell/cell_service/context_builder.dart | 94 ++++++++++++------- .../grid/cell/select_option_editor_bloc.dart | 2 +- .../grid/cell/select_option_service.dart | 2 +- .../application/grid/field/field_service.dart | 4 + .../grid/field/type_option/date_bloc.dart | 2 +- .../type_option/multi_select_type_option.dart | 4 +- .../grid/field/type_option/number_bloc.dart | 2 +- .../single_select_type_option.dart | 4 +- .../type_option/type_option_service.dart | 10 +- .../workspace/application/grid/grid_bloc.dart | 6 +- .../application/grid/grid_service.dart | 4 +- .../application/grid/row/row_detail_bloc.dart | 4 +- .../application/grid/row/row_service.dart | 20 ++-- .../grid/src/widgets/cell/cell_builder.dart | 6 +- .../src/widgets/cell/date_cell/date_cell.dart | 2 +- .../widgets/cell/date_cell/date_editor.dart | 10 +- .../widgets/cell/url_cell/cell_editor.dart | 8 +- .../src/widgets/cell/url_cell/url_cell.dart | 2 +- .../widgets/header/type_option/builder.dart | 10 +- .../widgets/header/type_option/checkbox.dart | 2 +- .../widgets/header/type_option/rich_text.dart | 2 +- .../src/widgets/header/type_option/url.dart | 2 +- .../grid/src/widgets/row/row_detail.dart | 2 +- 29 files changed, 161 insertions(+), 144 deletions(-) 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 index a531e65d2e..2a4c82bdd4 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart @@ -6,7 +6,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'block_listener.dart'; -class GridBlockCacheService { +class GridBlockCache { final String gridId; final GridBlock block; late GridRowsCache _rowCache; @@ -15,7 +15,7 @@ class GridBlockCacheService { List get rows => _rowCache.rows; GridRowsCache get rowCache => _rowCache; - GridBlockCacheService({ + GridBlockCache({ required this.gridId, required this.block, required GridFieldCache fieldCache, @@ -23,7 +23,7 @@ class GridBlockCacheService { _rowCache = GridRowsCache( gridId: gridId, block: block, - delegate: GridRowCacheDelegateImpl(fieldCache), + notifier: GridRowCacheFieldNotifierImpl(fieldCache), ); _listener = GridBlockListener(blockId: block.id); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart index a6079bae6d..dd50e98cd5 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart @@ -1,25 +1,29 @@ part of 'cell_service.dart'; -typedef GridCellMap = LinkedHashMap; +typedef GridCellMap = LinkedHashMap; -class _GridCellCacheItem { - GridCellId key; +class _GridCellCacheValue { + GridCellCacheKey key; dynamic object; - _GridCellCacheItem({ + _GridCellCacheValue({ required this.key, required this.object, }); } -class GridCellId { +/// Use to index the cell in the grid. +/// We use [fieldId + rowId] to identify the cell. +class GridCellCacheKey { final String fieldId; final String rowId; - GridCellId({ + GridCellCacheKey({ required this.fieldId, required this.rowId, }); } +/// GridCellsCache is used to cache cell data of each Grid. +/// We use GridCellCacheKey to index the cell in the cache. class GridCellsCache { final String gridId; @@ -33,29 +37,28 @@ class GridCellsCache { _cellDataByFieldId.remove(fieldId); } - void insert(T item) { - var map = _cellDataByFieldId[item.key.fieldId]; + void insert(T value) { + var map = _cellDataByFieldId[value.key.fieldId]; if (map == null) { - _cellDataByFieldId[item.key.fieldId] = {}; - map = _cellDataByFieldId[item.key.fieldId]; + _cellDataByFieldId[value.key.fieldId] = {}; + map = _cellDataByFieldId[value.key.fieldId]; } - map![item.key.rowId] = item.object; + map![value.key.rowId] = value.object; } - T? get(GridCellId key) { + T? get(GridCellCacheKey key) { final map = _cellDataByFieldId[key.fieldId]; if (map == null) { return null; } else { - final object = map[key.rowId]; - if (object is T) { - return object; + final value = map[key.rowId]; + if (value is T) { + return value; } else { - if (object != null) { - Log.error("Cache data type does not match the cache data type"); + if (value != null) { + Log.error("Expected value type: $T, but receive $value"); } - return null; } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart index 95b7b77b61..dfbd7e197b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart @@ -5,40 +5,22 @@ abstract class IGridCellDataConfig { bool get reloadOnFieldChanged; } -class GridCellDataConfig implements IGridCellDataConfig { - @override - final bool reloadOnFieldChanged; - - const GridCellDataConfig({ - this.reloadOnFieldChanged = false, - }); -} - -abstract class IGridCellDataLoader { - Future loadData(); - - IGridCellDataConfig get config; -} - abstract class ICellDataParser { T? parserData(List data); } -class GridCellDataLoader extends IGridCellDataLoader { +class GridCellDataLoader { final CellService service = CellService(); - final GridCell gridCell; + final GridCellIdentifier gridCell; final ICellDataParser parser; - - @override - final IGridCellDataConfig config; + final bool reloadOnFieldChanged; GridCellDataLoader({ required this.gridCell, required this.parser, - this.config = const GridCellDataConfig(), + this.reloadOnFieldChanged = false, }); - @override Future loadData() { final fut = service.getCell( gridId: gridCell.gridId, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart index 9e2f577d7c..4eebda7839 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart @@ -1,11 +1,13 @@ part of 'cell_service.dart'; +/// Save the cell data to disk +/// You can extend this class to do custom operations. For example, the DateCellDataPersistence. abstract class IGridCellDataPersistence { Future> save(D data); } class CellDataPersistence implements IGridCellDataPersistence { - final GridCell gridCell; + final GridCellIdentifier gridCell; CellDataPersistence({ required this.gridCell, @@ -36,7 +38,7 @@ class CalendarData with _$CalendarData { } class DateCellDataPersistence implements IGridCellDataPersistence { - final GridCell gridCell; + final GridCellIdentifier gridCell; DateCellDataPersistence({ required this.gridCell, }); @@ -61,7 +63,7 @@ class DateCellDataPersistence implements IGridCellDataPersistence } } -CellIdentifierPayload _cellIdentifier(GridCell gridCell) { +CellIdentifierPayload _cellIdentifier(GridCellIdentifier gridCell) { return CellIdentifierPayload.create() ..gridId = gridCell.gridId ..fieldId = gridCell.field.id diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart index 1c043e2096..e4c909d501 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart @@ -8,6 +8,8 @@ abstract class GridFieldChangedNotifier { void dispose(); } +/// Grid's cell helper wrapper that enables each cell will get notified when the corresponding field was changed. +/// You Register an onFieldChanged callback to listen to the cell changes, and unregister if you don't want to listen. class GridCellFieldNotifier { /// fieldId: {objectId: callback} final Map>> _fieldListenerByFieldId = {}; @@ -27,7 +29,8 @@ class GridCellFieldNotifier { ); } - void addFieldListener(GridCellId cacheKey, VoidCallback onFieldChanged) { + /// + void register(GridCellCacheKey cacheKey, VoidCallback onFieldChanged) { var map = _fieldListenerByFieldId[cacheKey.fieldId]; if (map == null) { _fieldListenerByFieldId[cacheKey.fieldId] = {}; @@ -43,7 +46,7 @@ class GridCellFieldNotifier { } } - void removeFieldListener(GridCellId cacheKey, VoidCallback fn) { + void unregister(GridCellCacheKey cacheKey, VoidCallback fn) { var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId]; final index = callbacks?.indexWhere((callback) => callback == fn); if (index != null && index != -1) { 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 6c7791af92..2cf9536f2d 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 @@ -18,6 +18,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'dart:convert' show utf8; +import '../../field/type_option/type_option_service.dart'; import 'cell_field_notifier.dart'; part 'cell_service.freezed.dart'; part 'cell_data_loader.dart'; @@ -57,18 +58,20 @@ class CellService { } } +/// Id of the cell +/// We can locate the cell by using gridId + rowId + field.id. @freezed -class GridCell with _$GridCell { - const factory GridCell({ +class GridCellIdentifier with _$GridCellIdentifier { + const factory GridCellIdentifier({ required String gridId, required String rowId, required Field field, - }) = _GridCell; + }) = _GridCellIdentifier; // ignore: unused_element - const GridCell._(); + const GridCellIdentifier._(); - String cellId() { - return rowId + field.id + "${field.fieldType}"; + ValueKey key() { + return ValueKey(rowId + field.id + "${field.fieldType}"); } } 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 f45520c602..0ec9e1753f 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 @@ -6,12 +6,12 @@ typedef GridDateCellController = IGridCellController typedef GridURLCellController = IGridCellController; class GridCellControllerBuilder { - final GridCell _gridCell; + final GridCellIdentifier _gridCell; final GridCellsCache _cellCache; final GridFieldCache _fieldCache; GridCellControllerBuilder( - {required GridCell gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache}) + {required GridCellIdentifier gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache}) : _cellCache = cellCache, _fieldCache = fieldCache, _gridCell = gridCell; @@ -29,34 +29,33 @@ class GridCellControllerBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, - cellFieldNotifier: cellFieldNotifier, + fieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); case FieldType.DateTime: final cellDataLoader = GridCellDataLoader( gridCell: _gridCell, parser: DateCellDataParser(), - config: const GridCellDataConfig(reloadOnFieldChanged: true), + reloadOnFieldChanged: true, ); return GridDateCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, - cellFieldNotifier: cellFieldNotifier, + fieldNotifier: cellFieldNotifier, cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell), ); case FieldType.Number: final cellDataLoader = GridCellDataLoader( gridCell: _gridCell, parser: StringCellDataParser(), - config: const GridCellDataConfig(reloadOnFieldChanged: true), ); return GridCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, - cellFieldNotifier: cellFieldNotifier, + fieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); case FieldType.RichText: @@ -68,7 +67,7 @@ class GridCellControllerBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, - cellFieldNotifier: cellFieldNotifier, + fieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); case FieldType.MultiSelect: @@ -76,14 +75,14 @@ class GridCellControllerBuilder { final cellDataLoader = GridCellDataLoader( gridCell: _gridCell, parser: SelectOptionCellDataParser(), - config: const GridCellDataConfig(reloadOnFieldChanged: true), + reloadOnFieldChanged: true, ); return GridSelectOptionCellController( gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, - cellFieldNotifier: cellFieldNotifier, + fieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); @@ -96,7 +95,7 @@ class GridCellControllerBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: cellDataLoader, - cellFieldNotifier: cellFieldNotifier, + fieldNotifier: cellFieldNotifier, cellDataPersistence: CellDataPersistence(gridCell: _gridCell), ); } @@ -104,17 +103,21 @@ class GridCellControllerBuilder { } } -// T: the type of the CellData -// D: the type of the data that will be saved to disk +/// IGridCellController is used to manipulate the cell and receive notifications. +/// * Read/Write cell data +/// * Listen on field/cell notifications. +/// +/// Generic T represents the type of the cell data. +/// Generic D represents the type of data that will be saved to the disk +/// // ignore: must_be_immutable class IGridCellController extends Equatable { - final GridCell gridCell; + final GridCellIdentifier gridCell; final GridCellsCache _cellsCache; - final GridCellId _cacheKey; + final GridCellCacheKey _cacheKey; final FieldService _fieldService; - final GridCellFieldNotifier _cellFieldNotifier; - // final GridCellFieldNotifier _fieldNotifier; - final IGridCellDataLoader _cellDataLoader; + final GridCellFieldNotifier _fieldNotifier; + final GridCellDataLoader _cellDataLoader; final IGridCellDataPersistence _cellDataPersistence; late final CellListener _cellListener; @@ -124,28 +127,27 @@ class IGridCellController extends Equatable { VoidCallback? _onFieldChangedFn; Timer? _loadDataOperation; Timer? _saveDataOperation; - bool isDispose = false; + bool _isDispose = false; IGridCellController({ required this.gridCell, required GridCellsCache cellCache, - required GridCellFieldNotifier cellFieldNotifier, - required IGridCellDataLoader cellDataLoader, + required GridCellFieldNotifier fieldNotifier, + required GridCellDataLoader cellDataLoader, required IGridCellDataPersistence cellDataPersistence, - // required GridFieldChangedNotifier notifierDelegate, }) : _cellsCache = cellCache, _cellDataLoader = cellDataLoader, _cellDataPersistence = cellDataPersistence, - _cellFieldNotifier = cellFieldNotifier, + _fieldNotifier = fieldNotifier, _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), - _cacheKey = GridCellId(rowId: gridCell.rowId, fieldId: gridCell.field.id); + _cacheKey = GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id); IGridCellController clone() { return IGridCellController( gridCell: gridCell, cellDataLoader: _cellDataLoader, cellCache: _cellsCache, - cellFieldNotifier: _cellFieldNotifier, + fieldNotifier: _fieldNotifier, cellDataPersistence: _cellDataPersistence); } @@ -191,16 +193,18 @@ class IGridCellController extends Equatable { onCellFieldChanged(); } - if (_cellDataLoader.config.reloadOnFieldChanged) { + if (_cellDataLoader.reloadOnFieldChanged) { _loadData(); } }; - _cellFieldNotifier.addFieldListener(_cacheKey, _onFieldChangedFn!); + _fieldNotifier.register(_cacheKey, _onFieldChangedFn!); /// Notify the listener, the cell data was changed. onCellChangedFn() => onCellChanged(_cellDataNotifier?.value); _cellDataNotifier?.addListener(onCellChangedFn); + + // Return the function pointer that can be used when calling removeListener. return onCellChangedFn; } @@ -208,22 +212,38 @@ class IGridCellController extends Equatable { _cellDataNotifier?.removeListener(fn); } - T? getCellData({bool loadIfNoCache = true}) { + /// Return the cell data. + /// The cell data will be read from the Cache first, and load from disk if it does not exist. + /// You can set [loadIfNotExist] to false (default is true) to disable loading the cell data. + T? getCellData({bool loadIfNotExist = true}) { final data = _cellsCache.get(_cacheKey); - if (data == null && loadIfNoCache) { + if (data == null && loadIfNotExist) { _loadData(); } return data; } - Future> getTypeOptionData() { - return _fieldService.getFieldTypeOptionData(fieldType: fieldType); + /// Return the FieldTypeOptionData that can be parsed into corresponding class using the [parser]. + /// [PD] is the type that the parser return. + Future> getFieldTypeOption(P parser) { + return _fieldService.getFieldTypeOptionData(fieldType: fieldType).then((result) { + return result.fold( + (data) => parser.fromBuffer(data.typeOptionData), + (err) => right(err), + ); + }); } + /// Save the cell data to disk + /// You can set [dedeplicate] to true (default is false) to reduce the save operation. + /// It's useful when you call this method when user editing the [TextField]. + /// The default debounce interval is 300 milliseconds. void saveCellData(D data, {bool deduplicate = false, void Function(Option)? resultCallback}) async { if (deduplicate) { _loadDataOperation?.cancel(); - _loadDataOperation = Timer(const Duration(milliseconds: 300), () async { + + _saveDataOperation?.cancel(); + _saveDataOperation = Timer(const Duration(milliseconds: 300), () async { final result = await _cellDataPersistence.save(data); if (resultCallback != null) { resultCallback(result); @@ -238,28 +258,30 @@ class IGridCellController extends Equatable { } void _loadData() { + _saveDataOperation?.cancel(); + _loadDataOperation?.cancel(); _loadDataOperation = Timer(const Duration(milliseconds: 10), () { _cellDataLoader.loadData().then((data) { _cellDataNotifier?.value = data; - _cellsCache.insert(_GridCellCacheItem(key: _cacheKey, object: data)); + _cellsCache.insert(_GridCellCacheValue(key: _cacheKey, object: data)); }); }); } void dispose() { - if (isDispose) { + if (_isDispose) { Log.error("$this should only dispose once"); return; } - isDispose = true; + _isDispose = true; _cellListener.stop(); _loadDataOperation?.cancel(); _saveDataOperation?.cancel(); _cellDataNotifier = null; if (_onFieldChangedFn != null) { - _cellFieldNotifier.removeFieldListener(_cacheKey, _onFieldChangedFn!); + _fieldNotifier.unregister(_cacheKey, _onFieldChangedFn!); _onFieldChangedFn = null; } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart index 139d29141b..b531955ab7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart @@ -184,7 +184,7 @@ class SelectOptionEditorState with _$SelectOptionEditorState { }) = _SelectOptionEditorState; factory SelectOptionEditorState.initial(GridSelectOptionCellController context) { - final data = context.getCellData(loadIfNoCache: false); + final data = context.getCellData(loadIfNotExist: false); return SelectOptionEditorState( options: data?.options ?? [], allOptions: data?.options ?? [], diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart index f3458454d1..147b24d468 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; import 'cell_service/cell_service.dart'; class SelectOptionService { - final GridCell gridCell; + final GridCellIdentifier gridCell; SelectOptionService({required this.gridCell}); String get gridId => gridCell.gridId; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index 99fef626c0..879cf599dd 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -9,6 +9,10 @@ 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; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart index 73be8a427e..7258854ec6 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/date_bloc.dart @@ -8,7 +8,7 @@ part 'date_bloc.freezed.dart'; typedef DateTypeOptionContext = TypeOptionWidgetContext; -class DateTypeOptionDataParser extends TypeOptionWidgetDataParser { +class DateTypeOptionDataParser extends TypeOptionDataParser { @override DateTypeOption fromBuffer(List buffer) { return DateTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart index f36974f8e3..eae1765396 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart @@ -18,7 +18,7 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext Function(SelectOption) get deleteOption { @@ -71,7 +71,7 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext { +class MultiSelectTypeOptionWidgetDataParser extends TypeOptionDataParser { @override MultiSelectTypeOption fromBuffer(List buffer) { return MultiSelectTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart index ea51970b32..804ce3ee11 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/number_bloc.dart @@ -10,7 +10,7 @@ part 'number_bloc.freezed.dart'; typedef NumberTypeOptionContext = TypeOptionWidgetContext; -class NumberTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { +class NumberTypeOptionWidgetDataParser extends TypeOptionDataParser { @override NumberTypeOption fromBuffer(List buffer) { return NumberTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart index 0dc05e8e1f..16e686fb44 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart @@ -18,7 +18,7 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext Function(SelectOption) get deleteOption { @@ -71,7 +71,7 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext { +class SingleSelectTypeOptionWidgetDataParser extends TypeOptionDataParser { @override SingleSelectTypeOption fromBuffer(List buffer) { return SingleSelectTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart index 84faa3c35a..05ca9e9aa1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart @@ -33,17 +33,17 @@ class TypeOptionService { } } -abstract class TypeOptionWidgetDataParser { +abstract class TypeOptionDataParser { T fromBuffer(List buffer); } class TypeOptionWidgetContext { T? _typeOptionObject; final GridFieldContext _fieldContext; - final TypeOptionWidgetDataParser dataBuilder; + final TypeOptionDataParser dataParser; TypeOptionWidgetContext({ - required this.dataBuilder, + required this.dataParser, required GridFieldContext fieldContext, }) : _fieldContext = fieldContext; @@ -56,7 +56,7 @@ class TypeOptionWidgetContext { return _typeOptionObject!; } - final T object = dataBuilder.fromBuffer(_fieldContext.typeOptionData); + final T object = dataParser.fromBuffer(_fieldContext.typeOptionData); _typeOptionObject = object; return object; } @@ -77,7 +77,7 @@ class TypeOptionContext2 { final Field field; final FieldService _fieldService; T? _data; - final TypeOptionWidgetDataParser dataBuilder; + final TypeOptionDataParser dataBuilder; TypeOptionContext2({ required this.gridId, 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 e6fff41317..3098ca1609 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -20,7 +20,7 @@ class GridBloc extends Bloc { final GridFieldCache fieldCache; // key: the block id - final LinkedHashMap _blocks; + final LinkedHashMap _blocks; List get rows { final List rows = []; @@ -69,7 +69,7 @@ class GridBloc extends Bloc { } GridRowsCache? getRowCache(String blockId, String rowId) { - final GridBlockCacheService? blockCache = _blocks[blockId]; + final GridBlockCache? blockCache = _blocks[blockId]; return blockCache?.rowCache; } @@ -119,7 +119,7 @@ class GridBloc extends Bloc { return; } - final cache = GridBlockCacheService( + final cache = GridBlockCache( gridId: gridId, block: block, fieldCache: fieldCache, diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index 3e9cbc2eee..0e176df919 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -186,11 +186,11 @@ class GridFieldCache { } } -class GridRowCacheDelegateImpl extends GridRowCacheDelegate { +class GridRowCacheFieldNotifierImpl extends GridRowCacheFieldNotifier { final GridFieldCache _cache; FieldChangesetCallback? _onChangesetFn; FieldsCallback? _onFieldFn; - GridRowCacheDelegateImpl(GridFieldCache cache) : _cache = cache; + GridRowCacheFieldNotifierImpl(GridFieldCache cache) : _cache = cache; @override UnmodifiableListView get fields => _cache.unmodifiableFields; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart index 0613b388a4..405c0ef523 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart @@ -58,13 +58,13 @@ class RowDetailBloc extends Bloc { @freezed class RowDetailEvent with _$RowDetailEvent { const factory RowDetailEvent.initial() = _Initial; - const factory RowDetailEvent.didReceiveCellDatas(List gridCells) = _DidReceiveCellDatas; + const factory RowDetailEvent.didReceiveCellDatas(List gridCells) = _DidReceiveCellDatas; } @freezed class RowDetailState with _$RowDetailState { const factory RowDetailState({ - required List gridCells, + required List gridCells, }) = _RowDetailState; factory RowDetailState.initial() => RowDetailState( 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 27749083b4..df8a068598 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 @@ -14,7 +14,7 @@ part 'row_service.freezed.dart'; typedef RowUpdateCallback = void Function(); -abstract class GridRowCacheDelegate { +abstract class GridRowCacheFieldNotifier { UnmodifiableListView get fields; void onFieldsChanged(VoidCallback callback); void onFieldChanged(void Function(Field) callback); @@ -27,7 +27,7 @@ class GridRowsCache { final _Notifier _notifier; List _rows = []; final HashMap _rowByRowId; - final GridRowCacheDelegate _delegate; + final GridRowCacheFieldNotifier _fieldNotifier; final GridCellsCache _cellCache; List get rows => _rows; @@ -36,19 +36,19 @@ class GridRowsCache { GridRowsCache({ required this.gridId, required this.block, - required GridRowCacheDelegate delegate, + required GridRowCacheFieldNotifier notifier, }) : _cellCache = GridCellsCache(gridId: gridId), _rowByRowId = HashMap(), _notifier = _Notifier(), - _delegate = delegate { + _fieldNotifier = notifier { // - delegate.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange())); - delegate.onFieldChanged((field) => _cellCache.remove(field.id)); + notifier.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange())); + notifier.onFieldChanged((field) => _cellCache.remove(field.id)); _rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList(); } Future dispose() async { - _delegate.dispose(); + _fieldNotifier.dispose(); _notifier.dispose(); await _cellCache.dispose(); } @@ -195,9 +195,9 @@ class GridRowsCache { GridCellMap _makeGridCells(String rowId, Row? row) { var cellDataMap = GridCellMap.new(); - for (final field in _delegate.fields) { + for (final field in _fieldNotifier.fields) { if (field.visibility) { - cellDataMap[field.id] = GridCell( + cellDataMap[field.id] = GridCellIdentifier( rowId: rowId, gridId: gridId, field: field, @@ -236,7 +236,7 @@ class GridRowsCache { return GridRow( gridId: gridId, blockId: block.id, - fields: _delegate.fields, + fields: _fieldNotifier.fields, rowId: rowId, height: rowHeight, ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index a17384dd59..1fd4c726be 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -21,15 +21,13 @@ class GridCellBuilder { required this.fieldCache, }); - GridCellWidget build(GridCell cell, {GridCellStyle? style}) { - final key = ValueKey(cell.cellId()); - + GridCellWidget build(GridCellIdentifier cell, {GridCellStyle? style}) { final cellControllerBuilder = GridCellControllerBuilder( gridCell: cell, cellCache: cellCache, fieldCache: fieldCache, ); - + final key = cell.key(); switch (cell.field.fieldType) { case FieldType.Checkbox: return CheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart index efcb107e55..7436d0ac7f 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart @@ -80,7 +80,7 @@ class _DateCellState extends GridCellState { final calendar = DateCellEditor(onDismissed: () => widget.onCellEditing.value = false); calendar.show( context, - cellContext: bloc.cellContext.clone(), + cellController: bloc.cellContext.clone(), ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart index 5dcd552fef..36ad22ec53 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_editor.dart @@ -31,16 +31,16 @@ class DateCellEditor with FlowyOverlayDelegate { Future show( BuildContext context, { - required GridDateCellController cellContext, + required GridDateCellController cellController, }) async { DateCellEditor.remove(context); - final result = await cellContext.getTypeOptionData(); + final result = await cellController.getFieldTypeOption(DateTypeOptionDataParser()); result.fold( - (data) { + (dateTypeOption) { final calendar = _CellCalendarWidget( - cellContext: cellContext, - dateTypeOption: DateTypeOption.fromBuffer(data.typeOptionData), + cellContext: cellController, + dateTypeOption: dateTypeOption, ); FlowyOverlay.of(context).insertWithAnchor( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/cell_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/cell_editor.dart index f756bceb32..b6bc8daa21 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/cell_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/cell_editor.dart @@ -7,9 +7,9 @@ import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; class URLCellEditor extends StatefulWidget with FlowyOverlayDelegate { - final GridURLCellController cellContext; + final GridURLCellController cellController; final VoidCallback completed; - const URLCellEditor({required this.cellContext, required this.completed, Key? key}) : super(key: key); + const URLCellEditor({required this.cellController, required this.completed, Key? key}) : super(key: key); @override State createState() => _URLCellEditorState(); @@ -21,7 +21,7 @@ class URLCellEditor extends StatefulWidget with FlowyOverlayDelegate { ) { FlowyOverlay.of(context).remove(identifier()); final editor = URLCellEditor( - cellContext: cellContext, + cellController: cellContext, completed: completed, ); @@ -62,7 +62,7 @@ class _URLCellEditorState extends State { @override void initState() { - _cellBloc = URLCellEditorBloc(cellContext: widget.cellContext); + _cellBloc = URLCellEditorBloc(cellContext: widget.cellController); _cellBloc.add(const URLCellEditorEvent.initial()); _controller = TextEditingController(text: _cellBloc.state.content); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart index 0edb65a7dc..9cc14fbbda 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/url_cell/url_cell.dart @@ -187,7 +187,7 @@ class _CopyURLAccessory extends StatelessWidget with GridCellAccessory { @override void onTap() { - final content = cellContext.getCellData(loadIfNoCache: false)?.content ?? ""; + final content = cellContext.getCellData(loadIfNotExist: false)?.content ?? ""; Clipboard.setData(ClipboardData(text: content)); showMessageToast(LocaleKeys.grid_row_copyProperty.tr()); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart index 872a501f90..f63edbac14 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart @@ -51,13 +51,13 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( case FieldType.Checkbox: final context = CheckboxTypeOptionContext( fieldContext: fieldContext, - dataBuilder: CheckboxTypeOptionWidgetDataParser(), + dataParser: CheckboxTypeOptionWidgetDataParser(), ); return CheckboxTypeOptionWidgetBuilder(context); case FieldType.DateTime: final context = DateTypeOptionContext( fieldContext: fieldContext, - dataBuilder: DateTypeOptionDataParser(), + dataParser: DateTypeOptionDataParser(), ); return DateTypeOptionWidgetBuilder( context, @@ -84,7 +84,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( case FieldType.Number: final context = NumberTypeOptionContext( fieldContext: fieldContext, - dataBuilder: NumberTypeOptionWidgetDataParser(), + dataParser: NumberTypeOptionWidgetDataParser(), ); return NumberTypeOptionWidgetBuilder( context, @@ -93,14 +93,14 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( case FieldType.RichText: final context = RichTextTypeOptionContext( fieldContext: fieldContext, - dataBuilder: RichTextTypeOptionWidgetDataParser(), + dataParser: RichTextTypeOptionWidgetDataParser(), ); return RichTextTypeOptionWidgetBuilder(context); case FieldType.URL: final context = URLTypeOptionContext( fieldContext: fieldContext, - dataBuilder: URLTypeOptionWidgetDataParser(), + dataParser: URLTypeOptionWidgetDataParser(), ); return URLTypeOptionWidgetBuilder(context); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart index 79622a6731..beca8acd09 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/checkbox.dart @@ -5,7 +5,7 @@ import 'builder.dart'; typedef CheckboxTypeOptionContext = TypeOptionWidgetContext; -class CheckboxTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { +class CheckboxTypeOptionWidgetDataParser extends TypeOptionDataParser { @override CheckboxTypeOption fromBuffer(List buffer) { return CheckboxTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/rich_text.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/rich_text.dart index f79fb2dd9d..2375918f11 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/rich_text.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/rich_text.dart @@ -5,7 +5,7 @@ import 'builder.dart'; typedef RichTextTypeOptionContext = TypeOptionWidgetContext; -class RichTextTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { +class RichTextTypeOptionWidgetDataParser extends TypeOptionDataParser { @override RichTextTypeOption fromBuffer(List buffer) { return RichTextTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/url.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/url.dart index a55711bd05..97c0db0814 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/url.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/url.dart @@ -5,7 +5,7 @@ import 'builder.dart'; typedef URLTypeOptionContext = TypeOptionWidgetContext; -class URLTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser { +class URLTypeOptionWidgetDataParser extends TypeOptionDataParser { @override URLTypeOption fromBuffer(List buffer) { return URLTypeOption.fromBuffer(buffer); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart index 45dd63eb7f..b342101bc8 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -137,7 +137,7 @@ class _PropertyList extends StatelessWidget { } class _RowDetailCell extends StatelessWidget { - final GridCell gridCell; + final GridCellIdentifier gridCell; final GridCellBuilder cellBuilder; const _RowDetailCell({ required this.gridCell, From 29f2d863fff5e290274d95c03b0ce90d7c662434 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 16 Jul 2022 15:38:38 +0800 Subject: [PATCH 023/112] chore: renmae property & add documentation --- .../{block_service.dart => block_cache.dart} | 7 +- .../{cache.dart => cell_cache.dart} | 26 +++--- .../cell/cell_service/cell_data_loader.dart | 10 +-- .../cell_service/cell_data_persistence.dart | 25 +++--- .../grid/cell/cell_service/cell_service.dart | 28 +++--- .../cell/cell_service/context_builder.dart | 84 +++++++++--------- .../grid/cell/select_option_editor_bloc.dart | 2 +- .../grid/cell/select_option_service.dart | 10 +-- .../grid/field/field_editor_bloc.dart | 4 +- .../application/grid/field/field_service.dart | 14 +-- .../workspace/application/grid/grid_bloc.dart | 4 +- .../application/grid/grid_service.dart | 5 +- .../grid/row/row_action_sheet_bloc.dart | 2 +- .../application/grid/row/row_bloc.dart | 10 +-- .../application/grid/row/row_detail_bloc.dart | 8 +- .../application/grid/row/row_service.dart | 88 +++++++++++-------- .../plugins/grid/src/grid_page.dart | 4 +- .../grid/src/widgets/cell/cell_builder.dart | 6 +- .../grid/src/widgets/header/field_cell.dart | 2 +- .../grid/src/widgets/header/field_editor.dart | 2 +- .../grid/src/widgets/header/grid_header.dart | 2 +- .../grid/src/widgets/row/grid_row.dart | 10 +-- .../grid/src/widgets/row/row_detail.dart | 24 ++--- .../src/widgets/toolbar/grid_property.dart | 2 +- 24 files changed, 190 insertions(+), 189 deletions(-) rename frontend/app_flowy/lib/workspace/application/grid/block/{block_service.dart => block_cache.dart} (84%) rename frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/{cache.dart => cell_cache.dart} (67%) diff --git a/frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart b/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart similarity index 84% rename from frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart rename to frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart index 2a4c82bdd4..caf61e64b3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/block/block_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart @@ -6,21 +6,22 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'block_listener.dart'; +/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information class GridBlockCache { final String gridId; final GridBlock block; - late GridRowsCache _rowCache; + late GridRowCache _rowCache; late GridBlockListener _listener; List get rows => _rowCache.rows; - GridRowsCache get rowCache => _rowCache; + GridRowCache get rowCache => _rowCache; GridBlockCache({ required this.gridId, required this.block, required GridFieldCache fieldCache, }) { - _rowCache = GridRowsCache( + _rowCache = GridRowCache( gridId: gridId, block: block, notifier: GridRowCacheFieldNotifierImpl(fieldCache), diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_cache.dart similarity index 67% rename from frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_cache.dart index dd50e98cd5..1f14c7c54a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cache.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_cache.dart @@ -2,11 +2,9 @@ part of 'cell_service.dart'; typedef GridCellMap = LinkedHashMap; -class _GridCellCacheValue { - GridCellCacheKey key; +class GridCell { dynamic object; - _GridCellCacheValue({ - required this.key, + GridCell({ required this.object, }); } @@ -22,14 +20,16 @@ class GridCellCacheKey { }); } -/// GridCellsCache is used to cache cell data of each Grid. +/// GridCellCache is used to cache cell data of each block. /// We use GridCellCacheKey to index the cell in the cache. -class GridCellsCache { +/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid +/// for more information +class GridCellCache { final String gridId; - /// fieldId: {cacheKey: cacheData} + /// fieldId: {cacheKey: GridCell} final Map> _cellDataByFieldId = {}; - GridCellsCache({ + GridCellCache({ required this.gridId, }); @@ -37,14 +37,14 @@ class GridCellsCache { _cellDataByFieldId.remove(fieldId); } - void insert(T value) { - var map = _cellDataByFieldId[value.key.fieldId]; + void insert(GridCellCacheKey key, T value) { + var map = _cellDataByFieldId[key.fieldId]; if (map == null) { - _cellDataByFieldId[value.key.fieldId] = {}; - map = _cellDataByFieldId[value.key.fieldId]; + _cellDataByFieldId[key.fieldId] = {}; + map = _cellDataByFieldId[key.fieldId]; } - map![value.key.rowId] = value.object; + map![key.rowId] = value.object; } T? get(GridCellCacheKey key) { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart index dfbd7e197b..324c65c5f5 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart @@ -11,22 +11,18 @@ abstract class ICellDataParser { class GridCellDataLoader { final CellService service = CellService(); - final GridCellIdentifier gridCell; + final GridCellIdentifier cellId; final ICellDataParser parser; final bool reloadOnFieldChanged; GridCellDataLoader({ - required this.gridCell, + required this.cellId, required this.parser, this.reloadOnFieldChanged = false, }); Future loadData() { - final fut = service.getCell( - gridId: gridCell.gridId, - fieldId: gridCell.field.id, - rowId: gridCell.rowId, - ); + final fut = service.getCell(cellId: cellId); return fut.then( (result) => result.fold((Cell cell) { try { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart index 4eebda7839..4959adf3ed 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart @@ -7,21 +7,16 @@ abstract class IGridCellDataPersistence { } class CellDataPersistence implements IGridCellDataPersistence { - final GridCellIdentifier gridCell; + final GridCellIdentifier cellId; CellDataPersistence({ - required this.gridCell, + required this.cellId, }); final CellService _cellService = CellService(); @override Future> save(String data) async { - final fut = _cellService.updateCell( - gridId: gridCell.gridId, - fieldId: gridCell.field.id, - rowId: gridCell.rowId, - data: data, - ); + final fut = _cellService.updateCell(cellId: cellId, data: data); return fut.then((result) { return result.fold( @@ -38,14 +33,14 @@ class CalendarData with _$CalendarData { } class DateCellDataPersistence implements IGridCellDataPersistence { - final GridCellIdentifier gridCell; + final GridCellIdentifier cellId; DateCellDataPersistence({ - required this.gridCell, + required this.cellId, }); @override Future> save(CalendarData data) { - var payload = DateChangesetPayload.create()..cellIdentifier = _cellIdentifier(gridCell); + var payload = DateChangesetPayload.create()..cellIdentifier = _makeCellIdPayload(cellId); final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString(); payload.date = date; @@ -63,9 +58,9 @@ class DateCellDataPersistence implements IGridCellDataPersistence } } -CellIdentifierPayload _cellIdentifier(GridCellIdentifier gridCell) { +CellIdentifierPayload _makeCellIdPayload(GridCellIdentifier cellId) { return CellIdentifierPayload.create() - ..gridId = gridCell.gridId - ..fieldId = gridCell.field.id - ..rowId = gridCell.rowId; + ..gridId = cellId.gridId + ..fieldId = cellId.fieldId + ..rowId = cellId.rowId; } 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 2cf9536f2d..d9924d38bb 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 @@ -23,7 +23,7 @@ import 'cell_field_notifier.dart'; part 'cell_service.freezed.dart'; part 'cell_data_loader.dart'; part 'context_builder.dart'; -part 'cache.dart'; +part 'cell_cache.dart'; part 'cell_data_persistence.dart'; // key: rowId @@ -32,28 +32,24 @@ class CellService { CellService(); Future> updateCell({ - required String gridId, - required String fieldId, - required String rowId, + required GridCellIdentifier cellId, required String data, }) { final payload = CellChangeset.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId + ..gridId = cellId.gridId + ..fieldId = cellId.fieldId + ..rowId = cellId.rowId ..content = data; return GridEventUpdateCell(payload).send(); } Future> getCell({ - required String gridId, - required String fieldId, - required String rowId, + required GridCellIdentifier cellId, }) { final payload = CellIdentifierPayload.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId; + ..gridId = cellId.gridId + ..fieldId = cellId.fieldId + ..rowId = cellId.rowId; return GridEventGetCell(payload).send(); } } @@ -71,7 +67,11 @@ class GridCellIdentifier with _$GridCellIdentifier { // ignore: unused_element const GridCellIdentifier._(); + String get fieldId => field.id; + + FieldType get fieldType => field.fieldType; + ValueKey key() { - return ValueKey(rowId + field.id + "${field.fieldType}"); + return ValueKey(rowId + fieldId + "${field.fieldType}"); } } 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 0ec9e1753f..124835cf94 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 @@ -6,97 +6,99 @@ typedef GridDateCellController = IGridCellController typedef GridURLCellController = IGridCellController; class GridCellControllerBuilder { - final GridCellIdentifier _gridCell; - final GridCellsCache _cellCache; + final GridCellIdentifier _cellId; + final GridCellCache _cellCache; final GridFieldCache _fieldCache; - GridCellControllerBuilder( - {required GridCellIdentifier gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache}) - : _cellCache = cellCache, + GridCellControllerBuilder({ + required GridCellIdentifier cellId, + required GridCellCache cellCache, + required GridFieldCache fieldCache, + }) : _cellCache = cellCache, _fieldCache = fieldCache, - _gridCell = gridCell; + _cellId = cellId; IGridCellController build() { final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache)); - switch (_gridCell.field.fieldType) { + switch (_cellId.fieldType) { case FieldType.Checkbox: final cellDataLoader = GridCellDataLoader( - gridCell: _gridCell, + cellId: _cellId, parser: StringCellDataParser(), ); return GridCellController( - gridCell: _gridCell, + cellId: _cellId, cellCache: _cellCache, cellDataLoader: cellDataLoader, fieldNotifier: cellFieldNotifier, - cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + cellDataPersistence: CellDataPersistence(cellId: _cellId), ); case FieldType.DateTime: final cellDataLoader = GridCellDataLoader( - gridCell: _gridCell, + cellId: _cellId, parser: DateCellDataParser(), reloadOnFieldChanged: true, ); return GridDateCellController( - gridCell: _gridCell, + cellId: _cellId, cellCache: _cellCache, cellDataLoader: cellDataLoader, fieldNotifier: cellFieldNotifier, - cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell), + cellDataPersistence: DateCellDataPersistence(cellId: _cellId), ); case FieldType.Number: final cellDataLoader = GridCellDataLoader( - gridCell: _gridCell, + cellId: _cellId, parser: StringCellDataParser(), ); return GridCellController( - gridCell: _gridCell, + cellId: _cellId, cellCache: _cellCache, cellDataLoader: cellDataLoader, fieldNotifier: cellFieldNotifier, - cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + cellDataPersistence: CellDataPersistence(cellId: _cellId), ); case FieldType.RichText: final cellDataLoader = GridCellDataLoader( - gridCell: _gridCell, + cellId: _cellId, parser: StringCellDataParser(), ); return GridCellController( - gridCell: _gridCell, + cellId: _cellId, cellCache: _cellCache, cellDataLoader: cellDataLoader, fieldNotifier: cellFieldNotifier, - cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + cellDataPersistence: CellDataPersistence(cellId: _cellId), ); case FieldType.MultiSelect: case FieldType.SingleSelect: final cellDataLoader = GridCellDataLoader( - gridCell: _gridCell, + cellId: _cellId, parser: SelectOptionCellDataParser(), reloadOnFieldChanged: true, ); return GridSelectOptionCellController( - gridCell: _gridCell, + cellId: _cellId, cellCache: _cellCache, cellDataLoader: cellDataLoader, fieldNotifier: cellFieldNotifier, - cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + cellDataPersistence: CellDataPersistence(cellId: _cellId), ); case FieldType.URL: final cellDataLoader = GridCellDataLoader( - gridCell: _gridCell, + cellId: _cellId, parser: URLCellDataParser(), ); return GridURLCellController( - gridCell: _gridCell, + cellId: _cellId, cellCache: _cellCache, cellDataLoader: cellDataLoader, fieldNotifier: cellFieldNotifier, - cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + cellDataPersistence: CellDataPersistence(cellId: _cellId), ); } throw UnimplementedError; @@ -112,8 +114,8 @@ class GridCellControllerBuilder { /// // ignore: must_be_immutable class IGridCellController extends Equatable { - final GridCellIdentifier gridCell; - final GridCellsCache _cellsCache; + final GridCellIdentifier cellId; + final GridCellCache _cellsCache; final GridCellCacheKey _cacheKey; final FieldService _fieldService; final GridCellFieldNotifier _fieldNotifier; @@ -130,8 +132,8 @@ class IGridCellController extends Equatable { bool _isDispose = false; IGridCellController({ - required this.gridCell, - required GridCellsCache cellCache, + required this.cellId, + required GridCellCache cellCache, required GridCellFieldNotifier fieldNotifier, required GridCellDataLoader cellDataLoader, required IGridCellDataPersistence cellDataPersistence, @@ -139,29 +141,27 @@ class IGridCellController extends Equatable { _cellDataLoader = cellDataLoader, _cellDataPersistence = cellDataPersistence, _fieldNotifier = fieldNotifier, - _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), - _cacheKey = GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id); + _fieldService = FieldService(gridId: cellId.gridId, fieldId: cellId.field.id), + _cacheKey = GridCellCacheKey(rowId: cellId.rowId, fieldId: cellId.field.id); IGridCellController clone() { return IGridCellController( - gridCell: gridCell, + cellId: cellId, cellDataLoader: _cellDataLoader, cellCache: _cellsCache, fieldNotifier: _fieldNotifier, cellDataPersistence: _cellDataPersistence); } - String get gridId => gridCell.gridId; + String get gridId => cellId.gridId; - String get rowId => gridCell.rowId; + String get rowId => cellId.rowId; - String get cellId => gridCell.rowId + gridCell.field.id; + String get fieldId => cellId.field.id; - String get fieldId => gridCell.field.id; + Field get field => cellId.field; - Field get field => gridCell.field; - - FieldType get fieldType => gridCell.field.fieldType; + FieldType get fieldType => cellId.field.fieldType; VoidCallback? startListening({required void Function(T?) onCellChanged, VoidCallback? onCellFieldChanged}) { if (isListening) { @@ -177,7 +177,7 @@ class IGridCellController extends Equatable { /// user input: 12 /// cell display: $12 _cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey)); - _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); + _cellListener = CellListener(rowId: cellId.rowId, fieldId: cellId.field.id); /// 1.Listen on user edit event and load the new cell data if needed. _cellListener.start(onCellChanged: (result) { @@ -264,7 +264,7 @@ class IGridCellController extends Equatable { _loadDataOperation = Timer(const Duration(milliseconds: 10), () { _cellDataLoader.loadData().then((data) { _cellDataNotifier?.value = data; - _cellsCache.insert(_GridCellCacheValue(key: _cacheKey, object: data)); + _cellsCache.insert(_cacheKey, GridCell(object: data)); }); }); } @@ -287,7 +287,7 @@ class IGridCellController extends Equatable { } @override - List get props => [_cellsCache.get(_cacheKey) ?? "", cellId]; + List get props => [_cellsCache.get(_cacheKey) ?? "", cellId.rowId + cellId.field.id]; } class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart index b531955ab7..2daabe1a98 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart @@ -17,7 +17,7 @@ class SelectOptionCellEditorBloc extends Bloc( (event, emit) async { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart index 147b24d468..7b6fffa310 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -7,12 +7,12 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart'; import 'cell_service/cell_service.dart'; class SelectOptionService { - final GridCellIdentifier gridCell; - SelectOptionService({required this.gridCell}); + final GridCellIdentifier cellId; + SelectOptionService({required this.cellId}); - String get gridId => gridCell.gridId; - String get fieldId => gridCell.field.id; - String get rowId => gridCell.rowId; + String get gridId => cellId.gridId; + String get fieldId => cellId.field.id; + String get rowId => cellId.rowId; Future> create({required String name}) { return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then( diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart index 2815d5519d..3779b4b418 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart @@ -9,7 +9,7 @@ class FieldEditorBloc extends Bloc { FieldEditorBloc({ required String gridId, required String fieldName, - required IFieldContextLoader fieldContextLoader, + required IFieldTypeOptionLoader fieldContextLoader, }) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) { on( (event, emit) async { @@ -53,7 +53,7 @@ class FieldEditorState with _$FieldEditorState { required Option fieldContext, }) = _FieldEditorState; - factory FieldEditorState.initial(String gridId, String fieldName, IFieldContextLoader loader) => FieldEditorState( + factory FieldEditorState.initial(String gridId, String fieldName, IFieldTypeOptionLoader loader) => FieldEditorState( gridId: gridId, fieldContext: none(), errorText: '', diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index 879cf599dd..e8e09a725b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -141,7 +141,7 @@ class GridFieldCellContext with _$GridFieldCellContext { }) = _GridFieldCellContext; } -abstract class IFieldContextLoader { +abstract class IFieldTypeOptionLoader { String get gridId; Future> load(); @@ -155,10 +155,10 @@ abstract class IFieldContextLoader { } } -class NewFieldContextLoader extends IFieldContextLoader { +class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader { @override final String gridId; - NewFieldContextLoader({ + NewFieldTypeOptionLoader({ required this.gridId, }); @@ -172,12 +172,12 @@ class NewFieldContextLoader extends IFieldContextLoader { } } -class FieldContextLoader extends IFieldContextLoader { +class FieldTypeOptionLoader extends IFieldTypeOptionLoader { @override final String gridId; final Field field; - FieldContextLoader({ + FieldTypeOptionLoader({ required this.gridId, required this.field, }); @@ -195,14 +195,14 @@ class FieldContextLoader extends IFieldContextLoader { class GridFieldContext { final String gridId; - final IFieldContextLoader _loader; + final IFieldTypeOptionLoader _loader; late FieldTypeOptionData _data; ValueNotifier? _fieldNotifier; GridFieldContext({ required this.gridId, - required IFieldContextLoader loader, + required IFieldTypeOptionLoader loader, }) : _loader = loader; Future> loadData() async { 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 3098ca1609..7f120cf3d8 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'block/block_service.dart'; +import 'block/block_cache.dart'; import 'grid_service.dart'; import 'row/row_service.dart'; import 'dart:collection'; @@ -68,7 +68,7 @@ class GridBloc extends Bloc { return super.close(); } - GridRowsCache? getRowCache(String blockId, String rowId) { + GridRowCache? getRowCache(String blockId, String rowId) { final GridBlockCache? blockCache = _blocks[blockId]; return blockCache?.rowCache; } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index 0e176df919..4e742f9f42 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -61,13 +61,12 @@ typedef FieldsCallback = void Function(List); class GridFieldCache { final String gridId; - late final GridFieldsListener _fieldListener; + final GridFieldsListener _fieldListener; FieldsNotifier? _fieldNotifier = FieldsNotifier(); final Map _fieldsCallbackMap = {}; final Map _changesetCallbackMap = {}; - GridFieldCache({required this.gridId}) { - _fieldListener = GridFieldsListener(gridId: gridId); + GridFieldCache({required this.gridId}) : _fieldListener = GridFieldsListener(gridId: gridId) { _fieldListener.start(onFieldsChanged: (result) { result.fold( (changeset) { diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart index 8754917223..7d570c9412 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart @@ -15,7 +15,7 @@ class RowActionSheetBloc extends Bloc : _rowService = RowService( gridId: rowData.gridId, blockId: rowData.blockId, - rowId: rowData.rowId, + rowId: rowData.id, ), super(RowActionSheetState.initial(rowData)) { on( diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 5af7c02a5d..69d2a95059 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart @@ -11,19 +11,19 @@ part 'row_bloc.freezed.dart'; class RowBloc extends Bloc { final RowService _rowService; - final GridRowsCache _rowCache; + final GridRowCache _rowCache; void Function()? _rowListenFn; RowBloc({ required GridRow rowData, - required GridRowsCache rowCache, + required GridRowCache rowCache, }) : _rowService = RowService( gridId: rowData.gridId, blockId: rowData.blockId, - rowId: rowData.rowId, + rowId: rowData.id, ), _rowCache = rowCache, - super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) { + super(RowState.initial(rowData, rowCache.loadGridCells(rowData.id))) { on( (event, emit) async { await event.map( @@ -58,7 +58,7 @@ class RowBloc extends Bloc { Future _startListening() async { _rowListenFn = _rowCache.addListener( - rowId: state.rowData.rowId, + rowId: state.rowData.id, onCellUpdated: (cellDatas, reason) => add(RowEvent.didReceiveCellDatas(cellDatas, reason)), listenWhen: () => !isClosed, ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart index 405c0ef523..b75caf32cf 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart @@ -8,12 +8,12 @@ part 'row_detail_bloc.freezed.dart'; class RowDetailBloc extends Bloc { final GridRow rowData; - final GridRowsCache _rowCache; + final GridRowCache _rowCache; void Function()? _rowListenFn; RowDetailBloc({ required this.rowData, - required GridRowsCache rowCache, + required GridRowCache rowCache, }) : _rowCache = rowCache, super(RowDetailState.initial()) { on( @@ -41,14 +41,14 @@ class RowDetailBloc extends Bloc { Future _startListening() async { _rowListenFn = _rowCache.addListener( - rowId: rowData.rowId, + rowId: rowData.id, onCellUpdated: (cellDatas, reason) => add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())), listenWhen: () => !isClosed, ); } Future _loadCellData() async { - final cellDataMap = _rowCache.loadGridCells(rowData.rowId); + final cellDataMap = _rowCache.loadGridCells(rowData.id); if (!isClosed) { add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList())); } 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 df8a068598..7296fd51a8 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 @@ -21,35 +21,46 @@ abstract class GridRowCacheFieldNotifier { void dispose(); } -class GridRowsCache { +/// Cache the rows in memory +/// Insert / delete / update row +/// +/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information. + +class GridRowCache { final String gridId; final GridBlock block; - final _Notifier _notifier; + + /// _rows containers the current block's rows + /// Use List to reverse the order of the GridRow. List _rows = []; + + /// Use Map for faster access the raw row data. final HashMap _rowByRowId; + + final GridCellCache _cellCache; final GridRowCacheFieldNotifier _fieldNotifier; - final GridCellsCache _cellCache; + final _GridRowChangesetNotifier _rowChangeReasonNotifier; - List get rows => _rows; - GridCellsCache get cellCache => _cellCache; + UnmodifiableListView get rows => UnmodifiableListView(_rows); + GridCellCache get cellCache => _cellCache; - GridRowsCache({ + GridRowCache({ required this.gridId, required this.block, required GridRowCacheFieldNotifier notifier, - }) : _cellCache = GridCellsCache(gridId: gridId), + }) : _cellCache = GridCellCache(gridId: gridId), _rowByRowId = HashMap(), - _notifier = _Notifier(), + _rowChangeReasonNotifier = _GridRowChangesetNotifier(), _fieldNotifier = notifier { // - notifier.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange())); + notifier.onFieldsChanged(() => _rowChangeReasonNotifier.receive(const GridRowChangeReason.fieldDidChange())); notifier.onFieldChanged((field) => _cellCache.remove(field.id)); _rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList(); } Future dispose() async { _fieldNotifier.dispose(); - _notifier.dispose(); + _rowChangeReasonNotifier.dispose(); await _cellCache.dispose(); } @@ -73,14 +84,15 @@ class GridRowsCache { final Map deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId}; _rows.asMap().forEach((index, row) { - if (deletedRowByRowId[row.rowId] == null) { + if (deletedRowByRowId[row.id] == null) { newRows.add(row); } else { + _rowByRowId.remove(row.id); deletedIndex.add(DeletedIndex(index: index, row: row)); } }); _rows = newRows; - _notifier.receive(GridRowChangeReason.delete(deletedIndex)); + _rowChangeReasonNotifier.receive(GridRowChangeReason.delete(deletedIndex)); } void _insertRows(List insertRows) { @@ -89,17 +101,16 @@ class GridRowsCache { } InsertedIndexs insertIndexs = []; - final List newRows = _rows; for (final insertRow in insertRows) { final insertIndex = InsertedIndex( index: insertRow.index, rowId: insertRow.rowId, ); insertIndexs.add(insertIndex); - newRows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble()))); + _rows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble()))); } - _notifier.receive(GridRowChangeReason.insert(insertIndexs)); + _rowChangeReasonNotifier.receive(GridRowChangeReason.insert(insertIndexs)); } void _updateRows(List updatedRows) { @@ -108,20 +119,19 @@ class GridRowsCache { } final UpdatedIndexs updatedIndexs = UpdatedIndexs(); - final List newRows = _rows; for (final updatedRow in updatedRows) { final rowId = updatedRow.rowId; - final index = newRows.indexWhere((row) => row.rowId == rowId); + final index = _rows.indexWhere((row) => row.id == rowId); if (index != -1) { _rowByRowId[rowId] = updatedRow.row; - newRows.removeAt(index); - newRows.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble())); + _rows.removeAt(index); + _rows.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble())); updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId); } } - _notifier.receive(GridRowChangeReason.update(updatedIndexs)); + _rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs)); } void _hideRows(List hideRows) {} @@ -131,8 +141,8 @@ class GridRowsCache { void onRowsChanged( void Function(GridRowChangeReason) onRowChanged, ) { - _notifier.addListener(() { - onRowChanged(_notifier._reason); + _rowChangeReasonNotifier.addListener(() { + onRowChanged(_rowChangeReasonNotifier.reason); }); } @@ -151,12 +161,12 @@ class GridRowsCache { final row = _rowByRowId[rowId]; if (row != null) { final GridCellMap cellDataMap = _makeGridCells(rowId, row); - onCellUpdated(cellDataMap, _notifier._reason); + onCellUpdated(cellDataMap, _rowChangeReasonNotifier.reason); } } } - _notifier._reason.whenOrNull( + _rowChangeReasonNotifier.reason.whenOrNull( update: (indexs) { if (indexs[rowId] != null) notifyUpdate(); }, @@ -164,12 +174,12 @@ class GridRowsCache { ); } - _notifier.addListener(listenrHandler); + _rowChangeReasonNotifier.addListener(listenrHandler); return listenrHandler; } void removeRowListener(VoidCallback callback) { - _notifier.removeListener(callback); + _rowChangeReasonNotifier.removeListener(callback); } GridCellMap loadGridCells(String rowId) { @@ -215,19 +225,19 @@ class GridRowsCache { updatedRow.freeze(); _rowByRowId[updatedRow.id] = updatedRow; - final index = _rows.indexWhere((gridRow) => gridRow.rowId == updatedRow.id); + final index = _rows.indexWhere((gridRow) => gridRow.id == updatedRow.id); if (index != -1) { // update the corresponding row in _rows if they are not the same - if (_rows[index].data != updatedRow) { - final row = _rows.removeAt(index).copyWith(data: updatedRow); + if (_rows[index].rawRow != updatedRow) { + final row = _rows.removeAt(index).copyWith(rawRow: updatedRow); _rows.insert(index, row); // Calculate the update index final UpdatedIndexs updatedIndexs = UpdatedIndexs(); - updatedIndexs[row.rowId] = UpdatedIndex(index: index, rowId: row.rowId); + updatedIndexs[row.id] = UpdatedIndex(index: index, rowId: row.id); // - _notifier.receive(GridRowChangeReason.update(updatedIndexs)); + _rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs)); } } } @@ -237,19 +247,19 @@ class GridRowsCache { gridId: gridId, blockId: block.id, fields: _fieldNotifier.fields, - rowId: rowId, + id: rowId, height: rowHeight, ); } } -class _Notifier extends ChangeNotifier { - GridRowChangeReason _reason = const InitialListState(); +class _GridRowChangesetNotifier extends ChangeNotifier { + GridRowChangeReason reason = const InitialListState(); - _Notifier(); + _GridRowChangesetNotifier(); - void receive(GridRowChangeReason reason) { - _reason = reason; + void receive(GridRowChangeReason newReason) { + reason = newReason; reason.map( insert: (_) => notifyListeners(), delete: (_) => notifyListeners(), @@ -319,10 +329,10 @@ class GridRow with _$GridRow { const factory GridRow({ required String gridId, required String blockId, - required String rowId, + required String id, required UnmodifiableListView fields, required double height, - Row? data, + Row? rawRow, }) = _GridRow; } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index 6b980e468f..d7d2999dd1 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -227,7 +227,7 @@ class _GridRowsState extends State<_GridRows> { GridRow rowData, Animation animation, ) { - final rowCache = context.read().getRowCache(rowData.blockId, rowData.rowId); + final rowCache = context.read().getRowCache(rowData.blockId, rowData.id); final fieldCache = context.read().fieldCache; if (rowCache != null) { return SizeTransition( @@ -236,7 +236,7 @@ class _GridRowsState extends State<_GridRows> { rowData: rowData, rowCache: rowCache, fieldCache: fieldCache, - key: ValueKey(rowData.rowId), + key: ValueKey(rowData.id), ), ); } else { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index 1fd4c726be..10efcbb0de 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -14,7 +14,7 @@ import 'text_cell.dart'; import 'url_cell/url_cell.dart'; class GridCellBuilder { - final GridCellsCache cellCache; + final GridCellCache cellCache; final GridFieldCache fieldCache; GridCellBuilder({ required this.cellCache, @@ -23,12 +23,12 @@ class GridCellBuilder { GridCellWidget build(GridCellIdentifier cell, {GridCellStyle? style}) { final cellControllerBuilder = GridCellControllerBuilder( - gridCell: cell, + cellId: cell, cellCache: cellCache, fieldCache: fieldCache, ); final key = cell.key(); - switch (cell.field.fieldType) { + switch (cell.fieldType) { case FieldType.Checkbox: return CheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key); case FieldType.DateTime: diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index 9237c71be0..2ace435bf3 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -65,7 +65,7 @@ class GridFieldCell extends StatelessWidget { FieldEditor( gridId: state.gridId, fieldName: field.name, - contextLoader: FieldContextLoader( + contextLoader: FieldTypeOptionLoader( gridId: state.gridId, field: field, ), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart index 148727752c..d3345b5b6f 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart @@ -14,7 +14,7 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate { final String gridId; final String fieldName; - final IFieldContextLoader contextLoader; + final IFieldTypeOptionLoader contextLoader; const FieldEditor({ required this.gridId, required this.fieldName, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index cc968d15cb..c63bd37d2e 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -151,7 +151,7 @@ class CreateFieldButton extends StatelessWidget { onTap: () => FieldEditor( gridId: gridId, fieldName: "", - contextLoader: NewFieldContextLoader(gridId: gridId), + contextLoader: NewFieldTypeOptionLoader(gridId: gridId), ).show(context), leftIcon: svgWidget("home/add"), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart index 0e1c6a0041..b0c1cd2ea0 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart @@ -16,7 +16,7 @@ import 'row_detail.dart'; class GridRowWidget extends StatefulWidget { final GridRow rowData; - final GridRowsCache rowCache; + final GridRowCache rowCache; final GridCellBuilder cellBuilder; GridRowWidget({ @@ -183,12 +183,12 @@ class _RowCells extends StatelessWidget { List _makeCells(BuildContext context, GridCellMap gridCellMap) { return gridCellMap.values.map( - (gridCell) { - final GridCellWidget child = builder.build(gridCell); + (cellId) { + final GridCellWidget child = builder.build(cellId); accessoryBuilder(GridCellAccessoryBuildContext buildContext) { final builder = child.accessoryBuilder; List accessories = []; - if (gridCell.field.isPrimary) { + if (cellId.field.isPrimary) { accessories.add(PrimaryCellAccessory( onTapCallback: onExpand, isCellEditing: buildContext.isCellEditing, @@ -202,7 +202,7 @@ class _RowCells extends StatelessWidget { } return CellContainer( - width: gridCell.field.width.toDouble(), + width: cellId.field.width.toDouble(), child: child, rowStateNotifier: Provider.of(context, listen: false), accessoryBuilder: accessoryBuilder, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart index b342101bc8..b10eeecb2c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -22,7 +22,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate { final GridRow rowData; - final GridRowsCache rowCache; + final GridRowCache rowCache; final GridCellBuilder cellBuilder; const RowDetailPage({ @@ -122,7 +122,7 @@ class _PropertyList extends StatelessWidget { itemCount: state.gridCells.length, itemBuilder: (BuildContext context, int index) { return _RowDetailCell( - gridCell: state.gridCells[index], + cellId: state.gridCells[index], cellBuilder: cellBuilder, ); }, @@ -137,10 +137,10 @@ class _PropertyList extends StatelessWidget { } class _RowDetailCell extends StatelessWidget { - final GridCellIdentifier gridCell; + final GridCellIdentifier cellId; final GridCellBuilder cellBuilder; const _RowDetailCell({ - required this.gridCell, + required this.cellId, required this.cellBuilder, Key? key, }) : super(key: key); @@ -148,8 +148,8 @@ class _RowDetailCell extends StatelessWidget { @override Widget build(BuildContext context) { final theme = context.watch(); - final style = _customCellStyle(theme, gridCell.field.fieldType); - final cell = cellBuilder.build(gridCell, style: style); + final style = _customCellStyle(theme, cellId.fieldType); + final cell = cellBuilder.build(cellId, style: style); final gesture = GestureDetector( behavior: HitTestBehavior.translucent, @@ -169,7 +169,7 @@ class _RowDetailCell extends StatelessWidget { children: [ SizedBox( width: 150, - child: FieldCellButton(field: gridCell.field, onTap: () => _showFieldEditor(context)), + child: FieldCellButton(field: cellId.field, onTap: () => _showFieldEditor(context)), ), const HSpace(10), Expanded(child: gesture), @@ -181,11 +181,11 @@ class _RowDetailCell extends StatelessWidget { void _showFieldEditor(BuildContext context) { FieldEditor( - gridId: gridCell.gridId, - fieldName: gridCell.field.name, - contextLoader: FieldContextLoader( - gridId: gridCell.gridId, - field: gridCell.field, + gridId: cellId.gridId, + fieldName: cellId.field.name, + contextLoader: FieldTypeOptionLoader( + gridId: cellId.gridId, + field: cellId.field, ), ).show(context); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index e19c90ecea..ac28ce9dbc 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -116,7 +116,7 @@ class _GridPropertyCell extends StatelessWidget { FieldEditor( gridId: gridId, fieldName: field.name, - contextLoader: FieldContextLoader(gridId: gridId, field: field), + contextLoader: FieldTypeOptionLoader(gridId: gridId, field: field), ).show(context, anchorDirection: AnchorDirection.bottomRight); }, ); From 27ce5b8fe92933e21e5c608d09a25da0e04aba7a Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 16 Jul 2022 19:59:00 +0800 Subject: [PATCH 024/112] refactor: field editor bloc --- .../grid/field/field_editor_bloc.dart | 35 ++++++++++++------- .../application/grid/field/field_service.dart | 23 +++++------- .../field/field_type_option_edit_bloc.dart | 14 ++++---- .../type_option/multi_select_type_option.dart | 8 ++--- .../single_select_type_option.dart | 4 +-- .../type_option/type_option_service.dart | 14 ++++---- .../grid/src/widgets/header/field_cell.dart | 2 +- .../grid/src/widgets/header/field_editor.dart | 15 ++++---- .../header/field_type_option_editor.dart | 13 +++---- .../grid/src/widgets/header/grid_header.dart | 2 +- .../widgets/header/type_option/builder.dart | 22 ++++++------ .../grid/src/widgets/row/row_detail.dart | 2 +- .../src/widgets/toolbar/grid_property.dart | 2 +- 13 files changed, 82 insertions(+), 74 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart index 3779b4b418..19da67e557 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart @@ -1,3 +1,4 @@ +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; @@ -6,27 +7,32 @@ import 'package:dartz/dartz.dart'; part 'field_editor_bloc.freezed.dart'; class FieldEditorBloc extends Bloc { + final TypeOptionDataController dataController; + FieldEditorBloc({ required String gridId, required String fieldName, - required IFieldTypeOptionLoader fieldContextLoader, - }) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) { + required IFieldTypeOptionLoader loader, + }) : dataController = TypeOptionDataController(gridId: gridId, loader: loader), + super(FieldEditorState.initial(gridId, fieldName)) { on( (event, emit) async { await event.when( initial: () async { - final fieldContext = GridFieldContext(gridId: gridId, loader: fieldContextLoader); - await fieldContext.loadData().then((result) { - result.fold( - (l) => emit(state.copyWith(fieldContext: Some(fieldContext), name: fieldContext.field.name)), - (r) => null, - ); + dataController.addFieldListener((field) { + if (!isClosed) { + add(FieldEditorEvent.didReceiveFieldChanged(field)); + } }); + await dataController.loadData(); }, updateName: (name) { - state.fieldContext.fold(() => null, (fieldContext) => fieldContext.fieldName = name); + dataController.fieldName = name; emit(state.copyWith(name: name)); }, + didReceiveFieldChanged: (Field field) { + emit(state.copyWith(field: Some(field))); + }, ); }, ); @@ -42,6 +48,7 @@ class FieldEditorBloc extends Bloc { class FieldEditorEvent with _$FieldEditorEvent { const factory FieldEditorEvent.initial() = _InitialField; const factory FieldEditorEvent.updateName(String name) = _UpdateName; + const factory FieldEditorEvent.didReceiveFieldChanged(Field field) = _DidReceiveFieldChanged; } @freezed @@ -50,13 +57,17 @@ class FieldEditorState with _$FieldEditorState { required String gridId, required String errorText, required String name, - required Option fieldContext, + required Option field, }) = _FieldEditorState; - factory FieldEditorState.initial(String gridId, String fieldName, IFieldTypeOptionLoader loader) => FieldEditorState( + factory FieldEditorState.initial( + String gridId, + String fieldName, + ) => + FieldEditorState( gridId: gridId, - fieldContext: none(), errorText: '', + field: none(), name: fieldName, ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index e8e09a725b..de5b6adcb0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -1,4 +1,5 @@ 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'; @@ -193,14 +194,14 @@ class FieldTypeOptionLoader extends IFieldTypeOptionLoader { } } -class GridFieldContext { +class TypeOptionDataController { final String gridId; final IFieldTypeOptionLoader _loader; late FieldTypeOptionData _data; - ValueNotifier? _fieldNotifier; + final PublishNotifier _fieldNotifier = PublishNotifier(); - GridFieldContext({ + TypeOptionDataController({ required this.gridId, required IFieldTypeOptionLoader loader, }) : _loader = loader; @@ -211,13 +212,7 @@ class GridFieldContext { (data) { data.freeze(); _data = data; - - if (_fieldNotifier == null) { - _fieldNotifier = ValueNotifier(data.field_2); - } else { - _fieldNotifier?.value = data.field_2; - } - + _fieldNotifier.value = data.field_2; return left(unit); }, (err) { @@ -260,9 +255,7 @@ class GridFieldContext { } }); - if (_data.field_2 != _fieldNotifier?.value) { - _fieldNotifier?.value = _data.field_2; - } + _fieldNotifier.value = _data.field_2; FieldService.insertField( gridId: gridId, @@ -292,11 +285,11 @@ class GridFieldContext { callback(field); } - _fieldNotifier?.addListener(listener); + _fieldNotifier.addListener(listener); return listener; } void removeFieldListener(void Function() listener) { - _fieldNotifier?.removeListener(listener); + _fieldNotifier.removeListener(listener); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart index c92ad41d56..b9407ac2ad 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart @@ -8,17 +8,17 @@ import 'field_service.dart'; part 'field_type_option_edit_bloc.freezed.dart'; class FieldTypeOptionEditBloc extends Bloc { - final GridFieldContext _fieldContext; + final TypeOptionDataController _dataController; void Function()? _fieldListenFn; - FieldTypeOptionEditBloc(GridFieldContext fieldContext) - : _fieldContext = fieldContext, - super(FieldTypeOptionEditState.initial(fieldContext)) { + FieldTypeOptionEditBloc(TypeOptionDataController dataController) + : _dataController = dataController, + super(FieldTypeOptionEditState.initial(dataController)) { on( (event, emit) async { event.when( initial: () { - _fieldListenFn = fieldContext.addFieldListener((field) { + _fieldListenFn = dataController.addFieldListener((field) { add(FieldTypeOptionEditEvent.didReceiveFieldUpdated(field)); }); }, @@ -33,7 +33,7 @@ class FieldTypeOptionEditBloc extends Bloc close() async { if (_fieldListenFn != null) { - _fieldContext.removeFieldListener(_fieldListenFn!); + _dataController.removeFieldListener(_fieldListenFn!); } return super.close(); } @@ -51,7 +51,7 @@ class FieldTypeOptionEditState with _$FieldTypeOptionEditState { required Field field, }) = _FieldTypeOptionEditState; - factory FieldTypeOptionEditState.initial(GridFieldContext fieldContext) => FieldTypeOptionEditState( + factory FieldTypeOptionEditState.initial(TypeOptionDataController fieldContext) => FieldTypeOptionEditState( field: fieldContext.field, ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart index eae1765396..0d9d75d4c7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart @@ -13,12 +13,12 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext Function(SelectOption) get deleteOption { diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart index 16e686fb44..b2b4581d96 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart @@ -13,12 +13,12 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext Function(SelectOption) get deleteOption { diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart index 05ca9e9aa1..c7c86ae661 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart @@ -39,30 +39,30 @@ abstract class TypeOptionDataParser { class TypeOptionWidgetContext { T? _typeOptionObject; - final GridFieldContext _fieldContext; + final TypeOptionDataController _dataController; final TypeOptionDataParser dataParser; TypeOptionWidgetContext({ required this.dataParser, - required GridFieldContext fieldContext, - }) : _fieldContext = fieldContext; + required TypeOptionDataController dataController, + }) : _dataController = dataController; - String get gridId => _fieldContext.gridId; + String get gridId => _dataController.gridId; - Field get field => _fieldContext.field; + Field get field => _dataController.field; T get typeOption { if (_typeOptionObject != null) { return _typeOptionObject!; } - final T object = dataParser.fromBuffer(_fieldContext.typeOptionData); + final T object = dataParser.fromBuffer(_dataController.typeOptionData); _typeOptionObject = object; return object; } set typeOption(T typeOption) { - _fieldContext.typeOptionData = typeOption.writeToBuffer(); + _dataController.typeOptionData = typeOption.writeToBuffer(); _typeOptionObject = typeOption; } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index 2ace435bf3..266ec5a619 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -65,7 +65,7 @@ class GridFieldCell extends StatelessWidget { FieldEditor( gridId: state.gridId, fieldName: field.name, - contextLoader: FieldTypeOptionLoader( + typeOptionLoader: FieldTypeOptionLoader( gridId: state.gridId, field: field, ), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart index d3345b5b6f..3a857a9fb4 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart @@ -14,11 +14,11 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate { final String gridId; final String fieldName; - final IFieldTypeOptionLoader contextLoader; + final IFieldTypeOptionLoader typeOptionLoader; const FieldEditor({ required this.gridId, required this.fieldName, - required this.contextLoader, + required this.typeOptionLoader, Key? key, }) : super(key: key); @@ -28,7 +28,7 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate { create: (context) => FieldEditorBloc( gridId: gridId, fieldName: fieldName, - fieldContextLoader: contextLoader, + loader: typeOptionLoader, )..add(const FieldEditorEvent.initial()), child: BlocBuilder( buildWhen: (p, c) => false, @@ -80,11 +80,14 @@ class _FieldTypeOptionCell extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder( - buildWhen: (p, c) => p.fieldContext != c.fieldContext, + buildWhen: (p, c) => p.field != c.field, builder: (context, state) { - return state.fieldContext.fold( + return state.field.fold( () => const SizedBox(), - (fieldContext) => FieldTypeOptionEditor(fieldContext: fieldContext), + (fieldContext) { + final dataController = context.read().dataController; + return FieldTypeOptionEditor(dataController: dataController); + }, ); }, ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart index bca9b8e2f7..60592d1032 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart @@ -22,10 +22,10 @@ typedef SwitchToFieldCallback = Future> ); class FieldTypeOptionEditor extends StatefulWidget { - final GridFieldContext fieldContext; + final TypeOptionDataController dataController; const FieldTypeOptionEditor({ - required this.fieldContext, + required this.dataController, Key? key, }) : super(key: key); @@ -39,10 +39,11 @@ class _FieldTypeOptionEditorState extends State { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => FieldTypeOptionEditBloc(widget.fieldContext)..add(const FieldTypeOptionEditEvent.initial()), + create: (context) => + FieldTypeOptionEditBloc(widget.dataController)..add(const FieldTypeOptionEditEvent.initial()), child: BlocBuilder( builder: (context, state) { - List children = [_switchFieldTypeButton(context, widget.fieldContext.field)]; + List children = [_switchFieldTypeButton(context, widget.dataController.field)]; final typeOptionWidget = _typeOptionWidget(context: context, state: state); if (typeOptionWidget != null) { @@ -68,7 +69,7 @@ class _FieldTypeOptionEditorState extends State { hoverColor: theme.hover, onTap: () { final list = FieldTypeList(onSelectField: (newFieldType) { - widget.fieldContext.switchToField(newFieldType); + widget.dataController.switchToField(newFieldType); }); _showOverlay(context, list); }, @@ -89,7 +90,7 @@ class _FieldTypeOptionEditorState extends State { return makeTypeOptionWidget( context: context, - fieldContext: widget.fieldContext, + dataController: widget.dataController, overlayDelegate: overlayDelegate, ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index c63bd37d2e..2240d7f6aa 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -151,7 +151,7 @@ class CreateFieldButton extends StatelessWidget { onTap: () => FieldEditor( gridId: gridId, fieldName: "", - contextLoader: NewFieldTypeOptionLoader(gridId: gridId), + typeOptionLoader: NewFieldTypeOptionLoader(gridId: gridId), ).show(context), leftIcon: svgWidget("home/add"), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart index f63edbac14..63fa761d98 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/builder.dart @@ -36,27 +36,27 @@ abstract class TypeOptionWidgetBuilder { Widget? makeTypeOptionWidget({ required BuildContext context, - required GridFieldContext fieldContext, + required TypeOptionDataController dataController, required TypeOptionOverlayDelegate overlayDelegate, }) { - final builder = makeTypeOptionWidgetBuilder(fieldContext, overlayDelegate); + final builder = makeTypeOptionWidgetBuilder(dataController, overlayDelegate); return builder.build(context); } TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( - GridFieldContext fieldContext, + TypeOptionDataController dataController, TypeOptionOverlayDelegate overlayDelegate, ) { - switch (fieldContext.field.fieldType) { + switch (dataController.field.fieldType) { case FieldType.Checkbox: final context = CheckboxTypeOptionContext( - fieldContext: fieldContext, + dataController: dataController, dataParser: CheckboxTypeOptionWidgetDataParser(), ); return CheckboxTypeOptionWidgetBuilder(context); case FieldType.DateTime: final context = DateTypeOptionContext( - fieldContext: fieldContext, + dataController: dataController, dataParser: DateTypeOptionDataParser(), ); return DateTypeOptionWidgetBuilder( @@ -65,7 +65,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( ); case FieldType.SingleSelect: final context = SingleSelectTypeOptionContext( - fieldContext: fieldContext, + fieldContext: dataController, dataBuilder: SingleSelectTypeOptionWidgetDataParser(), ); return SingleSelectTypeOptionWidgetBuilder( @@ -74,7 +74,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( ); case FieldType.MultiSelect: final context = MultiSelectTypeOptionContext( - fieldContext: fieldContext, + dataController: dataController, dataBuilder: MultiSelectTypeOptionWidgetDataParser(), ); return MultiSelectTypeOptionWidgetBuilder( @@ -83,7 +83,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( ); case FieldType.Number: final context = NumberTypeOptionContext( - fieldContext: fieldContext, + dataController: dataController, dataParser: NumberTypeOptionWidgetDataParser(), ); return NumberTypeOptionWidgetBuilder( @@ -92,14 +92,14 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder( ); case FieldType.RichText: final context = RichTextTypeOptionContext( - fieldContext: fieldContext, + dataController: dataController, dataParser: RichTextTypeOptionWidgetDataParser(), ); return RichTextTypeOptionWidgetBuilder(context); case FieldType.URL: final context = URLTypeOptionContext( - fieldContext: fieldContext, + dataController: dataController, dataParser: URLTypeOptionWidgetDataParser(), ); return URLTypeOptionWidgetBuilder(context); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart index b10eeecb2c..4449ea6770 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -183,7 +183,7 @@ class _RowDetailCell extends StatelessWidget { FieldEditor( gridId: cellId.gridId, fieldName: cellId.field.name, - contextLoader: FieldTypeOptionLoader( + typeOptionLoader: FieldTypeOptionLoader( gridId: cellId.gridId, field: cellId.field, ), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index ac28ce9dbc..99d70e93c7 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -116,7 +116,7 @@ class _GridPropertyCell extends StatelessWidget { FieldEditor( gridId: gridId, fieldName: field.name, - contextLoader: FieldTypeOptionLoader(gridId: gridId, field: field), + typeOptionLoader: FieldTypeOptionLoader(gridId: gridId, field: field), ).show(context, anchorDirection: AnchorDirection.bottomRight); }, ); From 807341448549d674af385151c3bd08a84b2284be Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Jul 2022 11:29:02 +0800 Subject: [PATCH 025/112] refactor: rename struct & add documentation --- .../application/grid/block/block_cache.dart | 2 +- .../workspace/application/grid/grid_bloc.dart | 23 ++++++----- .../application/grid/grid_service.dart | 6 +-- .../grid/row/row_action_sheet_bloc.dart | 6 +-- .../application/grid/row/row_bloc.dart | 18 ++++----- .../application/grid/row/row_detail_bloc.dart | 8 ++-- .../application/grid/row/row_service.dart | 40 +++++++++---------- .../plugins/grid/src/grid_page.dart | 14 +++---- .../grid/src/widgets/row/grid_row.dart | 10 ++--- .../src/widgets/row/row_action_sheet.dart | 2 +- .../grid/src/widgets/row/row_detail.dart | 6 +-- .../flowy-grid/src/entities/block_entities.rs | 39 +++++++----------- .../flowy-grid/src/entities/field_entities.rs | 26 ++++++------ .../flowy-grid/src/entities/grid_entities.rs | 4 +- .../flowy-grid/src/services/block_manager.rs | 13 +++--- .../src/services/block_revision_editor.rs | 10 ++--- .../flowy-grid/src/services/grid_editor.rs | 20 +++++----- .../flowy-grid/src/services/row/row_loader.rs | 11 ++--- .../tests/grid/block_test/script.rs | 4 +- .../flowy-grid/tests/grid/grid_editor.rs | 2 +- 20 files changed, 127 insertions(+), 137 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart b/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart index caf61e64b3..9afdf17be6 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart @@ -13,7 +13,7 @@ class GridBlockCache { late GridRowCache _rowCache; late GridBlockListener _listener; - List get rows => _rowCache.rows; + List get rows => _rowCache.rows; GridRowCache get rowCache => _rowCache; GridBlockCache({ 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 7f120cf3d8..aaf47d8fc9 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -22,8 +22,8 @@ class GridBloc extends Bloc { // key: the block id final LinkedHashMap _blocks; - List get rows { - final List rows = []; + List get rowInfos { + final List rows = []; for (var block in _blocks.values) { rows.addAll(block.rows); } @@ -46,11 +46,11 @@ class GridBloc extends Bloc { createRow: () { _gridService.createRow(); }, - didReceiveRowUpdate: (rows, reason) { - emit(state.copyWith(rows: rows, reason: reason)); + didReceiveRowUpdate: (newRowInfos, reason) { + emit(state.copyWith(rowInfos: newRowInfos, reason: reason)); }, didReceiveFieldUpdate: (fields) { - emit(state.copyWith(rows: rows, fields: GridFieldEquatable(fields))); + emit(state.copyWith(rowInfos: rowInfos, fields: GridFieldEquatable(fields))); }, ); }, @@ -94,7 +94,7 @@ class GridBloc extends Bloc { } Future _loadFields(Grid grid, Emitter emit) async { - final result = await _gridService.getFields(fieldOrders: grid.fieldOrders); + final result = await _gridService.getFields(fieldOrders: grid.fields); return Future( () => result.fold( (fields) { @@ -103,7 +103,7 @@ class GridBloc extends Bloc { emit(state.copyWith( grid: Some(grid), fields: GridFieldEquatable(fieldCache.fields), - rows: rows, + rowInfos: rowInfos, loadingState: GridLoadingState.finish(left(unit)), )); }, @@ -127,7 +127,7 @@ class GridBloc extends Bloc { cache.addListener( listenWhen: () => !isClosed, - onChangeReason: (reason) => add(GridEvent.didReceiveRowUpdate(rows, reason)), + onChangeReason: (reason) => add(GridEvent.didReceiveRowUpdate(rowInfos, reason)), ); _blocks[block.id] = cache; @@ -139,7 +139,8 @@ class GridBloc extends Bloc { class GridEvent with _$GridEvent { const factory GridEvent.initial() = InitialGrid; const factory GridEvent.createRow() = _CreateRow; - const factory GridEvent.didReceiveRowUpdate(List rows, GridRowChangeReason listState) = _DidReceiveRowUpdate; + const factory GridEvent.didReceiveRowUpdate(List rows, GridRowChangeReason listState) = + _DidReceiveRowUpdate; const factory GridEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; } @@ -149,14 +150,14 @@ class GridState with _$GridState { required String gridId, required Option grid, required GridFieldEquatable fields, - required List rows, + required List rowInfos, required GridLoadingState loadingState, required GridRowChangeReason reason, }) = _GridState; factory GridState.initial(String gridId) => GridState( fields: const GridFieldEquatable([]), - rows: [], + rowInfos: [], grid: none(), gridId: gridId, loadingState: const _Loading(), diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index 4e742f9f42..67511a4c61 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -32,7 +32,7 @@ class GridService { return GridEventCreateRow(payload).send(); } - Future> getFields({required List fieldOrders}) { + Future> getFields({required List fieldOrders}) { final payload = QueryFieldPayload.create() ..gridId = gridId ..fieldOrders = RepeatedFieldOrder(items: fieldOrders); @@ -141,12 +141,12 @@ class GridFieldCache { } } - void _deleteFields(List deletedFields) { + void _deleteFields(List deletedFields) { if (deletedFields.isEmpty) { return; } final List newFields = fields; - final Map deletedFieldMap = { + final Map deletedFieldMap = { for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder }; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart index 7d570c9412..9fe12f3ff5 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart @@ -11,7 +11,7 @@ part 'row_action_sheet_bloc.freezed.dart'; class RowActionSheetBloc extends Bloc { final RowService _rowService; - RowActionSheetBloc({required GridRow rowData}) + RowActionSheetBloc({required GridRowInfo rowData}) : _rowService = RowService( gridId: rowData.gridId, blockId: rowData.blockId, @@ -53,10 +53,10 @@ class RowActionSheetEvent with _$RowActionSheetEvent { @freezed class RowActionSheetState with _$RowActionSheetState { const factory RowActionSheetState({ - required GridRow rowData, + required GridRowInfo rowData, }) = _RowActionSheetState; - factory RowActionSheetState.initial(GridRow rowData) => RowActionSheetState( + factory RowActionSheetState.initial(GridRowInfo rowData) => RowActionSheetState( rowData: rowData, ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 69d2a95059..6fec53b441 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart @@ -15,15 +15,15 @@ class RowBloc extends Bloc { void Function()? _rowListenFn; RowBloc({ - required GridRow rowData, + required GridRowInfo rowInfo, required GridRowCache rowCache, }) : _rowService = RowService( - gridId: rowData.gridId, - blockId: rowData.blockId, - rowId: rowData.id, + gridId: rowInfo.gridId, + blockId: rowInfo.blockId, + rowId: rowInfo.id, ), _rowCache = rowCache, - super(RowState.initial(rowData, rowCache.loadGridCells(rowData.id))) { + super(RowState.initial(rowInfo, rowCache.loadGridCells(rowInfo.id))) { on( (event, emit) async { await event.map( @@ -58,7 +58,7 @@ class RowBloc extends Bloc { Future _startListening() async { _rowListenFn = _rowCache.addListener( - rowId: state.rowData.id, + rowId: state.rowInfo.id, onCellUpdated: (cellDatas, reason) => add(RowEvent.didReceiveCellDatas(cellDatas, reason)), listenWhen: () => !isClosed, ); @@ -76,14 +76,14 @@ class RowEvent with _$RowEvent { @freezed class RowState with _$RowState { const factory RowState({ - required GridRow rowData, + required GridRowInfo rowInfo, required GridCellMap gridCellMap, required UnmodifiableListView snapshots, GridRowChangeReason? changeReason, }) = _RowState; - factory RowState.initial(GridRow rowData, GridCellMap cellDataMap) => RowState( - rowData: rowData, + factory RowState.initial(GridRowInfo rowInfo, GridCellMap cellDataMap) => RowState( + rowInfo: rowInfo, gridCellMap: cellDataMap, snapshots: UnmodifiableListView(cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList()), ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart index b75caf32cf..966310fe8c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart @@ -7,12 +7,12 @@ import 'row_service.dart'; part 'row_detail_bloc.freezed.dart'; class RowDetailBloc extends Bloc { - final GridRow rowData; + final GridRowInfo rowInfo; final GridRowCache _rowCache; void Function()? _rowListenFn; RowDetailBloc({ - required this.rowData, + required this.rowInfo, required GridRowCache rowCache, }) : _rowCache = rowCache, super(RowDetailState.initial()) { @@ -41,14 +41,14 @@ class RowDetailBloc extends Bloc { Future _startListening() async { _rowListenFn = _rowCache.addListener( - rowId: rowData.id, + rowId: rowInfo.id, onCellUpdated: (cellDatas, reason) => add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())), listenWhen: () => !isClosed, ); } Future _loadCellData() async { - final cellDataMap = _rowCache.loadGridCells(rowData.id); + final cellDataMap = _rowCache.loadGridCells(rowInfo.id); if (!isClosed) { add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList())); } 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 7296fd51a8..e733c6c20a 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 @@ -32,7 +32,7 @@ class GridRowCache { /// _rows containers the current block's rows /// Use List to reverse the order of the GridRow. - List _rows = []; + List _rowInfos = []; /// Use Map for faster access the raw row data. final HashMap _rowByRowId; @@ -41,7 +41,7 @@ class GridRowCache { final GridRowCacheFieldNotifier _fieldNotifier; final _GridRowChangesetNotifier _rowChangeReasonNotifier; - UnmodifiableListView get rows => UnmodifiableListView(_rows); + UnmodifiableListView get rows => UnmodifiableListView(_rowInfos); GridCellCache get cellCache => _cellCache; GridRowCache({ @@ -55,7 +55,7 @@ class GridRowCache { // notifier.onFieldsChanged(() => _rowChangeReasonNotifier.receive(const GridRowChangeReason.fieldDidChange())); notifier.onFieldChanged((field) => _cellCache.remove(field.id)); - _rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList(); + _rowInfos = block.rows.map((rowInfo) => buildGridRow(rowInfo.id, rowInfo.height.toDouble())).toList(); } Future dispose() async { @@ -79,11 +79,11 @@ class GridRowCache { return; } - final List newRows = []; + final List newRows = []; final DeletedIndexs deletedIndex = []; final Map deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId}; - _rows.asMap().forEach((index, row) { + _rowInfos.asMap().forEach((index, row) { if (deletedRowByRowId[row.id] == null) { newRows.add(row); } else { @@ -91,7 +91,7 @@ class GridRowCache { deletedIndex.add(DeletedIndex(index: index, row: row)); } }); - _rows = newRows; + _rowInfos = newRows; _rowChangeReasonNotifier.receive(GridRowChangeReason.delete(deletedIndex)); } @@ -107,7 +107,7 @@ class GridRowCache { rowId: insertRow.rowId, ); insertIndexs.add(insertIndex); - _rows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble()))); + _rowInfos.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble()))); } _rowChangeReasonNotifier.receive(GridRowChangeReason.insert(insertIndexs)); @@ -121,12 +121,12 @@ class GridRowCache { final UpdatedIndexs updatedIndexs = UpdatedIndexs(); for (final updatedRow in updatedRows) { final rowId = updatedRow.rowId; - final index = _rows.indexWhere((row) => row.id == rowId); + final index = _rowInfos.indexWhere((row) => row.id == rowId); if (index != -1) { _rowByRowId[rowId] = updatedRow.row; - _rows.removeAt(index); - _rows.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble())); + _rowInfos.removeAt(index); + _rowInfos.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble())); updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId); } } @@ -225,12 +225,12 @@ class GridRowCache { updatedRow.freeze(); _rowByRowId[updatedRow.id] = updatedRow; - final index = _rows.indexWhere((gridRow) => gridRow.id == updatedRow.id); + final index = _rowInfos.indexWhere((gridRow) => gridRow.id == updatedRow.id); if (index != -1) { // update the corresponding row in _rows if they are not the same - if (_rows[index].rawRow != updatedRow) { - final row = _rows.removeAt(index).copyWith(rawRow: updatedRow); - _rows.insert(index, row); + if (_rowInfos[index].rawRow != updatedRow) { + final row = _rowInfos.removeAt(index).copyWith(rawRow: updatedRow); + _rowInfos.insert(index, row); // Calculate the update index final UpdatedIndexs updatedIndexs = UpdatedIndexs(); @@ -242,8 +242,8 @@ class GridRowCache { } } - GridRow buildGridRow(String rowId, double rowHeight) { - return GridRow( + GridRowInfo buildGridRow(String rowId, double rowHeight) { + return GridRowInfo( gridId: gridId, blockId: block.id, fields: _fieldNotifier.fields, @@ -325,15 +325,15 @@ class RowService { } @freezed -class GridRow with _$GridRow { - const factory GridRow({ +class GridRowInfo with _$GridRowInfo { + const factory GridRowInfo({ required String gridId, required String blockId, required String id, required UnmodifiableListView fields, required double height, Row? rawRow, - }) = _GridRow; + }) = _GridRowInfo; } typedef InsertedIndexs = List; @@ -360,7 +360,7 @@ class InsertedIndex { class DeletedIndex { final int index; - final GridRow row; + final GridRowInfo row; DeletedIndex({ required this.index, required this.row, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index d7d2999dd1..2ec27f3f3c 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -212,10 +212,10 @@ class _GridRowsState extends State<_GridRows> { builder: (context, state) { return SliverAnimatedList( key: _key, - initialItemCount: context.read().state.rows.length, + initialItemCount: context.read().state.rowInfos.length, itemBuilder: (BuildContext context, int index, Animation animation) { - final GridRow rowData = context.read().state.rows[index]; - return _renderRow(context, rowData, animation); + final GridRowInfo rowInfo = context.read().state.rowInfos[index]; + return _renderRow(context, rowInfo, animation); }, ); }, @@ -224,19 +224,19 @@ class _GridRowsState extends State<_GridRows> { Widget _renderRow( BuildContext context, - GridRow rowData, + GridRowInfo rowInfo, Animation animation, ) { - final rowCache = context.read().getRowCache(rowData.blockId, rowData.id); + final rowCache = context.read().getRowCache(rowInfo.blockId, rowInfo.id); final fieldCache = context.read().fieldCache; if (rowCache != null) { return SizeTransition( sizeFactor: animation, child: GridRowWidget( - rowData: rowData, + rowData: rowInfo, rowCache: rowCache, fieldCache: fieldCache, - key: ValueKey(rowData.id), + key: ValueKey(rowInfo.id), ), ); } else { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart index b0c1cd2ea0..c3e2e17b7e 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart @@ -15,7 +15,7 @@ import 'row_action_sheet.dart'; import 'row_detail.dart'; class GridRowWidget extends StatefulWidget { - final GridRow rowData; + final GridRowInfo rowData; final GridRowCache rowCache; final GridCellBuilder cellBuilder; @@ -40,7 +40,7 @@ class _GridRowWidgetState extends State { @override void initState() { _rowBloc = RowBloc( - rowData: widget.rowData, + rowInfo: widget.rowData, rowCache: widget.rowCache, ); _rowBloc.add(const RowEvent.initial()); @@ -53,7 +53,7 @@ class _GridRowWidgetState extends State { value: _rowBloc, child: _RowEnterRegion( child: BlocBuilder( - buildWhen: (p, c) => p.rowData.height != c.rowData.height, + buildWhen: (p, c) => p.rowInfo.height != c.rowInfo.height, builder: (context, state) { return Row( children: [ @@ -80,7 +80,7 @@ class _GridRowWidgetState extends State { void _expandRow(BuildContext context) { final page = RowDetailPage( - rowData: widget.rowData, + rowInfo: widget.rowData, rowCache: widget.rowCache, cellBuilder: widget.cellBuilder, ); @@ -148,7 +148,7 @@ class _DeleteRowButton extends StatelessWidget { width: 20, height: 30, onPressed: () => GridRowActionSheet( - rowData: context.read().state.rowData, + rowData: context.read().state.rowInfo, ).show(context), iconPadding: const EdgeInsets.all(3), icon: svgWidget("editor/details"), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart index 1d7886c86c..06e9c68d19 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart @@ -14,7 +14,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class GridRowActionSheet extends StatelessWidget { - final GridRow rowData; + final GridRowInfo rowData; const GridRowActionSheet({required this.rowData, Key? key}) : super(key: key); @override diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart index 4449ea6770..a01f97b847 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -21,12 +21,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate { - final GridRow rowData; + final GridRowInfo rowInfo; final GridRowCache rowCache; final GridCellBuilder cellBuilder; const RowDetailPage({ - required this.rowData, + required this.rowInfo, required this.rowCache, required this.cellBuilder, Key? key, @@ -62,7 +62,7 @@ class _RowDetailPageState extends State { Widget build(BuildContext context) { return BlocProvider( create: (context) { - final bloc = RowDetailBloc(rowData: widget.rowData, rowCache: widget.rowCache); + final bloc = RowDetailBloc(rowInfo: widget.rowInfo, rowCache: widget.rowCache); bloc.add(const RowDetailEvent.initial()); return bloc; }, diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs index 9cfdbc088c..eb486f4cd2 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -10,33 +10,33 @@ pub struct GridBlock { pub id: String, #[pb(index = 2)] - pub row_infos: Vec, + pub rows: Vec, } impl GridBlock { - pub fn new(block_id: &str, row_orders: Vec) -> Self { + pub fn new(block_id: &str, rows: Vec) -> Self { Self { id: block_id.to_owned(), - row_infos: row_orders, + rows, } } } #[derive(Debug, Default, Clone, ProtoBuf)] -pub struct RowInfo { +pub struct Row { #[pb(index = 1)] pub block_id: String, #[pb(index = 2)] - pub row_id: String, + pub id: String, #[pb(index = 3)] pub height: i32, } -impl RowInfo { +impl Row { pub fn row_id(&self) -> &str { - &self.row_id + &self.id } pub fn block_id(&self) -> &str { @@ -44,35 +44,26 @@ impl RowInfo { } } -impl std::convert::From<&RowRevision> for RowInfo { +impl std::convert::From<&RowRevision> for Row { fn from(rev: &RowRevision) -> Self { Self { block_id: rev.block_id.clone(), - row_id: rev.id.clone(), + id: rev.id.clone(), height: rev.height, } } } -impl std::convert::From<&Arc> for RowInfo { +impl std::convert::From<&Arc> for Row { fn from(rev: &Arc) -> Self { Self { block_id: rev.block_id.clone(), - row_id: rev.id.clone(), + id: rev.id.clone(), height: rev.height, } } } -#[derive(Debug, Default, ProtoBuf)] -pub struct Row { - #[pb(index = 1)] - pub id: String, - - #[pb(index = 2)] - pub height: i32, -} - #[derive(Debug, Default, ProtoBuf)] pub struct OptionalRow { #[pb(index = 1, one_of)] @@ -139,10 +130,10 @@ impl UpdatedRow { } } -impl std::convert::From for InsertedRow { - fn from(row_info: RowInfo) -> Self { +impl std::convert::From for InsertedRow { + fn from(row_info: Row) -> Self { Self { - row_id: row_info.row_id, + row_id: row_info.id, block_id: row_info.block_id, height: row_info.height, index: None, @@ -152,7 +143,7 @@ impl std::convert::From for InsertedRow { impl std::convert::From<&RowRevision> for InsertedRow { fn from(row: &RowRevision) -> Self { - let row_order = RowInfo::from(row); + let row_order = Row::from(row); Self::from(row_order) } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index d43e77e9ae..f7fa70455c 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -57,24 +57,24 @@ impl std::convert::From> for Field { } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct FieldOrder { +pub struct GridField { #[pb(index = 1)] pub field_id: String, } -impl std::convert::From<&str> for FieldOrder { +impl std::convert::From<&str> for GridField { fn from(s: &str) -> Self { - FieldOrder { field_id: s.to_owned() } + GridField { field_id: s.to_owned() } } } -impl std::convert::From for FieldOrder { +impl std::convert::From for GridField { fn from(s: String) -> Self { - FieldOrder { field_id: s } + GridField { field_id: s } } } -impl std::convert::From<&Arc> for FieldOrder { +impl std::convert::From<&Arc> for GridField { fn from(field_rev: &Arc) -> Self { Self { field_id: field_rev.id.clone(), @@ -90,7 +90,7 @@ pub struct GridFieldChangeset { pub inserted_fields: Vec, #[pb(index = 3)] - pub deleted_fields: Vec, + pub deleted_fields: Vec, #[pb(index = 4)] pub updated_fields: Vec, @@ -106,7 +106,7 @@ impl GridFieldChangeset { } } - pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { + pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { Self { grid_id: grid_id.to_string(), inserted_fields: vec![], @@ -259,18 +259,18 @@ impl std::convert::From> for RepeatedField { #[derive(Debug, Clone, Default, ProtoBuf)] pub struct RepeatedFieldOrder { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } impl std::ops::Deref for RepeatedFieldOrder { - type Target = Vec; + type Target = Vec; fn deref(&self) -> &Self::Target { &self.items } } -impl std::convert::From> for RepeatedFieldOrder { - fn from(field_orders: Vec) -> Self { +impl std::convert::From> for RepeatedFieldOrder { + fn from(field_orders: Vec) -> Self { RepeatedFieldOrder { items: field_orders } } } @@ -278,7 +278,7 @@ impl std::convert::From> for RepeatedFieldOrder { impl std::convert::From for RepeatedFieldOrder { fn from(s: String) -> Self { RepeatedFieldOrder { - items: vec![FieldOrder::from(s)], + items: vec![GridField::from(s)], } } } diff --git a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs index c05df11414..1cc6f2ba45 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs @@ -1,4 +1,4 @@ -use crate::entities::{FieldOrder, GridBlock}; +use crate::entities::{GridBlock, GridField}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; @@ -8,7 +8,7 @@ pub struct Grid { pub id: String, #[pb(index = 2)] - pub field_orders: Vec, + pub fields: Vec, #[pb(index = 3)] pub blocks: Vec, 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 a905a9640b..c52f0662ec 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs @@ -1,5 +1,5 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; -use crate::entities::{CellChangeset, GridBlockChangeset, InsertedRow, Row, RowInfo, UpdatedRow}; +use crate::entities::{CellChangeset, GridBlockChangeset, InsertedRow, Row, UpdatedRow}; use crate::manager::GridUser; use crate::services::block_revision_editor::GridBlockRevisionEditor; use crate::services::persistence::block_index::BlockIndexCache; @@ -138,7 +138,7 @@ impl GridBlockManager { Some(row_info) => { let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?; let _ = self - .notify_did_update_block(&block_id, GridBlockChangeset::delete(&block_id, vec![row_info.row_id])) + .notify_did_update_block(&block_id, GridBlockChangeset::delete(&block_id, vec![row_info.id])) .await?; } } @@ -146,15 +146,12 @@ impl GridBlockManager { Ok(()) } - pub(crate) async fn delete_rows( - &self, - row_orders: Vec, - ) -> FlowyResult> { + pub(crate) async fn delete_rows(&self, row_orders: Vec) -> FlowyResult> { let mut changesets = vec![]; 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 + .rows .into_iter() .map(|row_info| Cow::Owned(row_info.row_id().to_owned())) .collect::>>(); @@ -217,7 +214,7 @@ impl GridBlockManager { } } - pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult> { + pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult> { let editor = self.get_editor(block_id).await?; editor.get_row_infos::<&str>(None).await } diff --git a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs index e73a66c0fa..99d851a7d5 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs @@ -1,4 +1,4 @@ -use crate::entities::RowInfo; +use crate::entities::Row; use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision}; @@ -123,12 +123,12 @@ impl GridBlockRevisionEditor { Ok(cell_revs) } - pub async fn get_row_info(&self, row_id: &str) -> FlowyResult> { + pub async fn get_row_info(&self, row_id: &str) -> FlowyResult> { let row_ids = Some(vec![Cow::Borrowed(row_id)]); Ok(self.get_row_infos(row_ids).await?.pop()) } - pub async fn get_row_infos(&self, row_ids: Option>>) -> FlowyResult> + pub async fn get_row_infos(&self, row_ids: Option>>) -> FlowyResult> where T: AsRef + ToOwned + ?Sized, { @@ -138,8 +138,8 @@ impl GridBlockRevisionEditor { .await .get_row_revs(row_ids)? .iter() - .map(RowInfo::from) - .collect::>(); + .map(Row::from) + .collect::>(); Ok(row_infos) } 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 1d63b6dd69..e6a37ef203 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -189,7 +189,7 @@ impl GridRevisionEditor { pub async fn delete_field(&self, field_id: &str) -> FlowyResult<()> { let _ = self.modify(|grid_pad| Ok(grid_pad.delete_field_rev(field_id)?)).await?; - let field_order = FieldOrder::from(field_id); + let field_order = GridField::from(field_id); let notified_changeset = GridFieldChangeset::delete(&self.grid_id, vec![field_order]); let _ = self.notify_did_update_grid(notified_changeset).await?; Ok(()) @@ -269,14 +269,14 @@ impl GridRevisionEditor { Ok(()) } - pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { + pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { 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 = RowInfo::from(&row_rev); + let row_order = Row::from(&row_rev); // insert the row let row_count = self.block_manager.create_row(&block_id, row_rev, start_row_id).await?; @@ -287,13 +287,13 @@ impl GridRevisionEditor { Ok(row_order) } - pub async fn insert_rows(&self, contexts: Vec) -> FlowyResult> { + pub async fn insert_rows(&self, contexts: Vec) -> FlowyResult> { let block_id = self.block_id().await?; let mut rows_by_block_id: HashMap> = 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(RowInfo::from(&row_rev)); + row_orders.push(Row::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) -> FlowyResult<()> { + pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { let changesets = self.block_manager.delete_rows(row_orders).await?; for changeset in changesets { let _ = self.update_block(changeset).await?; @@ -434,21 +434,21 @@ impl GridRevisionEditor { let field_orders = pad_read_guard .get_field_revs(None)? .iter() - .map(FieldOrder::from) + .map(GridField::from) .collect(); let mut block_orders = vec![]; for block_rev in pad_read_guard.get_block_meta_revs() { 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_infos: row_orders, + rows: row_orders, }; block_orders.push(block_order); } Ok(Grid { id: self.grid_id.clone(), - field_orders, + fields: field_orders, blocks: block_orders, }) } @@ -517,7 +517,7 @@ impl GridRevisionEditor { .modify(|grid_pad| Ok(grid_pad.move_field(field_id, from as usize, to as usize)?)) .await?; if let Some((index, field_rev)) = self.grid_pad.read().await.get_field_rev(field_id) { - let delete_field_order = FieldOrder::from(field_id); + let delete_field_order = GridField::from(field_id); let insert_field = IndexField::from_field_rev(field_rev, index); let notified_changeset = GridFieldChangeset { grid_id: self.grid_id.clone(), 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 1b9ce80101..9d6543b650 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,4 +1,4 @@ -use crate::entities::{GridBlock, RepeatedGridBlock, Row, RowInfo}; +use crate::entities::{GridBlock, RepeatedGridBlock, Row}; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; use std::collections::HashMap; @@ -9,7 +9,7 @@ pub struct GridBlockSnapshot { pub row_revs: Vec>, } -pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec { +pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec { let mut map: HashMap = HashMap::new(); row_orders.into_iter().for_each(|row_info| { // Memory Optimization: escape clone block_id @@ -17,7 +17,7 @@ pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec let cloned_block_id = block_id.clone(); map.entry(block_id) .or_insert_with(|| GridBlock::new(&cloned_block_id, vec![])) - .row_infos + .rows .push(row_info); }); map.into_values().collect::>() @@ -35,8 +35,8 @@ pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec // Some((field_id, cell)) // } -pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc]) -> Vec { - row_revs.iter().map(RowInfo::from).collect::>() +pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc]) -> Vec { + row_revs.iter().map(Row::from).collect::>() } pub(crate) fn make_row_from_row_rev(fields: &[Arc], row_rev: Arc) -> Option { @@ -58,6 +58,7 @@ pub(crate) fn make_rows_from_row_revs(_fields: &[Arc], row_revs: // .collect::>(); Row { + block_id: row_rev.block_id.clone(), id: row_rev.id.clone(), height: row_rev.height, } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 288133958b..5a9b29b76d 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -1,5 +1,5 @@ use crate::grid::grid_editor::GridEditorTest; -use flowy_grid::entities::RowInfo; +use flowy_grid::entities::Row; use flowy_grid::services::row::{CreateRowRevisionBuilder, CreateRowRevisionPayload}; use flowy_grid_data_model::revision::{ FieldRevision, GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, @@ -90,7 +90,7 @@ impl GridRowTest { let row_orders = row_ids .into_iter() .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) - .collect::>(); + .collect::>(); self.editor.delete_rows(row_orders).await.unwrap(); self.row_revs = self.get_row_revs().await; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index d944aac6c5..bfa9e6e0ba 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -30,7 +30,7 @@ pub struct GridEditorTest { pub block_meta_revs: Vec>, pub row_revs: Vec>, pub field_count: usize, - pub row_order_by_row_id: HashMap, + pub row_order_by_row_id: HashMap, } impl GridEditorTest { From 5ea3213c4e12123999ef14c96f5087eb6f9c667e Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Jul 2022 12:57:25 +0800 Subject: [PATCH 026/112] chore: fix tests --- .../checkbox_type_option/checkbox_tests.rs | 2 +- .../checkbox_type_option_entities.rs | 2 +- .../src/services/filter/impls/checkbox_filter.rs | 5 +++-- .../flowy-grid/tests/grid/block_test/row_test.rs | 14 +++++++------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs index 9e041cc415..1a60a0a5a8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs @@ -25,6 +25,6 @@ mod tests { assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); let data = apply_cell_data_changeset("12", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); + assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), ""); } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs index 54cde9b310..233c481eb6 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs @@ -6,7 +6,7 @@ use std::str::FromStr; pub const YES: &str = "Yes"; pub const NO: &str = "No"; -pub struct CheckboxCellData(pub String); +pub struct CheckboxCellData(String); impl CheckboxCellData { pub fn is_check(&self) -> bool { diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs index ca67d7aeaf..24e21bbeb7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/checkbox_filter.rs @@ -28,6 +28,7 @@ impl CellFilterOperation for CheckboxTypeOption { mod tests { use crate::entities::{CheckboxCondition, GridCheckboxFilter}; use crate::services::field::CheckboxCellData; + use std::str::FromStr; #[test] fn checkbox_filter_is_check_test() { @@ -35,7 +36,7 @@ mod tests { condition: CheckboxCondition::IsChecked, }; for (value, visible) in [("true", true), ("yes", true), ("false", false), ("no", false)] { - let data = CheckboxCellData(value.to_owned()); + let data = CheckboxCellData::from_str(value).unwrap(); assert_eq!(checkbox_filter.is_visible(&data), visible); } } @@ -46,7 +47,7 @@ mod tests { condition: CheckboxCondition::IsUnChecked, }; for (value, visible) in [("false", true), ("no", true), ("true", false), ("yes", false)] { - let data = CheckboxCellData(value.to_owned()); + let data = CheckboxCellData::from_str(value).unwrap(); assert_eq!(checkbox_filter.is_visible(&data), visible); } } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index 6dafb2973f..7b64a44b48 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -9,13 +9,13 @@ use flowy_grid_data_model::revision::RowMetaChangeset; async fn grid_create_row_count_test() { let mut test = GridRowTest::new().await; let scripts = vec![ - AssertRowCount(3), + AssertRowCount(5), CreateEmptyRow, CreateEmptyRow, CreateRow { row_rev: test.row_builder().build(), }, - AssertRowCount(6), + AssertRowCount(8), ]; test.run_scripts(scripts).await; } @@ -31,11 +31,11 @@ async fn grid_update_row() { cell_by_field_id: Default::default(), }; - let scripts = vec![AssertRowCount(3), CreateRow { row_rev }, UpdateRow { changeset }]; + let scripts = vec![AssertRowCount(5), CreateRow { row_rev }, UpdateRow { changeset }]; test.run_scripts(scripts).await; let expected_row = test.last_row().unwrap(); - let scripts = vec![AssertRow { expected_row }, AssertRowCount(4)]; + let scripts = vec![AssertRow { expected_row }, AssertRowCount(6)]; test.run_scripts(scripts).await; } @@ -46,19 +46,19 @@ async fn grid_delete_row() { let row_2 = test.row_builder().build(); let row_ids = vec![row_1.id.clone(), row_2.id.clone()]; let scripts = vec![ - AssertRowCount(3), + AssertRowCount(5), CreateRow { row_rev: row_1 }, CreateRow { row_rev: row_2 }, AssertBlockCount(1), AssertBlock { block_index: 0, - row_count: 5, + row_count: 7, start_row_index: 0, }, DeleteRows { row_ids }, AssertBlock { block_index: 0, - row_count: 3, + row_count: 5, start_row_index: 0, }, ]; From 1bf0f0f875ab306c33942cdc42cfc037b2d1a1b1 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Jul 2022 13:38:53 +0800 Subject: [PATCH 027/112] chore: add suffix PB to rust struct --- .../application/grid/block/block_cache.dart | 2 +- .../application/grid/field/field_service.dart | 4 +- .../application/grid/grid_service.dart | 10 +- .../flowy-grid/src/entities/block_entities.rs | 70 +++++----- .../flowy-grid/src/entities/cell_entities.rs | 4 +- .../flowy-grid/src/entities/field_entities.rs | 130 ++++++++---------- .../src/entities/filter_entities/util.rs | 18 +-- .../flowy-grid/src/entities/grid_entities.rs | 36 ++--- .../flowy-grid/src/entities/group_entities.rs | 22 +-- .../flowy-grid/src/entities/row_entities.rs | 16 +-- .../src/entities/setting_entities.rs | 34 ++--- .../flowy-grid/src/entities/sort_entities.rs | 12 +- .../rust-lib/flowy-grid/src/event_handler.rs | 90 ++++++------ .../flowy-grid/src/services/block_manager.rs | 33 +++-- .../src/services/block_revision_editor.rs | 10 +- .../src/services/cell/cell_operation.rs | 6 +- .../src/services/field/field_builder.rs | 6 +- .../date_type_option/date_tests.rs | 30 ++-- .../date_type_option/date_type_option.rs | 14 +- .../date_type_option_entities.rs | 20 +-- .../multi_select_type_option.rs | 24 ++-- .../selection_type_option/select_option.rs | 100 +++++++------- .../single_select_type_option.rs | 40 +++--- .../text_type_option/text_type_option.rs | 6 +- .../type_options/url_type_option/url_tests.rs | 6 +- .../url_type_option/url_type_option.rs | 14 +- .../url_type_option_entities.rs | 12 +- .../src/services/filter/filter_service.rs | 10 +- .../filter/impls/select_option_filter.rs | 12 +- .../flowy-grid/src/services/grid_editor.rs | 48 +++---- .../flowy-grid/src/services/row/row_loader.rs | 26 ++-- .../src/services/setting/setting_builder.rs | 14 +- .../tests/grid/block_test/script.rs | 8 +- .../flowy-grid/tests/grid/block_test/util.rs | 10 +- .../flowy-grid/tests/grid/cell_test/test.rs | 4 +- .../flowy-grid/tests/grid/field_test/test.rs | 8 +- .../flowy-grid/tests/grid/field_test/util.rs | 14 +- .../tests/grid/filter_test/script.rs | 6 +- .../grid/filter_test/text_filter_test.rs | 10 +- .../flowy-grid/tests/grid/grid_editor.rs | 16 +-- 40 files changed, 474 insertions(+), 481 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart b/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart index 9afdf17be6..3c99c0e0e1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/block/block_cache.dart @@ -9,7 +9,7 @@ import 'block_listener.dart'; /// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information class GridBlockCache { final String gridId; - final GridBlock block; + final GridBlockPB block; late GridRowCache _rowCache; late GridBlockListener _listener; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index de5b6adcb0..828ea4cc74 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -21,10 +21,10 @@ class FieldService { FieldService({required this.gridId, required this.fieldId}); Future> moveField(int fromIndex, int toIndex) { - final payload = MoveItemPayload.create() + final payload = MoveItemPayloadPB.create() ..gridId = gridId ..itemId = fieldId - ..ty = MoveItemType.MoveField + ..ty = MoveItemTypePB.MoveField ..fromIndex = fromIndex ..toIndex = toIndex; diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index 67511a4c61..1d0c309d51 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -19,10 +19,10 @@ class GridService { required this.gridId, }); - Future> loadGrid() async { + Future> loadGrid() async { await FolderEventSetLatestView(ViewId(value: gridId)).send(); - final payload = GridId(value: gridId); + final payload = GridIdPB(value: gridId); return GridEventGetGrid(payload).send(); } @@ -32,7 +32,7 @@ class GridService { return GridEventCreateRow(payload).send(); } - Future> getFields({required List fieldOrders}) { + Future> getFields({required List fieldOrders}) { final payload = QueryFieldPayload.create() ..gridId = gridId ..fieldOrders = RepeatedFieldOrder(items: fieldOrders); @@ -141,12 +141,12 @@ class GridFieldCache { } } - void _deleteFields(List deletedFields) { + void _deleteFields(List deletedFields) { if (deletedFields.isEmpty) { return; } final List newFields = fields; - final Map deletedFieldMap = { + final Map deletedFieldMap = { for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder }; diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs index eb486f4cd2..df2192c77d 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -5,16 +5,16 @@ use flowy_grid_data_model::revision::RowRevision; use std::sync::Arc; #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridBlock { +pub struct GridBlockPB { #[pb(index = 1)] pub id: String, #[pb(index = 2)] - pub rows: Vec, + pub rows: Vec, } -impl GridBlock { - pub fn new(block_id: &str, rows: Vec) -> Self { +impl GridBlockPB { + pub fn new(block_id: &str, rows: Vec) -> Self { Self { id: block_id.to_owned(), rows, @@ -23,7 +23,7 @@ impl GridBlock { } #[derive(Debug, Default, Clone, ProtoBuf)] -pub struct Row { +pub struct GridRowPB { #[pb(index = 1)] pub block_id: String, @@ -34,7 +34,7 @@ pub struct Row { pub height: i32, } -impl Row { +impl GridRowPB { pub fn row_id(&self) -> &str { &self.id } @@ -44,7 +44,7 @@ impl Row { } } -impl std::convert::From<&RowRevision> for Row { +impl std::convert::From<&RowRevision> for GridRowPB { fn from(rev: &RowRevision) -> Self { Self { block_id: rev.block_id.clone(), @@ -54,7 +54,7 @@ impl std::convert::From<&RowRevision> for Row { } } -impl std::convert::From<&Arc> for Row { +impl std::convert::From<&Arc> for GridRowPB { fn from(rev: &Arc) -> Self { Self { block_id: rev.block_id.clone(), @@ -65,36 +65,36 @@ impl std::convert::From<&Arc> for Row { } #[derive(Debug, Default, ProtoBuf)] -pub struct OptionalRow { +pub struct OptionalRowPB { #[pb(index = 1, one_of)] - pub row: Option, + pub row: Option, } #[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedRow { +pub struct RepeatedRowPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl std::convert::From> for RepeatedRow { - fn from(items: Vec) -> Self { +impl std::convert::From> for RepeatedRowPB { + fn from(items: Vec) -> Self { Self { items } } } #[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedGridBlock { +pub struct RepeatedGridBlockPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl std::convert::From> for RepeatedGridBlock { - fn from(items: Vec) -> Self { +impl std::convert::From> for RepeatedGridBlockPB { + fn from(items: Vec) -> Self { Self { items } } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct InsertedRow { +pub struct InsertedRowPB { #[pb(index = 1)] pub block_id: String, @@ -109,7 +109,7 @@ pub struct InsertedRow { } #[derive(Debug, Default, ProtoBuf)] -pub struct UpdatedRow { +pub struct UpdatedRowPB { #[pb(index = 1)] pub block_id: String, @@ -117,11 +117,11 @@ pub struct UpdatedRow { pub row_id: String, #[pb(index = 3)] - pub row: Row, + pub row: GridRowPB, } -impl UpdatedRow { - pub fn new(row_rev: &RowRevision, row: Row) -> Self { +impl UpdatedRowPB { + pub fn new(row_rev: &RowRevision, row: GridRowPB) -> Self { Self { row_id: row_rev.id.clone(), block_id: row_rev.block_id.clone(), @@ -130,8 +130,8 @@ impl UpdatedRow { } } -impl std::convert::From for InsertedRow { - fn from(row_info: Row) -> Self { +impl std::convert::From for InsertedRowPB { + fn from(row_info: GridRowPB) -> Self { Self { row_id: row_info.id, block_id: row_info.block_id, @@ -141,26 +141,26 @@ impl std::convert::From for InsertedRow { } } -impl std::convert::From<&RowRevision> for InsertedRow { +impl std::convert::From<&RowRevision> for InsertedRowPB { fn from(row: &RowRevision) -> Self { - let row_order = Row::from(row); + let row_order = GridRowPB::from(row); Self::from(row_order) } } #[derive(Debug, Default, ProtoBuf)] -pub struct GridBlockChangeset { +pub struct GridBlockChangesetPB { #[pb(index = 1)] pub block_id: String, #[pb(index = 2)] - pub inserted_rows: Vec, + pub inserted_rows: Vec, #[pb(index = 3)] pub deleted_rows: Vec, #[pb(index = 4)] - pub updated_rows: Vec, + pub updated_rows: Vec, #[pb(index = 5)] pub visible_rows: Vec, @@ -168,8 +168,8 @@ pub struct GridBlockChangeset { #[pb(index = 6)] pub hide_rows: Vec, } -impl GridBlockChangeset { - pub fn insert(block_id: &str, inserted_rows: Vec) -> Self { +impl GridBlockChangesetPB { + pub fn insert(block_id: &str, inserted_rows: Vec) -> Self { Self { block_id: block_id.to_owned(), inserted_rows, @@ -185,7 +185,7 @@ impl GridBlockChangeset { } } - pub fn update(block_id: &str, updated_rows: Vec) -> Self { + pub fn update(block_id: &str, updated_rows: Vec) -> Self { Self { block_id: block_id.to_owned(), updated_rows, @@ -195,7 +195,7 @@ impl GridBlockChangeset { } #[derive(ProtoBuf, Default)] -pub struct QueryGridBlocksPayload { +pub struct QueryGridBlocksPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -208,7 +208,7 @@ pub struct QueryGridBlocksParams { pub block_ids: Vec, } -impl TryInto for QueryGridBlocksPayload { +impl TryInto for QueryGridBlocksPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs index f7daa84147..57993a27db 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs @@ -1,4 +1,4 @@ -use crate::entities::{FieldIdentifier, FieldIdentifierPayload}; +use crate::entities::{FieldIdentifier, FieldIdentifierPayloadPB}; use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; @@ -8,7 +8,7 @@ use std::collections::HashMap; #[derive(ProtoBuf, Default)] pub struct CreateSelectOptionPayload { #[pb(index = 1)] - pub field_identifier: FieldIdentifierPayload, + pub field_identifier: FieldIdentifierPayloadPB, #[pb(index = 2)] pub option_name: String, diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index f7fa70455c..1a4fac2e8c 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -9,7 +9,7 @@ use std::sync::Arc; use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString}; #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct Field { +pub struct FieldPB { #[pb(index = 1)] pub id: String, @@ -35,7 +35,7 @@ pub struct Field { pub is_primary: bool, } -impl std::convert::From for Field { +impl std::convert::From for FieldPB { fn from(field_rev: FieldRevision) -> Self { Self { id: field_rev.id, @@ -50,31 +50,31 @@ impl std::convert::From for Field { } } -impl std::convert::From> for Field { +impl std::convert::From> for FieldPB { fn from(field_rev: Arc) -> Self { let field_rev = field_rev.as_ref().clone(); - Field::from(field_rev) + FieldPB::from(field_rev) } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridField { +pub struct GridFieldPB { #[pb(index = 1)] pub field_id: String, } -impl std::convert::From<&str> for GridField { +impl std::convert::From<&str> for GridFieldPB { fn from(s: &str) -> Self { - GridField { field_id: s.to_owned() } + GridFieldPB { field_id: s.to_owned() } } } -impl std::convert::From for GridField { +impl std::convert::From for GridFieldPB { fn from(s: String) -> Self { - GridField { field_id: s } + GridFieldPB { field_id: s } } } -impl std::convert::From<&Arc> for GridField { +impl std::convert::From<&Arc> for GridFieldPB { fn from(field_rev: &Arc) -> Self { Self { field_id: field_rev.id.clone(), @@ -82,22 +82,22 @@ impl std::convert::From<&Arc> for GridField { } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridFieldChangeset { +pub struct GridFieldChangesetPB { #[pb(index = 1)] pub grid_id: String, #[pb(index = 2)] - pub inserted_fields: Vec, + pub inserted_fields: Vec, #[pb(index = 3)] - pub deleted_fields: Vec, + pub deleted_fields: Vec, #[pb(index = 4)] - pub updated_fields: Vec, + pub updated_fields: Vec, } -impl GridFieldChangeset { - pub fn insert(grid_id: &str, inserted_fields: Vec) -> Self { +impl GridFieldChangesetPB { + pub fn insert(grid_id: &str, inserted_fields: Vec) -> Self { Self { grid_id: grid_id.to_owned(), inserted_fields, @@ -106,7 +106,7 @@ impl GridFieldChangeset { } } - pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { + pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { Self { grid_id: grid_id.to_string(), inserted_fields: vec![], @@ -115,7 +115,7 @@ impl GridFieldChangeset { } } - pub fn update(grid_id: &str, updated_fields: Vec) -> Self { + pub fn update(grid_id: &str, updated_fields: Vec) -> Self { Self { grid_id: grid_id.to_string(), inserted_fields: vec![], @@ -126,25 +126,25 @@ impl GridFieldChangeset { } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct IndexField { +pub struct IndexFieldPB { #[pb(index = 1)] - pub field: Field, + pub field: FieldPB, #[pb(index = 2)] pub index: i32, } -impl IndexField { +impl IndexFieldPB { pub fn from_field_rev(field_rev: &Arc, index: usize) -> Self { Self { - field: Field::from(field_rev.as_ref().clone()), + field: FieldPB::from(field_rev.as_ref().clone()), index: index as i32, } } } #[derive(Debug, Default, ProtoBuf)] -pub struct GetEditFieldContextPayload { +pub struct GetEditFieldContextPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -156,7 +156,7 @@ pub struct GetEditFieldContextPayload { } #[derive(Debug, Default, ProtoBuf)] -pub struct EditFieldPayload { +pub struct EditFieldPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -176,7 +176,7 @@ pub struct EditFieldParams { pub field_type: FieldType, } -impl TryInto for EditFieldPayload { +impl TryInto for EditFieldPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -195,7 +195,7 @@ pub struct CreateFieldParams { pub field_type: FieldType, } -impl TryInto for EditFieldPayload { +impl TryInto for EditFieldPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -209,87 +209,75 @@ impl TryInto for EditFieldPayload { } #[derive(Debug, Default, ProtoBuf)] -pub struct FieldTypeOptionContext { +pub struct FieldTypeOptionDataPB { #[pb(index = 1)] pub grid_id: String, #[pb(index = 2)] - pub grid_field: Field, + pub field: FieldPB, #[pb(index = 3)] pub type_option_data: Vec, } #[derive(Debug, Default, ProtoBuf)] -pub struct FieldTypeOptionData { +pub struct RepeatedFieldPB { #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub field: Field, - - #[pb(index = 3)] - pub type_option_data: Vec, + pub items: Vec, } - -#[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedField { - #[pb(index = 1)] - pub items: Vec, -} -impl std::ops::Deref for RepeatedField { - type Target = Vec; +impl std::ops::Deref for RepeatedFieldPB { + type Target = Vec; fn deref(&self) -> &Self::Target { &self.items } } -impl std::ops::DerefMut for RepeatedField { +impl std::ops::DerefMut for RepeatedFieldPB { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.items } } -impl std::convert::From> for RepeatedField { - fn from(items: Vec) -> Self { +impl std::convert::From> for RepeatedFieldPB { + fn from(items: Vec) -> Self { Self { items } } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct RepeatedFieldOrder { +pub struct RepeatedGridFieldPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl std::ops::Deref for RepeatedFieldOrder { - type Target = Vec; +impl std::ops::Deref for RepeatedGridFieldPB { + type Target = Vec; fn deref(&self) -> &Self::Target { &self.items } } -impl std::convert::From> for RepeatedFieldOrder { - fn from(field_orders: Vec) -> Self { - RepeatedFieldOrder { items: field_orders } +impl std::convert::From> for RepeatedGridFieldPB { + fn from(field_orders: Vec) -> Self { + RepeatedGridFieldPB { items: field_orders } } } -impl std::convert::From for RepeatedFieldOrder { +impl std::convert::From for RepeatedGridFieldPB { fn from(s: String) -> Self { - RepeatedFieldOrder { - items: vec![GridField::from(s)], + RepeatedGridFieldPB { + items: vec![GridFieldPB::from(s)], } } } #[derive(ProtoBuf, Default)] -pub struct InsertFieldPayload { +pub struct InsertFieldPayloadPB { #[pb(index = 1)] pub grid_id: String, #[pb(index = 2)] - pub field: Field, + pub field: FieldPB, #[pb(index = 3)] pub type_option_data: Vec, @@ -301,12 +289,12 @@ pub struct InsertFieldPayload { #[derive(Clone)] pub struct InsertFieldParams { pub grid_id: String, - pub field: Field, + pub field: FieldPB, pub type_option_data: Vec, pub start_field_id: Option, } -impl TryInto for InsertFieldPayload { +impl TryInto for InsertFieldPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -328,7 +316,7 @@ impl TryInto for InsertFieldPayload { } #[derive(ProtoBuf, Default)] -pub struct UpdateFieldTypeOptionPayload { +pub struct UpdateFieldTypeOptionPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -346,7 +334,7 @@ pub struct UpdateFieldTypeOptionParams { pub type_option_data: Vec, } -impl TryInto for UpdateFieldTypeOptionPayload { +impl TryInto for UpdateFieldTypeOptionPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -362,20 +350,20 @@ impl TryInto for UpdateFieldTypeOptionPayload { } #[derive(ProtoBuf, Default)] -pub struct QueryFieldPayload { +pub struct QueryFieldPayloadPB { #[pb(index = 1)] pub grid_id: String, #[pb(index = 2)] - pub field_orders: RepeatedFieldOrder, + pub field_orders: RepeatedGridFieldPB, } pub struct QueryFieldParams { pub grid_id: String, - pub field_orders: RepeatedFieldOrder, + pub field_orders: RepeatedGridFieldPB, } -impl TryInto for QueryFieldPayload { +impl TryInto for QueryFieldPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -388,7 +376,7 @@ impl TryInto for QueryFieldPayload { } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct FieldChangesetPayload { +pub struct FieldChangesetPayloadPB { #[pb(index = 1)] pub field_id: String, @@ -417,7 +405,7 @@ pub struct FieldChangesetPayload { pub type_option_data: Option>, } -impl TryInto for FieldChangesetPayload { +impl TryInto for FieldChangesetPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -569,7 +557,7 @@ impl std::convert::From for FieldType { } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct FieldIdentifierPayload { +pub struct FieldIdentifierPayloadPB { #[pb(index = 1)] pub field_id: String, @@ -582,7 +570,7 @@ pub struct FieldIdentifier { pub grid_id: String, } -impl TryInto for FieldIdentifierPayload { +impl TryInto for FieldIdentifierPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs index bc520dea54..03cc3d6111 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/filter_entities/util.rs @@ -17,7 +17,7 @@ pub struct GridFilter { } #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct RepeatedGridFilter { +pub struct RepeatedGridFilterPB { #[pb(index = 1)] pub items: Vec, } @@ -28,22 +28,22 @@ impl std::convert::From<&GridFilterRevision> for GridFilter { } } -impl std::convert::From>> for RepeatedGridFilter { +impl std::convert::From>> for RepeatedGridFilterPB { fn from(revs: Vec>) -> Self { - RepeatedGridFilter { + RepeatedGridFilterPB { items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(), } } } -impl std::convert::From> for RepeatedGridFilter { +impl std::convert::From> for RepeatedGridFilterPB { fn from(items: Vec) -> Self { Self { items } } } #[derive(ProtoBuf, Debug, Default, Clone)] -pub struct DeleteFilterPayload { +pub struct DeleteFilterPayloadPB { #[pb(index = 1)] pub field_id: String, @@ -54,7 +54,7 @@ pub struct DeleteFilterPayload { pub field_type: FieldType, } -impl TryInto for DeleteFilterPayload { +impl TryInto for DeleteFilterPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -73,7 +73,7 @@ impl TryInto for DeleteFilterPayload { } #[derive(ProtoBuf, Debug, Default, Clone)] -pub struct CreateGridFilterPayload { +pub struct CreateGridFilterPayloadPB { #[pb(index = 1)] pub field_id: String, @@ -87,7 +87,7 @@ pub struct CreateGridFilterPayload { pub content: Option, } -impl CreateGridFilterPayload { +impl CreateGridFilterPayloadPB { #[allow(dead_code)] pub fn new>(field_rev: &FieldRevision, condition: T, content: Option) -> Self { Self { @@ -99,7 +99,7 @@ impl CreateGridFilterPayload { } } -impl TryInto for CreateGridFilterPayload { +impl TryInto for CreateGridFilterPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs index 1cc6f2ba45..d333f201a4 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs @@ -1,69 +1,69 @@ -use crate::entities::{GridBlock, GridField}; +use crate::entities::{GridBlockPB, GridFieldPB}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct Grid { +pub struct GridPB { #[pb(index = 1)] pub id: String, #[pb(index = 2)] - pub fields: Vec, + pub fields: Vec, #[pb(index = 3)] - pub blocks: Vec, + pub blocks: Vec, } #[derive(ProtoBuf, Default)] -pub struct CreateGridPayload { +pub struct CreateGridPayloadPB { #[pb(index = 1)] pub name: String, } #[derive(Clone, ProtoBuf, Default, Debug)] -pub struct GridId { +pub struct GridIdPB { #[pb(index = 1)] pub value: String, } -impl AsRef for GridId { +impl AsRef for GridIdPB { fn as_ref(&self) -> &str { &self.value } } #[derive(Clone, ProtoBuf, Default, Debug)] -pub struct GridBlockId { +pub struct GridBlockIdPB { #[pb(index = 1)] pub value: String, } -impl AsRef for GridBlockId { +impl AsRef for GridBlockIdPB { fn as_ref(&self) -> &str { &self.value } } -impl std::convert::From<&str> for GridBlockId { +impl std::convert::From<&str> for GridBlockIdPB { fn from(s: &str) -> Self { - GridBlockId { value: s.to_owned() } + GridBlockIdPB { value: s.to_owned() } } } #[derive(Debug, Clone, ProtoBuf_Enum)] -pub enum MoveItemType { +pub enum MoveItemTypePB { MoveField = 0, MoveRow = 1, } -impl std::default::Default for MoveItemType { +impl std::default::Default for MoveItemTypePB { fn default() -> Self { - MoveItemType::MoveField + MoveItemTypePB::MoveField } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct MoveItemPayload { +pub struct MoveItemPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -77,7 +77,7 @@ pub struct MoveItemPayload { pub to_index: i32, #[pb(index = 5)] - pub ty: MoveItemType, + pub ty: MoveItemTypePB, } #[derive(Clone)] @@ -86,10 +86,10 @@ pub struct MoveItemParams { pub item_id: String, pub from_index: i32, pub to_index: i32, - pub ty: MoveItemType, + pub ty: MoveItemTypePB, } -impl TryInto for MoveItemPayload { +impl TryInto for MoveItemPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs index 53d20bbc57..dda624fc67 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities.rs @@ -7,7 +7,7 @@ use std::convert::TryInto; use std::sync::Arc; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct GridGroup { +pub struct GridGroupPB { #[pb(index = 1)] pub id: String, @@ -18,9 +18,9 @@ pub struct GridGroup { pub sub_group_field_id: Option, } -impl std::convert::From<&GridGroupRevision> for GridGroup { +impl std::convert::From<&GridGroupRevision> for GridGroupPB { fn from(rev: &GridGroupRevision) -> Self { - GridGroup { + GridGroupPB { id: rev.id.clone(), group_field_id: rev.field_id.clone(), sub_group_field_id: rev.sub_field_id.clone(), @@ -29,27 +29,27 @@ impl std::convert::From<&GridGroupRevision> for GridGroup { } #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct RepeatedGridGroup { +pub struct RepeatedGridGroupPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl std::convert::From> for RepeatedGridGroup { - fn from(items: Vec) -> Self { +impl std::convert::From> for RepeatedGridGroupPB { + fn from(items: Vec) -> Self { Self { items } } } -impl std::convert::From>> for RepeatedGridGroup { +impl std::convert::From>> for RepeatedGridGroupPB { fn from(revs: Vec>) -> Self { - RepeatedGridGroup { + RepeatedGridGroupPB { items: revs.iter().map(|rev| rev.as_ref().into()).collect(), } } } #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct CreateGridGroupPayload { +pub struct CreateGridGroupPayloadPB { #[pb(index = 1, one_of)] pub field_id: Option, @@ -57,7 +57,7 @@ pub struct CreateGridGroupPayload { pub sub_field_id: Option, } -impl TryInto for CreateGridGroupPayload { +impl TryInto for CreateGridGroupPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs index 4b3c8a7a78..f66e1c1d06 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs @@ -3,7 +3,7 @@ use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; #[derive(ProtoBuf, Default)] -pub struct GridRowIdPayload { +pub struct GridRowIdPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -15,7 +15,7 @@ pub struct GridRowIdPayload { } #[derive(Debug, Default, Clone, ProtoBuf)] -pub struct GridRowId { +pub struct GridRowIdPB { #[pb(index = 1)] pub grid_id: String, @@ -26,15 +26,15 @@ pub struct GridRowId { pub row_id: String, } -impl TryInto for GridRowIdPayload { +impl TryInto for GridRowIdPayloadPB { type Error = ErrorCode; - fn try_into(self) -> Result { + fn try_into(self) -> Result { 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(GridRowId { + Ok(GridRowIdPB { grid_id: grid_id.0, block_id: block_id.0, row_id: row_id.0, @@ -43,7 +43,7 @@ impl TryInto for GridRowIdPayload { } #[derive(Debug, Default, Clone, ProtoBuf)] -pub struct BlockRowId { +pub struct BlockRowIdPB { #[pb(index = 1)] pub block_id: String, @@ -52,7 +52,7 @@ pub struct BlockRowId { } #[derive(ProtoBuf, Default)] -pub struct CreateRowPayload { +pub struct CreateRowPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -66,7 +66,7 @@ pub struct CreateRowParams { pub start_row_id: Option, } -impl TryInto for CreateRowPayload { +impl TryInto for CreateRowPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs index 740ab38def..9272cfe46d 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs @@ -1,6 +1,6 @@ use crate::entities::{ - CreateGridFilterPayload, CreateGridGroupPayload, CreateGridSortPayload, DeleteFilterPayload, RepeatedGridFilter, - RepeatedGridGroup, RepeatedGridSort, + CreateGridFilterPayloadPB, CreateGridGroupPayloadPB, CreateGridSortPayloadPB, DeleteFilterPayloadPB, + RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB, }; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; @@ -13,34 +13,34 @@ use strum::IntoEnumIterator; use strum_macros::EnumIter; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct GridSetting { +pub struct GridSettingPB { #[pb(index = 1)] - pub layouts: Vec, + pub layouts: Vec, #[pb(index = 2)] pub current_layout_type: GridLayoutType, #[pb(index = 3)] - pub filters_by_field_id: HashMap, + pub filters_by_field_id: HashMap, #[pb(index = 4)] - pub groups_by_field_id: HashMap, + pub groups_by_field_id: HashMap, #[pb(index = 5)] - pub sorts_by_field_id: HashMap, + pub sorts_by_field_id: HashMap, } #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct GridLayout { +pub struct GridLayoutPB { #[pb(index = 1)] ty: GridLayoutType, } -impl GridLayout { - pub fn all() -> Vec { +impl GridLayoutPB { + pub fn all() -> Vec { let mut layouts = vec![]; for layout_ty in GridLayoutType::iter() { - layouts.push(GridLayout { ty: layout_ty }) + layouts.push(GridLayoutPB { ty: layout_ty }) } layouts @@ -79,7 +79,7 @@ impl std::convert::From for GridLayoutRevision { } #[derive(Default, ProtoBuf)] -pub struct GridSettingChangesetPayload { +pub struct GridSettingChangesetPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -87,25 +87,25 @@ pub struct GridSettingChangesetPayload { pub layout_type: GridLayoutType, #[pb(index = 3, one_of)] - pub insert_filter: Option, + pub insert_filter: Option, #[pb(index = 4, one_of)] - pub delete_filter: Option, + pub delete_filter: Option, #[pb(index = 5, one_of)] - pub insert_group: Option, + pub insert_group: Option, #[pb(index = 6, one_of)] pub delete_group: Option, #[pb(index = 7, one_of)] - pub insert_sort: Option, + pub insert_sort: Option, #[pb(index = 8, one_of)] pub delete_sort: Option, } -impl TryInto for GridSettingChangesetPayload { +impl TryInto for GridSettingChangesetPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs index 3a560460fe..b630b000c5 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/sort_entities.rs @@ -26,32 +26,32 @@ impl std::convert::From<&GridSortRevision> for GridSort { } #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct RepeatedGridSort { +pub struct RepeatedGridSortPB { #[pb(index = 1)] pub items: Vec, } -impl std::convert::From>> for RepeatedGridSort { +impl std::convert::From>> for RepeatedGridSortPB { fn from(revs: Vec>) -> Self { - RepeatedGridSort { + RepeatedGridSortPB { items: revs.into_iter().map(|rev| rev.as_ref().into()).collect(), } } } -impl std::convert::From> for RepeatedGridSort { +impl std::convert::From> for RepeatedGridSortPB { fn from(items: Vec) -> Self { Self { items } } } #[derive(ProtoBuf, Debug, Default, Clone)] -pub struct CreateGridSortPayload { +pub struct CreateGridSortPayloadPB { #[pb(index = 1, one_of)] pub field_id: Option, } -impl TryInto for CreateGridSortPayload { +impl TryInto for CreateGridSortPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 52c3c3424c..81f74c8e32 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -3,9 +3,9 @@ use crate::manager::GridManager; use crate::services::cell::AnyCellData; use crate::services::field::{ default_type_option_builder_from_type, select_option_operation, type_option_builder_from_json_str, - DateChangesetParams, DateChangesetPayload, SelectOption, SelectOptionCellChangeset, - SelectOptionCellChangesetParams, SelectOptionCellChangesetPayload, SelectOptionCellData, SelectOptionChangeset, - SelectOptionChangesetPayload, + DateChangesetParams, DateChangesetPayloadPB, SelectOptionPB, SelectOptionCellChangeset, + SelectOptionCellChangesetParams, SelectOptionCellChangesetPayloadPB, SelectOptionCellDataPB, SelectOptionChangeset, + SelectOptionChangesetPayloadPB, }; use crate::services::row::make_row_from_row_rev; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; @@ -16,10 +16,10 @@ use std::sync::Arc; #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn get_grid_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { - let grid_id: GridId = data.into_inner(); +) -> DataResult { + let grid_id: GridIdPB = data.into_inner(); let editor = manager.open_grid(grid_id).await?; let grid = editor.get_grid_data().await?; data_result(grid) @@ -27,10 +27,10 @@ pub(crate) async fn get_grid_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn get_grid_setting_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { - let grid_id: GridId = data.into_inner(); +) -> DataResult { + let grid_id: GridIdPB = data.into_inner(); let editor = manager.open_grid(grid_id).await?; let grid_setting = editor.get_grid_setting().await?; data_result(grid_setting) @@ -38,7 +38,7 @@ pub(crate) async fn get_grid_setting_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn update_grid_setting_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: GridSettingChangesetParams = data.into_inner().try_into()?; @@ -49,9 +49,9 @@ pub(crate) async fn update_grid_setting_handler( #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn get_grid_blocks_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: QueryGridBlocksParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let repeated_grid_block = editor.get_blocks(Some(params.block_ids)).await?; @@ -60,9 +60,9 @@ pub(crate) async fn get_grid_blocks_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn get_fields_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: QueryFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let field_orders = params @@ -72,13 +72,13 @@ pub(crate) async fn get_fields_handler( .map(|field_order| field_order.field_id) .collect(); let field_revs = editor.get_field_revs(Some(field_orders)).await?; - let repeated_field: RepeatedField = field_revs.into_iter().map(Field::from).collect::>().into(); + let repeated_field: RepeatedFieldPB = field_revs.into_iter().map(FieldPB::from).collect::>().into(); data_result(repeated_field) } #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn update_field_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let changeset: FieldChangesetParams = data.into_inner().try_into()?; @@ -89,7 +89,7 @@ pub(crate) async fn update_field_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn insert_field_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: InsertFieldParams = data.into_inner().try_into()?; @@ -100,7 +100,7 @@ pub(crate) async fn insert_field_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn update_field_type_option_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: UpdateFieldTypeOptionParams = data.into_inner().try_into()?; @@ -113,7 +113,7 @@ pub(crate) async fn update_field_type_option_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn delete_field_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: FieldIdentifier = data.into_inner().try_into()?; @@ -124,9 +124,9 @@ pub(crate) async fn delete_field_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn switch_to_field_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: EditFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; editor @@ -140,7 +140,7 @@ pub(crate) async fn switch_to_field_handler( .unwrap_or(Arc::new(editor.next_field_rev(¶ms.field_type).await?)); let type_option_data = get_type_option_data(&field_rev, ¶ms.field_type).await?; - let data = FieldTypeOptionData { + let data = FieldTypeOptionDataPB { grid_id: params.grid_id, field: field_rev.into(), type_option_data, @@ -151,7 +151,7 @@ pub(crate) async fn switch_to_field_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn duplicate_field_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: FieldIdentifier = data.into_inner().try_into()?; @@ -163,9 +163,9 @@ pub(crate) async fn duplicate_field_handler( /// Return the FieldTypeOptionData if the Field exists otherwise return record not found error. #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn get_field_type_option_data_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: EditFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_field_rev(¶ms.field_id).await { @@ -173,7 +173,7 @@ pub(crate) async fn get_field_type_option_data_handler( Some(field_rev) => { let field_type = field_rev.field_type_rev.into(); let type_option_data = get_type_option_data(&field_rev, &field_type).await?; - let data = FieldTypeOptionData { + let data = FieldTypeOptionDataPB { grid_id: params.grid_id, field: field_rev.into(), type_option_data, @@ -186,16 +186,16 @@ pub(crate) async fn get_field_type_option_data_handler( /// Create FieldMeta and save it. Return the FieldTypeOptionData. #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn create_field_type_option_data_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: CreateFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let field_rev = editor.create_next_field_rev(¶ms.field_type).await?; let field_type: FieldType = field_rev.field_type_rev.into(); let type_option_data = get_type_option_data(&field_rev, &field_type).await?; - data_result(FieldTypeOptionData { + data_result(FieldTypeOptionDataPB { grid_id: params.grid_id, field: field_rev.into(), type_option_data, @@ -204,7 +204,7 @@ pub(crate) async fn create_field_type_option_data_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn move_item_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: MoveItemParams = data.into_inner().try_into()?; @@ -227,25 +227,25 @@ 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, + data: Data, manager: AppData>, -) -> DataResult { - let params: GridRowId = data.into_inner().try_into()?; +) -> DataResult { + let params: GridRowIdPB = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let row = editor .get_row_rev(¶ms.row_id) .await? .and_then(make_row_from_row_rev); - data_result(OptionalRow { row }) + data_result(OptionalRowPB { row }) } #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn delete_row_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: GridRowId = data.into_inner().try_into()?; + let params: GridRowIdPB = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.delete_row(¶ms.row_id).await?; Ok(()) @@ -253,10 +253,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, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: GridRowId = data.into_inner().try_into()?; + let params: GridRowIdPB = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.duplicate_row(¶ms.row_id).await?; Ok(()) @@ -264,7 +264,7 @@ pub(crate) async fn duplicate_row_handler( #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn create_row_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: CreateRowParams = data.into_inner().try_into()?; @@ -301,7 +301,7 @@ pub(crate) async fn update_cell_handler( pub(crate) async fn new_select_option_handler( data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: CreateSelectOptionParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_field_rev(¶ms.field_id).await { @@ -316,7 +316,7 @@ pub(crate) async fn new_select_option_handler( #[tracing::instrument(level = "trace", skip_all, err)] pub(crate) async fn update_select_option_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let changeset: SelectOptionChangeset = data.into_inner().try_into()?; @@ -359,13 +359,13 @@ pub(crate) async fn update_select_option_handler( pub(crate) async fn get_select_option_handler( data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: CellIdentifier = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_field_rev(¶ms.field_id).await { None => { tracing::error!("Can't find the select option field with id: {}", params.field_id); - data_result(SelectOptionCellData::default()) + data_result(SelectOptionCellDataPB::default()) } Some(field_rev) => { // @@ -386,7 +386,7 @@ pub(crate) async fn get_select_option_handler( #[tracing::instrument(level = "trace", skip_all, err)] pub(crate) async fn update_select_option_cell_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: SelectOptionCellChangesetParams = data.into_inner().try_into()?; @@ -397,7 +397,7 @@ pub(crate) async fn update_select_option_cell_handler( #[tracing::instrument(level = "trace", skip_all, err)] pub(crate) async fn update_date_cell_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: DateChangesetParams = data.into_inner().try_into()?; 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 c52f0662ec..0bbd3b09f0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs @@ -1,5 +1,5 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; -use crate::entities::{CellChangeset, GridBlockChangeset, InsertedRow, Row, UpdatedRow}; +use crate::entities::{CellChangeset, GridBlockChangesetPB, GridRowPB, InsertedRowPB, UpdatedRowPB}; use crate::manager::GridUser; use crate::services::block_revision_editor::GridBlockRevisionEditor; use crate::services::persistence::block_index::BlockIndexCache; @@ -71,12 +71,12 @@ impl GridBlockManager { let _ = self.persistence.insert(&row_rev.block_id, &row_rev.id)?; let editor = self.get_editor(&row_rev.block_id).await?; - let mut index_row_order = InsertedRow::from(&row_rev); + let mut index_row_order = InsertedRowPB::from(&row_rev); let (row_count, row_index) = editor.create_row(row_rev, start_row_id).await?; index_row_order.index = row_index; let _ = self - .notify_did_update_block(block_id, GridBlockChangeset::insert(block_id, vec![index_row_order])) + .notify_did_update_block(block_id, GridBlockChangesetPB::insert(block_id, vec![index_row_order])) .await?; Ok(row_count) } @@ -92,7 +92,7 @@ impl GridBlockManager { let mut row_count = 0; for row in row_revs { let _ = self.persistence.insert(&row.block_id, &row.id)?; - let mut row_order = InsertedRow::from(&row); + let mut row_order = InsertedRowPB::from(&row); let (count, index) = editor.create_row(row, None).await?; row_count = count; row_order.index = index; @@ -101,7 +101,7 @@ impl GridBlockManager { changesets.push(GridBlockMetaRevisionChangeset::from_row_count(&block_id, row_count)); let _ = self - .notify_did_update_block(&block_id, GridBlockChangeset::insert(&block_id, inserted_row_orders)) + .notify_did_update_block(&block_id, GridBlockChangesetPB::insert(&block_id, inserted_row_orders)) .await?; } @@ -110,7 +110,7 @@ impl GridBlockManager { pub async fn update_row(&self, changeset: RowMetaChangeset, row_builder: F) -> FlowyResult<()> where - F: FnOnce(Arc) -> Option, + F: FnOnce(Arc) -> Option, { let editor = self.get_editor_from_row_id(&changeset.row_id).await?; let _ = editor.update_row(changeset.clone()).await?; @@ -118,8 +118,8 @@ impl GridBlockManager { None => tracing::error!("Internal error: can't find the row with id: {}", changeset.row_id), Some(row_rev) => { if let Some(row) = row_builder(row_rev.clone()) { - let row_order = UpdatedRow::new(&row_rev, row); - let block_order_changeset = GridBlockChangeset::update(&editor.block_id, vec![row_order]); + let row_order = UpdatedRowPB::new(&row_rev, row); + let block_order_changeset = GridBlockChangesetPB::update(&editor.block_id, vec![row_order]); let _ = self .notify_did_update_block(&editor.block_id, block_order_changeset) .await?; @@ -138,7 +138,7 @@ impl GridBlockManager { Some(row_info) => { let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?; let _ = self - .notify_did_update_block(&block_id, GridBlockChangeset::delete(&block_id, vec![row_info.id])) + .notify_did_update_block(&block_id, GridBlockChangesetPB::delete(&block_id, vec![row_info.id])) .await?; } } @@ -146,7 +146,10 @@ impl GridBlockManager { Ok(()) } - pub(crate) async fn delete_rows(&self, row_orders: Vec) -> FlowyResult> { + pub(crate) async fn delete_rows( + &self, + row_orders: Vec, + ) -> FlowyResult> { let mut changesets = vec![]; for grid_block in block_from_row_orders(row_orders) { let editor = self.get_editor(&grid_block.id).await?; @@ -170,14 +173,14 @@ impl GridBlockManager { match editor.get_row_revs(Some(vec![Cow::Borrowed(row_id)])).await?.pop() { None => {} Some(row_rev) => { - let insert_row = InsertedRow { + let insert_row = InsertedRowPB { block_id: row_rev.block_id.clone(), row_id: row_rev.id.clone(), index: Some(to as i32), height: row_rev.height, }; - let notified_changeset = GridBlockChangeset { + let notified_changeset = GridBlockChangesetPB { block_id: editor.block_id.clone(), inserted_rows: vec![insert_row], deleted_rows: vec![row_rev.id.clone()], @@ -195,7 +198,7 @@ impl GridBlockManager { pub async fn update_cell(&self, changeset: CellChangeset, row_builder: F) -> FlowyResult<()> where - F: FnOnce(Arc) -> Option, + F: FnOnce(Arc) -> Option, { let row_changeset: RowMetaChangeset = changeset.clone().into(); let _ = self.update_row(row_changeset, row_builder).await?; @@ -214,7 +217,7 @@ impl GridBlockManager { } } - pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult> { + pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult> { let editor = self.get_editor(block_id).await?; editor.get_row_infos::<&str>(None).await } @@ -244,7 +247,7 @@ impl GridBlockManager { Ok(snapshots) } - async fn notify_did_update_block(&self, block_id: &str, changeset: GridBlockChangeset) -> FlowyResult<()> { + async fn notify_did_update_block(&self, block_id: &str, changeset: GridBlockChangesetPB) -> FlowyResult<()> { send_dart_notification(block_id, GridNotification::DidUpdateGridBlock) .payload(changeset) .send(); diff --git a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs index 99d851a7d5..3b94665283 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs @@ -1,4 +1,4 @@ -use crate::entities::Row; +use crate::entities::GridRowPB; use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision}; @@ -123,12 +123,12 @@ impl GridBlockRevisionEditor { Ok(cell_revs) } - pub async fn get_row_info(&self, row_id: &str) -> FlowyResult> { + pub async fn get_row_info(&self, row_id: &str) -> FlowyResult> { let row_ids = Some(vec![Cow::Borrowed(row_id)]); Ok(self.get_row_infos(row_ids).await?.pop()) } - pub async fn get_row_infos(&self, row_ids: Option>>) -> FlowyResult> + pub async fn get_row_infos(&self, row_ids: Option>>) -> FlowyResult> where T: AsRef + ToOwned + ?Sized, { @@ -138,8 +138,8 @@ impl GridBlockRevisionEditor { .await .get_row_revs(row_ids)? .iter() - .map(Row::from) - .collect::>(); + .map(GridRowPB::from) + .collect::>(); Ok(row_infos) } diff --git a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs index b4729c6925..e34f3a8430 100644 --- a/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/cell/cell_operation.rs @@ -58,7 +58,9 @@ pub fn apply_cell_data_changeset>( FieldType::RichText => RichTextTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::Number => NumberTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::DateTime => DateTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), - FieldType::SingleSelect => SingleSelectTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), + FieldType::SingleSelect => { + SingleSelectTypeOptionPB::from(field_rev).apply_changeset(changeset.into(), cell_rev) + } FieldType::MultiSelect => MultiSelectTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::Checkbox => CheckboxTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), FieldType::URL => URLTypeOption::from(field_rev).apply_changeset(changeset.into(), cell_rev), @@ -104,7 +106,7 @@ pub fn try_decode_cell_data( .get_type_option_entry::(field_type)? .decode_cell_data(cell_data.into(), s_field_type, field_rev), FieldType::SingleSelect => field_rev - .get_type_option_entry::(field_type)? + .get_type_option_entry::(field_type)? .decode_cell_data(cell_data.into(), s_field_type, field_rev), FieldType::MultiSelect => field_rev .get_type_option_entry::(field_type)? diff --git a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs index 352d3e7f5c..dea6686915 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs @@ -1,4 +1,4 @@ -use crate::entities::{Field, FieldType}; +use crate::entities::{FieldPB, FieldType}; use crate::services::field::type_options::*; use bytes::Bytes; use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry}; @@ -28,7 +28,7 @@ impl FieldBuilder { Self::new(type_option_builder) } - pub fn from_field(field: Field, type_option_builder: Box) -> Self { + pub fn from_field(field: FieldPB, type_option_builder: Box) -> Self { let field_rev = FieldRevision { id: field.id, name: field.name, @@ -93,7 +93,7 @@ pub fn default_type_option_builder_from_type(field_type: &FieldType) -> Box RichTextTypeOption::default().into(), FieldType::Number => NumberTypeOption::default().into(), FieldType::DateTime => DateTypeOption::default().into(), - FieldType::SingleSelect => SingleSelectTypeOption::default().into(), + FieldType::SingleSelect => SingleSelectTypeOptionPB::default().into(), FieldType::MultiSelect => MultiSelectTypeOption::default().into(), FieldType::Checkbox => CheckboxTypeOption::default().into(), FieldType::URL => URLTypeOption::default().into(), diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs index 0c81268f77..5bb2b1c415 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs @@ -14,7 +14,7 @@ mod tests { let field_rev = FieldBuilder::from_field_type(&field_type).build(); assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some("1e".to_string()), time: Some("23:00".to_owned()), }, @@ -60,7 +60,7 @@ mod tests { TimeFormat::TwentyFourHour => { assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(1653609600.to_string()), time: None, }, @@ -70,7 +70,7 @@ mod tests { ); assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(1653609600.to_string()), time: Some("23:00".to_owned()), }, @@ -82,7 +82,7 @@ mod tests { TimeFormat::TwelveHour => { assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(1653609600.to_string()), time: None, }, @@ -93,7 +93,7 @@ mod tests { // assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(1653609600.to_string()), time: Some("".to_owned()), }, @@ -104,7 +104,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(1653609600.to_string()), time: Some("11:23 pm".to_owned()), }, @@ -126,7 +126,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(date_timestamp.clone()), time: None, }, @@ -138,7 +138,7 @@ mod tests { type_option.include_time = true; assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(date_timestamp.clone()), time: None, }, @@ -149,7 +149,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(date_timestamp.clone()), time: Some("1:00".to_owned()), }, @@ -161,7 +161,7 @@ mod tests { type_option.time_format = TimeFormat::TwelveHour; assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(date_timestamp), time: Some("1:00 am".to_owned()), }, @@ -181,7 +181,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(date_timestamp.clone()), time: Some("1:".to_owned()), }, @@ -192,7 +192,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(date_timestamp), time: Some("1:00".to_owned()), }, @@ -212,7 +212,7 @@ mod tests { assert_changeset_result( &type_option, - DateCellChangeset { + DateCellChangesetPB { date: Some(date_timestamp), time: Some("1:00 am".to_owned()), }, @@ -224,7 +224,7 @@ mod tests { fn assert_changeset_result( type_option: &DateTypeOption, - changeset: DateCellChangeset, + changeset: DateCellChangesetPB, _field_type: &FieldType, field_rev: &FieldRevision, expected: &str, @@ -243,7 +243,7 @@ mod tests { field_rev: &FieldRevision, expected: &str, ) { - let s = serde_json::to_string(&DateCellChangeset { + let s = serde_json::to_string(&DateCellChangesetPB { date: Some(timestamp.to_string()), time: None, }) diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs index 783b9faa7c..17b897b1f0 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs @@ -2,7 +2,7 @@ use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; use crate::services::field::{ - BoxTypeOptionBuilder, DateCellChangeset, DateCellData, DateFormat, DateTimestamp, TimeFormat, TypeOptionBuilder, + BoxTypeOptionBuilder, DateCellChangesetPB, DateCellDataPB, DateFormat, DateTimestamp, TimeFormat, TypeOptionBuilder, }; use bytes::Bytes; use chrono::format::strftime::StrftimeItems; @@ -32,15 +32,15 @@ impl DateTypeOption { Self::default() } - fn today_desc_from_timestamp>(&self, timestamp: T) -> DateCellData { + fn today_desc_from_timestamp>(&self, timestamp: T) -> DateCellDataPB { let timestamp = *timestamp.as_ref(); let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0); self.date_from_native(native) } - fn date_from_native(&self, native: chrono::NaiveDateTime) -> DateCellData { + fn date_from_native(&self, native: chrono::NaiveDateTime) -> DateCellDataPB { if native.timestamp() == 0 { - return DateCellData::default(); + return DateCellDataPB::default(); } let time = native.time(); @@ -57,7 +57,7 @@ impl DateTypeOption { } let timestamp = native.timestamp(); - DateCellData { date, time, timestamp } + DateCellDataPB { date, time, timestamp } } fn date_fmt(&self, time: &Option) -> String { @@ -129,7 +129,7 @@ impl CellDisplayable for DateTypeOption { } } -impl CellDataOperation for DateTypeOption { +impl CellDataOperation for DateTypeOption { fn decode_cell_data( &self, cell_data: CellData, @@ -148,7 +148,7 @@ impl CellDataOperation for DateTypeOption { fn apply_changeset( &self, - changeset: CellDataChangeset, + changeset: CellDataChangeset, _cell_rev: Option, ) -> Result { let changeset = changeset.try_into_inner()?; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs index b73c89a9b2..28dfd90dcf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use strum_macros::EnumIter; #[derive(Clone, Debug, Default, ProtoBuf)] -pub struct DateCellData { +pub struct DateCellDataPB { #[pb(index = 1)] pub date: String, @@ -22,7 +22,7 @@ pub struct DateCellData { } #[derive(Clone, Debug, Default, ProtoBuf)] -pub struct DateChangesetPayload { +pub struct DateChangesetPayloadPB { #[pb(index = 1)] pub cell_identifier: CellIdentifierPayload, @@ -39,7 +39,7 @@ pub struct DateChangesetParams { pub time: Option, } -impl TryInto for DateChangesetPayload { +impl TryInto for DateChangesetPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -54,7 +54,7 @@ impl TryInto for DateChangesetPayload { impl std::convert::From for CellChangeset { fn from(params: DateChangesetParams) -> Self { - let changeset = DateCellChangeset { + let changeset = DateCellChangesetPB { date: params.date, time: params.time, }; @@ -69,12 +69,12 @@ impl std::convert::From for CellChangeset { } #[derive(Clone, Serialize, Deserialize)] -pub struct DateCellChangeset { +pub struct DateCellChangesetPB { pub date: Option, pub time: Option, } -impl DateCellChangeset { +impl DateCellChangesetPB { pub fn date_timestamp(&self) -> Option { if let Some(date) = &self.date { match date.parse::() { @@ -87,12 +87,12 @@ impl DateCellChangeset { } } -impl FromCellChangeset for DateCellChangeset { +impl FromCellChangeset for DateCellChangesetPB { fn from_changeset(changeset: String) -> FlowyResult where Self: Sized, { - serde_json::from_str::(&changeset).map_err(internal_error) + serde_json::from_str::(&changeset).map_err(internal_error) } } pub struct DateTimestamp(i64); @@ -202,9 +202,9 @@ impl std::default::Default for TimeFormat { pub struct DateCellDataParser(); impl CellBytesParser for DateCellDataParser { - type Object = DateCellData; + type Object = DateCellDataPB; fn parse(&self, bytes: &Bytes) -> FlowyResult { - DateCellData::try_from(bytes.as_ref()).map_err(internal_error) + DateCellDataPB::try_from(bytes.as_ref()).map_err(internal_error) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs index 759114ca5a..187b81d060 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/multi_select_type_option.rs @@ -3,8 +3,8 @@ use crate::impl_type_option; use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; use crate::services::field::type_options::util::get_cell_data; use crate::services::field::{ - make_selected_select_options, BoxTypeOptionBuilder, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, - SelectOptionIds, SelectOptionOperation, TypeOptionBuilder, SELECTION_IDS_SEPARATOR, + make_selected_select_options, BoxTypeOptionBuilder, SelectOptionCellChangeset, SelectOptionCellDataPB, + SelectOptionIds, SelectOptionOperation, SelectOptionPB, TypeOptionBuilder, SELECTION_IDS_SEPARATOR, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] pub struct MultiSelectTypeOption { #[pb(index = 1)] - pub options: Vec, + pub options: Vec, #[pb(index = 2)] pub disable_color: bool, @@ -24,19 +24,19 @@ pub struct MultiSelectTypeOption { impl_type_option!(MultiSelectTypeOption, FieldType::MultiSelect); impl SelectOptionOperation for MultiSelectTypeOption { - fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellData { + fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellDataPB { let select_options = make_selected_select_options(cell_data, &self.options); - SelectOptionCellData { + SelectOptionCellDataPB { options: self.options.clone(), select_options, } } - fn options(&self) -> &Vec { + fn options(&self) -> &Vec { &self.options } - fn mut_options(&mut self) -> &mut Vec { + fn mut_options(&mut self) -> &mut Vec { &mut self.options } } @@ -97,7 +97,7 @@ pub struct MultiSelectTypeOptionBuilder(MultiSelectTypeOption); impl_into_box_type_option_builder!(MultiSelectTypeOptionBuilder); impl_builder_from_json_str_and_from_bytes!(MultiSelectTypeOptionBuilder, MultiSelectTypeOption); impl MultiSelectTypeOptionBuilder { - pub fn option(mut self, opt: SelectOption) -> Self { + pub fn option(mut self, opt: SelectOptionPB) -> Self { self.0.options.push(opt); self } @@ -123,9 +123,9 @@ mod tests { #[test] fn multi_select_test() { - let google_option = SelectOption::new("Google"); - let facebook_option = SelectOption::new("Facebook"); - let twitter_option = SelectOption::new("Twitter"); + let google_option = SelectOptionPB::new("Google"); + let facebook_option = SelectOptionPB::new("Facebook"); + let twitter_option = SelectOptionPB::new("Twitter"); let multi_select = MultiSelectTypeOptionBuilder::default() .option(google_option.clone()) .option(facebook_option.clone()) @@ -172,7 +172,7 @@ mod tests { cell_data: String, type_option: &MultiSelectTypeOption, field_rev: &FieldRevision, - expected: Vec, + expected: Vec, ) { let field_type: FieldType = field_rev.field_type_rev.into(); assert_eq!( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index c06bf25957..e3dd16ef2f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -1,6 +1,6 @@ use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType}; use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString}; -use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; +use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{internal_error, ErrorCode, FlowyResult}; @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; pub const SELECTION_IDS_SEPARATOR: &str = ","; #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)] -pub struct SelectOption { +pub struct SelectOptionPB { #[pb(index = 1)] pub id: String, @@ -20,20 +20,20 @@ pub struct SelectOption { pub name: String, #[pb(index = 3)] - pub color: SelectOptionColor, + pub color: SelectOptionColorPB, } -impl SelectOption { +impl SelectOptionPB { pub fn new(name: &str) -> Self { - SelectOption { + SelectOptionPB { id: nanoid!(4), name: name.to_owned(), - color: SelectOptionColor::default(), + color: SelectOptionColorPB::default(), } } - pub fn with_color(name: &str, color: SelectOptionColor) -> Self { - SelectOption { + pub fn with_color(name: &str, color: SelectOptionColorPB) -> Self { + SelectOptionPB { id: nanoid!(4), name: name.to_owned(), color, @@ -43,7 +43,7 @@ impl SelectOption { #[derive(ProtoBuf_Enum, PartialEq, Eq, Serialize, Deserialize, Debug, Clone)] #[repr(u8)] -pub enum SelectOptionColor { +pub enum SelectOptionColorPB { Purple = 0, Pink = 1, LightPink = 2, @@ -55,16 +55,16 @@ pub enum SelectOptionColor { Blue = 8, } -impl std::default::Default for SelectOptionColor { +impl std::default::Default for SelectOptionColorPB { fn default() -> Self { - SelectOptionColor::Purple + SelectOptionColorPB::Purple } } pub fn make_selected_select_options( cell_data: CellData, - options: &[SelectOption], -) -> Vec { + options: &[SelectOptionPB], +) -> Vec { if let Ok(ids) = cell_data.try_into_inner() { ids.iter() .flat_map(|option_id| options.iter().find(|option| &option.id == option_id).cloned()) @@ -75,7 +75,7 @@ pub fn make_selected_select_options( } pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync { - fn insert_option(&mut self, new_option: SelectOption) { + fn insert_option(&mut self, new_option: SelectOptionPB) { let options = self.mut_options(); if let Some(index) = options .iter() @@ -88,23 +88,23 @@ pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync { } } - fn delete_option(&mut self, delete_option: SelectOption) { + fn delete_option(&mut self, delete_option: SelectOptionPB) { let options = self.mut_options(); if let Some(index) = options.iter().position(|option| option.id == delete_option.id) { options.remove(index); } } - fn create_option(&self, name: &str) -> SelectOption { + fn create_option(&self, name: &str) -> SelectOptionPB { let color = select_option_color_from_index(self.options().len()); - SelectOption::with_color(name, color) + SelectOptionPB::with_color(name, color) } - fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellData; + fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellDataPB; - fn options(&self) -> &Vec; + fn options(&self) -> &Vec; - fn mut_options(&mut self) -> &mut Vec; + fn mut_options(&mut self) -> &mut Vec; } impl CellDisplayable for T @@ -125,7 +125,7 @@ pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult { - let type_option = SingleSelectTypeOption::from(field_rev); + let type_option = SingleSelectTypeOptionPB::from(field_rev); Ok(Box::new(type_option)) } FieldType::MultiSelect => { @@ -139,18 +139,18 @@ pub fn select_option_operation(field_rev: &FieldRevision) -> FlowyResult SelectOptionColor { +pub fn select_option_color_from_index(index: usize) -> SelectOptionColorPB { match index % 8 { - 0 => SelectOptionColor::Purple, - 1 => SelectOptionColor::Pink, - 2 => SelectOptionColor::LightPink, - 3 => SelectOptionColor::Orange, - 4 => SelectOptionColor::Yellow, - 5 => SelectOptionColor::Lime, - 6 => SelectOptionColor::Green, - 7 => SelectOptionColor::Aqua, - 8 => SelectOptionColor::Blue, - _ => SelectOptionColor::Purple, + 0 => SelectOptionColorPB::Purple, + 1 => SelectOptionColorPB::Pink, + 2 => SelectOptionColorPB::LightPink, + 3 => SelectOptionColorPB::Orange, + 4 => SelectOptionColorPB::Yellow, + 5 => SelectOptionColorPB::Lime, + 6 => SelectOptionColorPB::Green, + 7 => SelectOptionColorPB::Aqua, + 8 => SelectOptionColorPB::Blue, + _ => SelectOptionColorPB::Purple, } } pub struct SelectOptionIds(Vec); @@ -215,15 +215,15 @@ impl CellBytesParser for SelectOptionIdsParser { pub struct SelectOptionCellDataParser(); impl CellBytesParser for SelectOptionCellDataParser { - type Object = SelectOptionCellData; + type Object = SelectOptionCellDataPB; fn parse(&self, bytes: &Bytes) -> FlowyResult { - SelectOptionCellData::try_from(bytes.as_ref()).map_err(internal_error) + SelectOptionCellDataPB::try_from(bytes.as_ref()).map_err(internal_error) } } #[derive(Clone, Debug, Default, ProtoBuf)] -pub struct SelectOptionCellChangesetPayload { +pub struct SelectOptionCellChangesetPayloadPB { #[pb(index = 1)] pub cell_identifier: CellIdentifierPayload, @@ -256,7 +256,7 @@ impl std::convert::From for CellChangeset { } } -impl TryInto for SelectOptionCellChangesetPayload { +impl TryInto for SelectOptionCellChangesetPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -323,37 +323,37 @@ impl SelectOptionCellChangeset { } #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] -pub struct SelectOptionCellData { +pub struct SelectOptionCellDataPB { #[pb(index = 1)] - pub options: Vec, + pub options: Vec, #[pb(index = 2)] - pub select_options: Vec, + pub select_options: Vec, } #[derive(Clone, Debug, Default, ProtoBuf)] -pub struct SelectOptionChangesetPayload { +pub struct SelectOptionChangesetPayloadPB { #[pb(index = 1)] pub cell_identifier: CellIdentifierPayload, #[pb(index = 2, one_of)] - pub insert_option: Option, + pub insert_option: Option, #[pb(index = 3, one_of)] - pub update_option: Option, + pub update_option: Option, #[pb(index = 4, one_of)] - pub delete_option: Option, + pub delete_option: Option, } pub struct SelectOptionChangeset { pub cell_identifier: CellIdentifier, - pub insert_option: Option, - pub update_option: Option, - pub delete_option: Option, + pub insert_option: Option, + pub update_option: Option, + pub delete_option: Option, } -impl TryInto for SelectOptionChangesetPayload { +impl TryInto for SelectOptionChangesetPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -368,11 +368,11 @@ impl TryInto for SelectOptionChangesetPayload { } pub struct SelectedSelectOptions { - pub(crate) options: Vec, + pub(crate) options: Vec, } -impl std::convert::From for SelectedSelectOptions { - fn from(data: SelectOptionCellData) -> Self { +impl std::convert::From for SelectedSelectOptions { + fn from(data: SelectOptionCellDataPB) -> Self { Self { options: data.select_options, } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs index 8aae4bf677..553425222e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/single_select_type_option.rs @@ -2,8 +2,8 @@ use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; use crate::services::field::{ - make_selected_select_options, SelectOption, SelectOptionCellChangeset, SelectOptionCellData, SelectOptionIds, - SelectOptionOperation, + make_selected_select_options, SelectOptionCellChangeset, SelectOptionCellDataPB, SelectOptionIds, + SelectOptionOperation, SelectOptionPB, }; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use bytes::Bytes; @@ -14,36 +14,36 @@ use serde::{Deserialize, Serialize}; // Single select #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] -pub struct SingleSelectTypeOption { +pub struct SingleSelectTypeOptionPB { #[pb(index = 1)] - pub options: Vec, + pub options: Vec, #[pb(index = 2)] pub disable_color: bool, } -impl_type_option!(SingleSelectTypeOption, FieldType::SingleSelect); +impl_type_option!(SingleSelectTypeOptionPB, FieldType::SingleSelect); -impl SelectOptionOperation for SingleSelectTypeOption { - fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellData { +impl SelectOptionOperation for SingleSelectTypeOptionPB { + fn selected_select_option(&self, cell_data: CellData) -> SelectOptionCellDataPB { let mut select_options = make_selected_select_options(cell_data, &self.options); // only keep option in single select select_options.truncate(1); - SelectOptionCellData { + SelectOptionCellDataPB { options: self.options.clone(), select_options, } } - fn options(&self) -> &Vec { + fn options(&self) -> &Vec { &self.options } - fn mut_options(&mut self) -> &mut Vec { + fn mut_options(&mut self) -> &mut Vec { &mut self.options } } -impl CellDataOperation for SingleSelectTypeOption { +impl CellDataOperation for SingleSelectTypeOptionPB { fn decode_cell_data( &self, cell_data: CellData, @@ -77,12 +77,12 @@ impl CellDataOperation for SingleSel } #[derive(Default)] -pub struct SingleSelectTypeOptionBuilder(SingleSelectTypeOption); +pub struct SingleSelectTypeOptionBuilder(SingleSelectTypeOptionPB); impl_into_box_type_option_builder!(SingleSelectTypeOptionBuilder); -impl_builder_from_json_str_and_from_bytes!(SingleSelectTypeOptionBuilder, SingleSelectTypeOption); +impl_builder_from_json_str_and_from_bytes!(SingleSelectTypeOptionBuilder, SingleSelectTypeOptionPB); impl SingleSelectTypeOptionBuilder { - pub fn option(mut self, opt: SelectOption) -> Self { + pub fn option(mut self, opt: SelectOptionPB) -> Self { self.0.options.push(opt); self } @@ -109,9 +109,9 @@ mod tests { #[test] fn single_select_test() { - let google_option = SelectOption::new("Google"); - let facebook_option = SelectOption::new("Facebook"); - let twitter_option = SelectOption::new("Twitter"); + let google_option = SelectOptionPB::new("Google"); + let facebook_option = SelectOptionPB::new("Facebook"); + let twitter_option = SelectOptionPB::new("Twitter"); let single_select = SingleSelectTypeOptionBuilder::default() .option(google_option.clone()) .option(facebook_option.clone()) @@ -122,7 +122,7 @@ mod tests { .visibility(true) .build(); - let type_option = SingleSelectTypeOption::from(&field_rev); + let type_option = SingleSelectTypeOptionPB::from(&field_rev); let option_ids = vec![google_option.id.clone(), facebook_option.id].join(SELECTION_IDS_SEPARATOR); let data = SelectOptionCellChangeset::from_insert(&option_ids).to_str(); @@ -152,9 +152,9 @@ mod tests { fn assert_single_select_options( cell_data: String, - type_option: &SingleSelectTypeOption, + type_option: &SingleSelectTypeOptionPB, field_rev: &FieldRevision, - expected: Vec, + expected: Vec, ) { let field_type: FieldType = field_rev.field_type_rev.into(); assert_eq!( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs index 2716206dfd..b11bd026d2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option/text_type_option.rs @@ -131,7 +131,7 @@ mod tests { ); // Single select - let done_option = SelectOption::new("Done"); + let done_option = SelectOptionPB::new("Done"); let done_option_id = done_option.id.clone(); let single_select = SingleSelectTypeOptionBuilder::default().option(done_option.clone()); let single_select_field_rev = FieldBuilder::new(single_select).build(); @@ -151,8 +151,8 @@ mod tests { ); // Multiple select - let google_option = SelectOption::new("Google"); - let facebook_option = SelectOption::new("Facebook"); + let google_option = SelectOptionPB::new("Google"); + let facebook_option = SelectOptionPB::new("Facebook"); let ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); let cell_data_changeset = SelectOptionCellChangeset::from_insert(&ids).to_str(); let multi_select = MultiSelectTypeOptionBuilder::default() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs index 6f74bdb4d4..77f4ea767e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs @@ -3,7 +3,7 @@ mod tests { use crate::entities::FieldType; use crate::services::cell::{CellData, CellDataOperation}; use crate::services::field::{FieldBuilder, URLCellDataParser}; - use crate::services::field::{URLCellData, URLTypeOption}; + use crate::services::field::{URLCellDataPB, URLTypeOption}; use flowy_grid_data_model::revision::FieldRevision; #[test] @@ -52,12 +52,12 @@ mod tests { assert_eq!(expected_url.to_owned(), decode_cell_data.url); } - fn decode_cell_data>>( + fn decode_cell_data>>( encoded_data: T, type_option: &URLTypeOption, field_rev: &FieldRevision, field_type: &FieldType, - ) -> URLCellData { + ) -> URLCellDataPB { type_option .decode_cell_data(encoded_data.into(), field_type, field_rev) .unwrap() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs index 0d4ceb5caf..3fa49dac09 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option.rs @@ -1,7 +1,7 @@ use crate::entities::FieldType; use crate::impl_type_option; use crate::services::cell::{CellBytes, CellData, CellDataChangeset, CellDataOperation, CellDisplayable}; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder, URLCellData}; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder, URLCellDataPB}; use bytes::Bytes; use fancy_regex::Regex; use flowy_derive::ProtoBuf; @@ -32,22 +32,22 @@ pub struct URLTypeOption { } impl_type_option!(URLTypeOption, FieldType::URL); -impl CellDisplayable for URLTypeOption { +impl CellDisplayable for URLTypeOption { fn display_data( &self, - cell_data: CellData, + cell_data: CellData, _decoded_field_type: &FieldType, _field_rev: &FieldRevision, ) -> FlowyResult { - let cell_data: URLCellData = cell_data.try_into_inner()?; + let cell_data: URLCellDataPB = cell_data.try_into_inner()?; CellBytes::from(cell_data) } } -impl CellDataOperation for URLTypeOption { +impl CellDataOperation for URLTypeOption { fn decode_cell_data( &self, - cell_data: CellData, + cell_data: CellData, decoded_field_type: &FieldType, field_rev: &FieldRevision, ) -> FlowyResult { @@ -67,7 +67,7 @@ impl CellDataOperation for URLTypeOption { if let Ok(Some(m)) = URL_REGEX.find(&content) { url = auto_append_scheme(m.as_str()); } - URLCellData { url, content }.to_json() + URLCellDataPB { url, content }.to_json() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs index ddb84cf9a7..6ff77cea9a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_type_option_entities.rs @@ -5,7 +5,7 @@ use flowy_error::{internal_error, FlowyResult}; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] -pub struct URLCellData { +pub struct URLCellDataPB { #[pb(index = 1)] pub url: String, @@ -13,7 +13,7 @@ pub struct URLCellData { pub content: String, } -impl URLCellData { +impl URLCellDataPB { pub fn new(s: &str) -> Self { Self { url: "".to_string(), @@ -28,15 +28,15 @@ impl URLCellData { pub struct URLCellDataParser(); impl CellBytesParser for URLCellDataParser { - type Object = URLCellData; + type Object = URLCellDataPB; fn parse(&self, bytes: &Bytes) -> FlowyResult { - URLCellData::try_from(bytes.as_ref()).map_err(internal_error) + URLCellDataPB::try_from(bytes.as_ref()).map_err(internal_error) } } -impl FromCellString for URLCellData { +impl FromCellString for URLCellDataPB { fn from_cell_str(s: &str) -> FlowyResult { - serde_json::from_str::(s).map_err(internal_error) + serde_json::from_str::(s).map_err(internal_error) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs index 6442dd4710..be02e80ebd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs @@ -1,10 +1,10 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; -use crate::entities::{FieldType, GridBlockChangeset}; +use crate::entities::{FieldType, GridBlockChangesetPB}; use crate::services::block_manager::GridBlockManager; use crate::services::cell::{AnyCellData, CellFilterOperation}; use crate::services::field::{ CheckboxTypeOption, DateTypeOption, MultiSelectTypeOption, NumberTypeOption, RichTextTypeOption, - SingleSelectTypeOption, URLTypeOption, + SingleSelectTypeOptionPB, URLTypeOption, }; use crate::services::filter::filter_cache::{ refresh_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache, @@ -90,7 +90,7 @@ impl GridFilterService { } } - let changeset = GridBlockChangeset { + let changeset = GridBlockChangesetPB { block_id: block.block_id, hide_rows, visible_rows, @@ -137,7 +137,7 @@ impl GridFilterService { } } - async fn notify(&self, changesets: Vec) { + async fn notify(&self, changesets: Vec) { for changeset in changesets { send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridBlock) .payload(changeset) @@ -213,7 +213,7 @@ fn filter_cell( FieldType::SingleSelect => filter_cache.select_option_filter.get(&filter_id).and_then(|filter| { Some( field_rev - .get_type_option_entry::(field_type_rev)? + .get_type_option_entry::(field_type_rev)? .apply_filter(any_cell_data, filter.value()) .ok(), ) diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs index 82d5ab6a0b..e6cb9ff846 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/impls/select_option_filter.rs @@ -2,7 +2,7 @@ use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; use crate::services::cell::{AnyCellData, CellFilterOperation}; -use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; +use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; use crate::services::field::{SelectOptionOperation, SelectedSelectOptions}; use flowy_error::FlowyResult; @@ -50,7 +50,7 @@ impl CellFilterOperation for MultiSelectTypeOption { } } -impl CellFilterOperation for SingleSelectTypeOption { +impl CellFilterOperation for SingleSelectTypeOptionPB { fn apply_filter(&self, any_cell_data: AnyCellData, filter: &GridSelectOptionFilter) -> FlowyResult { if !any_cell_data.is_single_select() { return Ok(true); @@ -64,13 +64,13 @@ impl CellFilterOperation for SingleSelectTypeOption { mod tests { #![allow(clippy::all)] use crate::entities::{GridSelectOptionFilter, SelectOptionCondition}; - use crate::services::field::selection_type_option::{SelectOption, SelectedSelectOptions}; + use crate::services::field::selection_type_option::{SelectOptionPB, SelectedSelectOptions}; #[test] fn select_option_filter_is_test() { - let option_1 = SelectOption::new("A"); - let option_2 = SelectOption::new("B"); - let option_3 = SelectOption::new("C"); + let option_1 = SelectOptionPB::new("A"); + let option_2 = SelectOptionPB::new("B"); + let option_3 = SelectOptionPB::new("C"); let filter_1 = GridSelectOptionFilter { condition: SelectOptionCondition::OptionIs, 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 c312779487..a292ffa1ff 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -188,8 +188,8 @@ impl GridRevisionEditor { pub async fn delete_field(&self, field_id: &str) -> FlowyResult<()> { let _ = self.modify(|grid_pad| Ok(grid_pad.delete_field_rev(field_id)?)).await?; - let field_order = GridField::from(field_id); - let notified_changeset = GridFieldChangeset::delete(&self.grid_id, vec![field_order]); + let field_order = GridFieldPB::from(field_id); + let notified_changeset = GridFieldChangesetPB::delete(&self.grid_id, vec![field_order]); let _ = self.notify_did_update_grid(notified_changeset).await?; Ok(()) } @@ -268,13 +268,13 @@ impl GridRevisionEditor { Ok(()) } - pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { + pub async fn create_row(&self, start_row_id: Option) -> FlowyResult { 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 = RowRevisionBuilder::new(&field_revs).build(&block_id); - let row_order = Row::from(&row_rev); + let row_order = GridRowPB::from(&row_rev); // insert the row let row_count = self.block_manager.create_row(&block_id, row_rev, start_row_id).await?; @@ -285,12 +285,12 @@ impl GridRevisionEditor { Ok(row_order) } - pub async fn insert_rows(&self, row_revs: Vec) -> FlowyResult> { + pub async fn insert_rows(&self, row_revs: Vec) -> FlowyResult> { let block_id = self.block_id().await?; let mut rows_by_block_id: HashMap> = HashMap::new(); let mut row_orders = vec![]; for row_rev in row_revs { - row_orders.push(Row::from(&row_rev)); + row_orders.push(GridRowPB::from(&row_rev)); rows_by_block_id .entry(block_id.clone()) .or_insert_with(Vec::new) @@ -307,7 +307,7 @@ impl GridRevisionEditor { self.block_manager.update_row(changeset, make_row_from_row_rev).await } - pub async fn get_rows(&self, block_id: &str) -> FlowyResult { + pub async fn get_rows(&self, block_id: &str) -> FlowyResult { let block_ids = vec![block_id.to_owned()]; let mut grid_block_snapshot = self.grid_block_snapshots(Some(block_ids)).await?; @@ -402,7 +402,7 @@ impl GridRevisionEditor { } } - pub async fn get_blocks(&self, block_ids: Option>) -> FlowyResult { + pub async fn get_blocks(&self, block_ids: Option>) -> FlowyResult { let block_snapshots = self.grid_block_snapshots(block_ids.clone()).await?; make_grid_blocks(block_ids, block_snapshots) } @@ -412,7 +412,7 @@ impl GridRevisionEditor { Ok(block_meta_revs) } - pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { + pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { let changesets = self.block_manager.delete_rows(row_orders).await?; for changeset in changesets { let _ = self.update_block(changeset).await?; @@ -420,31 +420,31 @@ impl GridRevisionEditor { Ok(()) } - pub async fn get_grid_data(&self) -> FlowyResult { + pub async fn get_grid_data(&self) -> FlowyResult { let pad_read_guard = self.grid_pad.read().await; let field_orders = pad_read_guard .get_field_revs(None)? .iter() - .map(GridField::from) + .map(GridFieldPB::from) .collect(); let mut block_orders = vec![]; for block_rev in pad_read_guard.get_block_meta_revs() { let row_orders = self.block_manager.get_row_orders(&block_rev.block_id).await?; - let block_order = GridBlock { + let block_order = GridBlockPB { id: block_rev.block_id.clone(), rows: row_orders, }; block_orders.push(block_order); } - Ok(Grid { + Ok(GridPB { id: self.grid_id.clone(), fields: field_orders, blocks: block_orders, }) } - pub async fn get_grid_setting(&self) -> FlowyResult { + pub async fn get_grid_setting(&self) -> FlowyResult { let read_guard = self.grid_pad.read().await; let grid_setting_rev = read_guard.get_grid_setting_rev(); let field_revs = read_guard.get_field_revs(None)?; @@ -495,11 +495,11 @@ impl GridRevisionEditor { pub async fn move_item(&self, params: MoveItemParams) -> FlowyResult<()> { match params.ty { - MoveItemType::MoveField => { + MoveItemTypePB::MoveField => { self.move_field(¶ms.item_id, params.from_index, params.to_index) .await } - MoveItemType::MoveRow => self.move_row(¶ms.item_id, params.from_index, params.to_index).await, + MoveItemTypePB::MoveRow => self.move_row(¶ms.item_id, params.from_index, params.to_index).await, } } @@ -508,9 +508,9 @@ impl GridRevisionEditor { .modify(|grid_pad| Ok(grid_pad.move_field(field_id, from as usize, to as usize)?)) .await?; if let Some((index, field_rev)) = self.grid_pad.read().await.get_field_rev(field_id) { - let delete_field_order = GridField::from(field_id); - let insert_field = IndexField::from_field_rev(field_rev, index); - let notified_changeset = GridFieldChangeset { + let delete_field_order = GridFieldPB::from(field_id); + let insert_field = IndexFieldPB::from_field_rev(field_rev, index); + let notified_changeset = GridFieldChangesetPB { grid_id: self.grid_id.clone(), inserted_fields: vec![insert_field], deleted_fields: vec![delete_field_order], @@ -599,8 +599,8 @@ impl GridRevisionEditor { #[tracing::instrument(level = "trace", skip_all, err)] async fn notify_did_insert_grid_field(&self, field_id: &str) -> FlowyResult<()> { if let Some((index, field_rev)) = self.grid_pad.read().await.get_field_rev(field_id) { - let index_field = IndexField::from_field_rev(field_rev, index); - let notified_changeset = GridFieldChangeset::insert(&self.grid_id, vec![index_field]); + let index_field = IndexFieldPB::from_field_rev(field_rev, index); + let notified_changeset = GridFieldChangesetPB::insert(&self.grid_id, vec![index_field]); let _ = self.notify_did_update_grid(notified_changeset).await?; } Ok(()) @@ -615,8 +615,8 @@ impl GridRevisionEditor { .get_field_rev(field_id) .map(|(index, field)| (index, field.clone())) { - let updated_field = Field::from(field_rev); - let notified_changeset = GridFieldChangeset::update(&self.grid_id, vec![updated_field.clone()]); + let updated_field = FieldPB::from(field_rev); + let notified_changeset = GridFieldChangesetPB::update(&self.grid_id, vec![updated_field.clone()]); let _ = self.notify_did_update_grid(notified_changeset).await?; send_dart_notification(field_id, GridNotification::DidUpdateField) @@ -627,7 +627,7 @@ impl GridRevisionEditor { Ok(()) } - async fn notify_did_update_grid(&self, changeset: GridFieldChangeset) -> FlowyResult<()> { + async fn notify_did_update_grid(&self, changeset: GridFieldChangesetPB) -> FlowyResult<()> { send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridField) .payload(changeset) .send(); 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 c00604a40a..3a5aa58c6d 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,4 +1,4 @@ -use crate::entities::{GridBlock, RepeatedGridBlock, Row}; +use crate::entities::{GridBlockPB, GridRowPB, RepeatedGridBlockPB}; use flowy_error::FlowyResult; use flowy_grid_data_model::revision::RowRevision; use std::collections::HashMap; @@ -9,14 +9,14 @@ pub struct GridBlockSnapshot { pub row_revs: Vec>, } -pub(crate) fn block_from_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_info| { // Memory Optimization: escape clone block_id 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(&cloned_block_id, vec![])) + .or_insert_with(|| GridBlockPB::new(&cloned_block_id, vec![])) .rows .push(row_info); }); @@ -35,16 +35,16 @@ pub(crate) fn block_from_row_orders(row_orders: Vec) -> Vec { // Some((field_id, cell)) // } -pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc]) -> Vec { - row_revs.iter().map(Row::from).collect::>() +pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc]) -> Vec { + row_revs.iter().map(GridRowPB::from).collect::>() } -pub(crate) fn make_row_from_row_rev(row_rev: Arc) -> Option { +pub(crate) fn make_row_from_row_rev(row_rev: Arc) -> Option { make_rows_from_row_revs(&[row_rev]).pop() } -pub(crate) fn make_rows_from_row_revs(row_revs: &[Arc]) -> Vec { - let make_row = |row_rev: &Arc| Row { +pub(crate) fn make_rows_from_row_revs(row_revs: &[Arc]) -> Vec { + let make_row = |row_rev: &Arc| GridRowPB { block_id: row_rev.block_id.clone(), id: row_rev.id.clone(), height: row_rev.height, @@ -56,15 +56,15 @@ pub(crate) fn make_rows_from_row_revs(row_revs: &[Arc]) -> Vec pub(crate) fn make_grid_blocks( block_ids: Option>, block_snapshots: Vec, -) -> FlowyResult { +) -> FlowyResult { match block_ids { None => Ok(block_snapshots .into_iter() .map(|snapshot| { let row_orders = make_row_orders_from_row_revs(&snapshot.row_revs); - GridBlock::new(&snapshot.block_id, row_orders) + GridBlockPB::new(&snapshot.block_id, row_orders) }) - .collect::>() + .collect::>() .into()), Some(block_ids) => { let block_meta_data_map: HashMap<&String, &Vec>> = block_snapshots @@ -78,7 +78,7 @@ pub(crate) fn make_grid_blocks( None => {} Some(row_revs) => { let row_orders = make_row_orders_from_row_revs(row_revs); - grid_blocks.push(GridBlock::new(&block_id, row_orders)); + grid_blocks.push(GridBlockPB::new(&block_id, row_orders)); } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs index 6880db5277..be283981cf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/setting/setting_builder.rs @@ -1,5 +1,5 @@ use crate::entities::{ - GridLayout, GridLayoutType, GridSetting, RepeatedGridFilter, RepeatedGridGroup, RepeatedGridSort, + GridLayoutPB, GridLayoutType, GridSettingPB, RepeatedGridFilterPB, RepeatedGridGroupPB, RepeatedGridSortPB, }; use flowy_grid_data_model::revision::{FieldRevision, GridSettingRevision}; use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; @@ -40,7 +40,7 @@ impl GridSettingChangesetBuilder { } } -pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[Arc]) -> GridSetting { +pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[Arc]) -> GridSettingPB { let current_layout_type: GridLayoutType = grid_setting_rev.layout.clone().into(); let filters_by_field_id = grid_setting_rev .get_all_filter(field_revs) @@ -48,7 +48,7 @@ pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[A filters_by_field_id .into_iter() .map(|(k, v)| (k, v.into())) - .collect::>() + .collect::>() }) .unwrap_or_default(); let groups_by_field_id = grid_setting_rev @@ -57,7 +57,7 @@ pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[A groups_by_field_id .into_iter() .map(|(k, v)| (k, v.into())) - .collect::>() + .collect::>() }) .unwrap_or_default(); let sorts_by_field_id = grid_setting_rev @@ -66,12 +66,12 @@ pub fn make_grid_setting(grid_setting_rev: &GridSettingRevision, field_revs: &[A sorts_by_field_id .into_iter() .map(|(k, v)| (k, v.into())) - .collect::>() + .collect::>() }) .unwrap_or_default(); - GridSetting { - layouts: GridLayout::all(), + GridSettingPB { + layouts: GridLayoutPB::all(), current_layout_type, filters_by_field_id, groups_by_field_id, diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 18810032f0..318910f217 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -2,7 +2,7 @@ use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow}; use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; -use flowy_grid::entities::{CellIdentifier, FieldType, Row}; +use flowy_grid::entities::{CellIdentifier, FieldType, GridRowPB}; use flowy_grid::services::field::*; use flowy_grid_data_model::revision::{ GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, @@ -97,7 +97,7 @@ impl GridRowTest { let row_orders = row_ids .into_iter() .map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone()) - .collect::>(); + .collect::>(); self.editor.delete_rows(row_orders).await.unwrap(); self.row_revs = self.get_row_revs().await; @@ -289,7 +289,7 @@ impl<'a> CreateRowScriptBuilder<'a> { pub fn insert_single_select_cell(&mut self, f: F, expected: &str) where - F: Fn(Vec) -> SelectOption, + F: Fn(Vec) -> SelectOptionPB, { let field_id = self.builder.insert_single_select_cell(f); self.output_by_field_type.insert( @@ -303,7 +303,7 @@ impl<'a> CreateRowScriptBuilder<'a> { pub fn insert_multi_select_cell(&mut self, f: F, expected: &str) where - F: Fn(Vec) -> Vec, + F: Fn(Vec) -> Vec, { let field_id = self.builder.insert_multi_select_cell(f); self.output_by_field_type.insert( diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs index 7aade54a08..216a4d4acd 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs @@ -2,7 +2,7 @@ use flowy_grid::entities::FieldType; use std::sync::Arc; use flowy_grid::services::field::{ - DateCellChangeset, MultiSelectTypeOption, SelectOption, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, + DateCellChangesetPB, MultiSelectTypeOption, SelectOptionPB, SingleSelectTypeOptionPB, SELECTION_IDS_SEPARATOR, }; use flowy_grid::services::row::RowRevisionBuilder; use flowy_grid_data_model::revision::{FieldRevision, RowRevision}; @@ -44,7 +44,7 @@ impl<'a> GridRowTestBuilder<'a> { } pub fn insert_date_cell(&mut self, data: &str) -> String { - let value = serde_json::to_string(&DateCellChangeset { + let value = serde_json::to_string(&DateCellChangesetPB { date: Some(data.to_string()), time: None, }) @@ -71,10 +71,10 @@ impl<'a> GridRowTestBuilder<'a> { pub fn insert_single_select_cell(&mut self, f: F) -> String where - F: Fn(Vec) -> SelectOption, + F: Fn(Vec) -> SelectOptionPB, { let single_select_field = self.field_rev_with_type(&FieldType::SingleSelect); - let type_option = SingleSelectTypeOption::from(&single_select_field); + let type_option = SingleSelectTypeOptionPB::from(&single_select_field); let option = f(type_option.options); self.inner_builder .insert_select_option_cell(&single_select_field.id, option.id) @@ -85,7 +85,7 @@ impl<'a> GridRowTestBuilder<'a> { pub fn insert_multi_select_cell(&mut self, f: F) -> String where - F: Fn(Vec) -> Vec, + F: Fn(Vec) -> Vec, { let multi_select_field = self.field_rev_with_type(&FieldType::MultiSelect); let type_option = MultiSelectTypeOption::from(&multi_select_field); diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs index ccdb8ea629..2334c89f9a 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs @@ -3,7 +3,7 @@ use crate::grid::cell_test::script::GridCellTest; use crate::grid::field_test::util::make_date_cell_string; use flowy_grid::entities::{CellChangeset, FieldType}; use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset; -use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOption}; +use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; #[tokio::test] async fn grid_cell_update() { @@ -24,7 +24,7 @@ async fn grid_cell_update() { FieldType::Number => "123".to_string(), FieldType::DateTime => make_date_cell_string("123"), FieldType::SingleSelect => { - let type_option = SingleSelectTypeOption::from(field_rev); + let type_option = SingleSelectTypeOptionPB::from(field_rev); SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() } FieldType::MultiSelect => { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs index c53ba2a2fc..98cb3d0324 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/test.rs @@ -1,8 +1,8 @@ use crate::grid::field_test::script::FieldScript::*; use crate::grid::field_test::script::GridFieldTest; use crate::grid::field_test::util::*; -use flowy_grid::services::field::selection_type_option::SelectOption; -use flowy_grid::services::field::SingleSelectTypeOption; +use flowy_grid::services::field::selection_type_option::SelectOptionPB; +use flowy_grid::services::field::SingleSelectTypeOptionPB; use flowy_grid_data_model::revision::TypeOptionDataEntry; use flowy_sync::entities::grid::FieldChangesetParams; @@ -71,8 +71,8 @@ async fn grid_update_field() { let mut test = GridFieldTest::new().await; let (params, single_select_field) = create_single_select_field(&test.grid_id()); - let mut single_select_type_option = SingleSelectTypeOption::from(&single_select_field); - single_select_type_option.options.push(SelectOption::new("Unknown")); + let mut single_select_type_option = SingleSelectTypeOptionPB::from(&single_select_field); + single_select_type_option.options.push(SelectOptionPB::new("Unknown")); let changeset = FieldChangesetParams { field_id: single_select_field.id.clone(), grid_id: test.grid_id(), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs index 42c04e41f9..95b6759950 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs @@ -1,5 +1,5 @@ use flowy_grid::entities::*; -use flowy_grid::services::field::selection_type_option::SelectOption; +use flowy_grid::services::field::selection_type_option::SelectOptionPB; use flowy_grid::services::field::*; use flowy_grid_data_model::revision::*; @@ -17,7 +17,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { .protobuf_bytes() .to_vec(); - let field = Field { + let field = FieldPB { id: field_rev.id, name: field_rev.name, desc: field_rev.desc, @@ -39,18 +39,18 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new("Done")) - .option(SelectOption::new("Progress")); + .option(SelectOptionPB::new("Done")) + .option(SelectOptionPB::new("Progress")); let field_rev = FieldBuilder::new(single_select).name("Name").visibility(true).build(); let cloned_field_rev = field_rev.clone(); let type_option_data = field_rev - .get_type_option_entry::(field_rev.field_type_rev) + .get_type_option_entry::(field_rev.field_type_rev) .unwrap() .protobuf_bytes() .to_vec(); - let field = Field { + let field = FieldPB { id: field_rev.id, name: field_rev.name, desc: field_rev.desc, @@ -73,7 +73,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev // The grid will contains all existing field types and there are three empty rows in this grid. pub fn make_date_cell_string(s: &str) -> String { - serde_json::to_string(&DateCellChangeset { + serde_json::to_string(&DateCellChangesetPB { date: Some(s.to_string()), time: None, }) diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs index 4a1ef3af83..267cb570eb 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs @@ -3,7 +3,7 @@ #![allow(dead_code)] #![allow(unused_imports)] -use flowy_grid::entities::{CreateGridFilterPayload, GridLayoutType, GridSetting}; +use flowy_grid::entities::{CreateGridFilterPayloadPB, GridLayoutType, GridSettingPB}; use flowy_grid::services::setting::GridSettingChangesetBuilder; use flowy_grid_data_model::revision::{FieldRevision, FieldTypeRevision}; use flowy_sync::entities::grid::{CreateGridFilterParams, DeleteFilterParams, GridSettingChangesetParams}; @@ -15,7 +15,7 @@ pub enum FilterScript { params: GridSettingChangesetParams, }, InsertGridTableFilter { - payload: CreateGridFilterPayload, + payload: CreateGridFilterPayloadPB, }, AssertTableFilterCount { count: i32, @@ -26,7 +26,7 @@ pub enum FilterScript { }, #[allow(dead_code)] AssertGridSetting { - expected_setting: GridSetting, + expected_setting: GridSettingPB, }, } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs index e954ebe512..3e45a4053d 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/filter_test/text_filter_test.rs @@ -1,13 +1,13 @@ use crate::grid::filter_test::script::FilterScript::*; use crate::grid::filter_test::script::*; -use flowy_grid::entities::{CreateGridFilterPayload, FieldType, TextFilterCondition}; +use flowy_grid::entities::{CreateGridFilterPayloadPB, FieldType, TextFilterCondition}; use flowy_grid_data_model::revision::FieldRevision; #[tokio::test] async fn grid_filter_create_test() { let mut test = GridFilterTest::new().await; let field_rev = test.get_field_rev(FieldType::RichText); - let payload = CreateGridFilterPayload::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned())); + let payload = CreateGridFilterPayloadPB::new(field_rev, TextFilterCondition::TextIsEmpty, Some("abc".to_owned())); let scripts = vec![InsertGridTableFilter { payload }, AssertTableFilterCount { count: 1 }]; test.run_scripts(scripts).await; } @@ -19,7 +19,7 @@ async fn grid_filter_invalid_condition_panic_test() { let field_rev = test.get_field_rev(FieldType::RichText).clone(); // 100 is not a valid condition, so this test should be panic. - let payload = CreateGridFilterPayload::new(&field_rev, 100, Some("".to_owned())); + let payload = CreateGridFilterPayloadPB::new(&field_rev, 100, Some("".to_owned())); let scripts = vec![InsertGridTableFilter { payload }]; test.run_scripts(scripts).await; } @@ -46,6 +46,6 @@ async fn grid_filter_delete_test() { #[tokio::test] async fn grid_filter_get_rows_test() {} -fn create_filter(field_rev: &FieldRevision, condition: TextFilterCondition, s: &str) -> CreateGridFilterPayload { - CreateGridFilterPayload::new(field_rev, condition, Some(s.to_owned())) +fn create_filter(field_rev: &FieldRevision, condition: TextFilterCondition, s: &str) -> CreateGridFilterPayloadPB { + CreateGridFilterPayloadPB::new(field_rev, condition, Some(s.to_owned())) } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs index d558390e25..f924b3e803 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs @@ -4,7 +4,7 @@ use crate::grid::block_test::util::GridRowTestBuilder; use bytes::Bytes; use flowy_grid::entities::*; -use flowy_grid::services::field::SelectOption; +use flowy_grid::services::field::SelectOptionPB; use flowy_grid::services::field::*; use flowy_grid::services::grid_editor::{GridPadBuilder, GridRevisionEditor}; use flowy_grid::services::row::{CreateRowRevisionPayload, RowRevisionBuilder}; @@ -32,7 +32,7 @@ pub struct GridEditorTest { pub block_meta_revs: Vec>, pub row_revs: Vec>, pub field_count: usize, - pub row_order_by_row_id: HashMap, + pub row_order_by_row_id: HashMap, } impl GridEditorTest { @@ -138,18 +138,18 @@ fn make_test_grid() -> BuildGridContext { FieldType::SingleSelect => { // Single Select let single_select = SingleSelectTypeOptionBuilder::default() - .option(SelectOption::new(COMPLETED)) - .option(SelectOption::new(PLANNED)) - .option(SelectOption::new(PAUSED)); + .option(SelectOptionPB::new(COMPLETED)) + .option(SelectOptionPB::new(PLANNED)) + .option(SelectOptionPB::new(PAUSED)); let single_select_field = FieldBuilder::new(single_select).name("Status").visibility(true).build(); grid_builder.add_field(single_select_field); } FieldType::MultiSelect => { // MultiSelect let multi_select = MultiSelectTypeOptionBuilder::default() - .option(SelectOption::new(GOOGLE)) - .option(SelectOption::new(FACEBOOK)) - .option(SelectOption::new(TWITTER)); + .option(SelectOptionPB::new(GOOGLE)) + .option(SelectOptionPB::new(FACEBOOK)) + .option(SelectOptionPB::new(TWITTER)); let multi_select_field = FieldBuilder::new(multi_select) .name("Platform") .visibility(true) From e45b14910b0be9042c83d3f891b4cc0451d85599 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Jul 2022 14:13:12 +0800 Subject: [PATCH 028/112] chore: add suffix PB to dart class --- .../app_flowy/lib/core/grid_notification.dart | 2 +- .../app_flowy/lib/startup/deps_resolver.dart | 2 +- .../grid/block/block_listener.dart | 4 +- .../cell/cell_service/cell_data_loader.dart | 20 +-- .../cell_service/cell_data_persistence.dart | 6 +- .../cell_service/cell_field_notifier.dart | 4 +- .../grid/cell/cell_service/cell_service.dart | 8 +- .../cell/cell_service/context_builder.dart | 14 +-- .../application/grid/cell/date_cal_bloc.dart | 12 +- .../application/grid/cell/date_cell_bloc.dart | 14 +-- .../grid/cell/select_option_cell_bloc.dart | 4 +- .../grid/cell/select_option_editor_bloc.dart | 22 ++-- .../grid/cell/select_option_service.dart | 24 ++-- .../application/grid/cell/url_cell_bloc.dart | 2 +- .../grid/cell/url_cell_editor_bloc.dart | 2 +- .../grid/field/field_action_sheet_bloc.dart | 8 +- .../grid/field/field_cell_bloc.dart | 4 +- .../grid/field/field_editor_bloc.dart | 6 +- .../grid/field/field_listener.dart | 4 +- .../application/grid/field/field_service.dart | 46 +++---- .../field/field_type_option_edit_bloc.dart | 4 +- .../application/grid/field/grid_listenr.dart | 4 +- .../type_option/edit_select_option_bloc.dart | 12 +- .../type_option/multi_select_type_option.dart | 10 +- .../select_option_type_option_bloc.dart | 22 ++-- .../single_select_type_option.dart | 18 +-- .../type_option/type_option_service.dart | 10 +- .../workspace/application/grid/grid_bloc.dart | 16 +-- .../application/grid/grid_header_bloc.dart | 12 +- .../application/grid/grid_service.dart | 46 +++---- .../workspace/application/grid/prelude.dart | 6 +- .../application/grid/row/row_bloc.dart | 4 +- .../application/grid/row/row_listener.dart | 6 +- .../application/grid/row/row_service.dart | 42 +++---- .../grid/setting/property_bloc.dart | 8 +- .../plugins/grid/src/layout/layout.dart | 2 +- .../cell/select_option_cell/extension.dart | 44 +++---- .../select_option_cell.dart | 2 +- .../select_option_editor.dart | 4 +- .../cell/select_option_cell/text_field.dart | 4 +- .../grid/src/widgets/header/field_cell.dart | 2 +- .../header/field_type_option_editor.dart | 6 +- .../grid/src/widgets/header/grid_header.dart | 2 +- .../header/type_option/select_option.dart | 8 +- .../type_option/select_option_editor.dart | 10 +- .../src/widgets/toolbar/grid_property.dart | 2 +- .../widgets/emoji_picker/src/emoji_lists.dart | 2 +- .../flowy-grid/src/entities/cell_entities.rs | 46 +++---- .../flowy-grid/src/entities/field_entities.rs | 116 +++++++++--------- .../flowy-grid/src/entities/grid_entities.rs | 4 +- .../rust-lib/flowy-grid/src/event_handler.rs | 40 +++--- frontend/rust-lib/flowy-grid/src/event_map.rs | 50 ++++---- .../flowy-grid/src/services/block_manager.rs | 6 +- .../src/services/field/field_builder.rs | 4 +- .../date_type_option_entities.rs | 14 +-- .../selection_type_option/select_option.rs | 16 +-- .../flowy-grid/src/services/grid_editor.rs | 22 ++-- .../tests/grid/block_test/script.rs | 6 +- .../flowy-grid/tests/grid/cell_test/script.rs | 4 +- .../flowy-grid/tests/grid/cell_test/test.rs | 4 +- .../flowy-grid/tests/grid/field_test/util.rs | 4 +- 61 files changed, 426 insertions(+), 426 deletions(-) diff --git a/frontend/app_flowy/lib/core/grid_notification.dart b/frontend/app_flowy/lib/core/grid_notification.dart index e45bf5efe2..9a2429a417 100644 --- a/frontend/app_flowy/lib/core/grid_notification.dart +++ b/frontend/app_flowy/lib/core/grid_notification.dart @@ -8,7 +8,7 @@ import 'package:flowy_sdk/rust_stream.dart'; import 'notification_helper.dart'; -// Grid +// GridPB typedef GridNotificationCallback = void Function(GridNotification, Either); class GridNotificationParser extends NotificationParser { diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index bd9c259575..bdb76996e9 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -134,7 +134,7 @@ void _resolveDocDeps(GetIt getIt) { } void _resolveGridDeps(GetIt getIt) { - // Grid + // GridPB getIt.registerFactoryParam( (view, _) => GridBloc(view: view), ); 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 index 7a2bbe0cb3..91f93c61fe 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/block/block_listener.dart @@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; -typedef GridBlockUpdateNotifierValue = Either, FlowyError>; +typedef GridBlockUpdateNotifierValue = Either, FlowyError>; class GridBlockListener { final String blockId; @@ -33,7 +33,7 @@ class GridBlockListener { switch (ty) { case GridNotification.DidUpdateGridBlock: result.fold( - (payload) => _rowsUpdateNotifier?.value = left([GridBlockChangeset.fromBuffer(payload)]), + (payload) => _rowsUpdateNotifier?.value = left([GridBlockChangesetPB.fromBuffer(payload)]), (error) => _rowsUpdateNotifier?.value = right(error), ); break; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart index 324c65c5f5..b779d227b1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart @@ -24,7 +24,7 @@ class GridCellDataLoader { Future loadData() { final fut = service.getCell(cellId: cellId); return fut.then( - (result) => result.fold((Cell cell) { + (result) => result.fold((GridCellPB cell) { try { return parser.parserData(cell.data); } catch (e, s) { @@ -48,32 +48,32 @@ class StringCellDataParser implements ICellDataParser { } } -class DateCellDataParser implements ICellDataParser { +class DateCellDataParser implements ICellDataParser { @override - DateCellData? parserData(List data) { + DateCellDataPB? parserData(List data) { if (data.isEmpty) { return null; } - return DateCellData.fromBuffer(data); + return DateCellDataPB.fromBuffer(data); } } -class SelectOptionCellDataParser implements ICellDataParser { +class SelectOptionCellDataParser implements ICellDataParser { @override - SelectOptionCellData? parserData(List data) { + SelectOptionCellDataPB? parserData(List data) { if (data.isEmpty) { return null; } - return SelectOptionCellData.fromBuffer(data); + return SelectOptionCellDataPB.fromBuffer(data); } } -class URLCellDataParser implements ICellDataParser { +class URLCellDataParser implements ICellDataParser { @override - URLCellData? parserData(List data) { + URLCellDataPB? parserData(List data) { if (data.isEmpty) { return null; } - return URLCellData.fromBuffer(data); + return URLCellDataPB.fromBuffer(data); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart index 4959adf3ed..a38a771158 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart @@ -40,7 +40,7 @@ class DateCellDataPersistence implements IGridCellDataPersistence @override Future> save(CalendarData data) { - var payload = DateChangesetPayload.create()..cellIdentifier = _makeCellIdPayload(cellId); + var payload = DateChangesetPayloadPB.create()..cellIdentifier = _makeCellIdPayload(cellId); final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString(); payload.date = date; @@ -58,8 +58,8 @@ class DateCellDataPersistence implements IGridCellDataPersistence } } -CellIdentifierPayload _makeCellIdPayload(GridCellIdentifier cellId) { - return CellIdentifierPayload.create() +GridCellIdentifierPayloadPB _makeCellIdPayload(GridCellIdentifier cellId) { + return GridCellIdentifierPayloadPB.create() ..gridId = cellId.gridId ..fieldId = cellId.fieldId ..rowId = cellId.rowId; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart index e4c909d501..72f1bc787d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_field_notifier.dart @@ -4,11 +4,11 @@ import 'package:flutter/foundation.dart'; import 'cell_service.dart'; abstract class GridFieldChangedNotifier { - void onFieldChanged(void Function(Field) callback); + void onFieldChanged(void Function(GridFieldPB) callback); void dispose(); } -/// Grid's cell helper wrapper that enables each cell will get notified when the corresponding field was changed. +/// GridPB's cell helper wrapper that enables each cell will get notified when the corresponding field was changed. /// You Register an onFieldChanged callback to listen to the cell changes, and unregister if you don't want to listen. class GridCellFieldNotifier { /// fieldId: {objectId: callback} 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 fab9c1a724..3e8746c20a 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 @@ -35,7 +35,7 @@ class CellService { required GridCellIdentifier cellId, required String data, }) { - final payload = CellChangeset.create() + final payload = CellChangesetPB.create() ..gridId = cellId.gridId ..fieldId = cellId.fieldId ..rowId = cellId.rowId @@ -43,10 +43,10 @@ class CellService { return GridEventUpdateCell(payload).send(); } - Future> getCell({ + Future> getCell({ required GridCellIdentifier cellId, }) { - final payload = CellIdentifierPayload.create() + final payload = GridCellIdentifierPayloadPB.create() ..gridId = cellId.gridId ..fieldId = cellId.fieldId ..rowId = cellId.rowId; @@ -61,7 +61,7 @@ class GridCellIdentifier with _$GridCellIdentifier { const factory GridCellIdentifier({ required String gridId, required String rowId, - required Field field, + required GridFieldPB field, }) = _GridCellIdentifier; // ignore: unused_element 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 124835cf94..8e51e33f29 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 @@ -1,9 +1,9 @@ part of 'cell_service.dart'; typedef GridCellController = IGridCellController; -typedef GridSelectOptionCellController = IGridCellController; -typedef GridDateCellController = IGridCellController; -typedef GridURLCellController = IGridCellController; +typedef GridSelectOptionCellController = IGridCellController; +typedef GridDateCellController = IGridCellController; +typedef GridURLCellController = IGridCellController; class GridCellControllerBuilder { final GridCellIdentifier _cellId; @@ -159,7 +159,7 @@ class IGridCellController extends Equatable { String get fieldId => cellId.field.id; - Field get field => cellId.field; + GridFieldPB get field => cellId.field; FieldType get fieldType => cellId.field.fieldType; @@ -223,7 +223,7 @@ class IGridCellController extends Equatable { return data; } - /// Return the FieldTypeOptionData that can be parsed into corresponding class using the [parser]. + /// Return the FieldTypeOptionDataPB that can be parsed into corresponding class using the [parser]. /// [PD] is the type that the parser return. Future> getFieldTypeOption(P parser) { return _fieldService.getFieldTypeOptionData(fieldType: fieldType).then((result) { @@ -305,8 +305,8 @@ class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier { } @override - void onFieldChanged(void Function(Field p1) callback) { - _onChangesetFn = (GridFieldChangeset changeset) { + void onFieldChanged(void Function(GridFieldPB p1) callback) { + _onChangesetFn = (GridFieldChangesetPB changeset) { for (final updatedField in changeset.updatedFields) { callback(updatedField); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 77a7c7f066..d99bdbf817 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -22,7 +22,7 @@ class DateCalBloc extends Bloc { DateCalBloc({ required DateTypeOption dateTypeOption, - required DateCellData? cellData, + required DateCellDataPB? cellData, required this.cellContext, }) : super(DateCalState.initial(dateTypeOption, cellData)) { on( @@ -38,7 +38,7 @@ class DateCalBloc extends Bloc { setFocusedDay: (focusedDay) { emit(state.copyWith(focusedDay: focusedDay)); }, - didReceiveCellUpdate: (DateCellData? cellData) { + didReceiveCellUpdate: (DateCellDataPB? cellData) { final calData = calDataFromCellData(cellData); final time = calData.foldRight("", (dateData, previous) => dateData.time); emit(state.copyWith(calData: calData, time: time)); @@ -188,7 +188,7 @@ class DateCalEvent with _$DateCalEvent { const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat; const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime; const factory DateCalEvent.setTime(String time) = _Time; - const factory DateCalEvent.didReceiveCellUpdate(DateCellData? data) = _DidReceiveCellUpdate; + const factory DateCalEvent.didReceiveCellUpdate(DateCellDataPB? data) = _DidReceiveCellUpdate; const factory DateCalEvent.didUpdateCalData(Option data, Option timeFormatError) = _DidUpdateCalData; } @@ -207,7 +207,7 @@ class DateCalState with _$DateCalState { factory DateCalState.initial( DateTypeOption dateTypeOption, - DateCellData? cellData, + DateCellDataPB? cellData, ) { Option calData = calDataFromCellData(cellData); final time = calData.foldRight("", (dateData, previous) => dateData.time); @@ -233,7 +233,7 @@ String _timeHintText(DateTypeOption typeOption) { return ""; } -Option calDataFromCellData(DateCellData? cellData) { +Option calDataFromCellData(DateCellDataPB? cellData) { String? time = timeFromCellData(cellData); Option calData = none(); if (cellData != null) { @@ -249,7 +249,7 @@ $fixnum.Int64 timestampFromDateTime(DateTime dateTime) { return $fixnum.Int64(timestamp); } -String? timeFromCellData(DateCellData? cellData) { +String? timeFromCellData(DateCellDataPB? cellData) { String? time; if (cellData?.hasTime() ?? false) { time = cellData?.time; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index d42769549a..c4f79f1f90 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -15,10 +15,10 @@ class DateCellBloc extends Bloc { (event, emit) async { event.when( initial: () => _startListening(), - didReceiveCellUpdate: (DateCellData? cellData) { + didReceiveCellUpdate: (DateCellDataPB? cellData) { emit(state.copyWith(data: cellData, dateStr: _dateStrFromCellData(cellData))); }, - didReceiveFieldUpdate: (Field value) => emit(state.copyWith(field: value)), + didReceiveFieldUpdate: (GridFieldPB value) => emit(state.copyWith(field: value)), ); }, ); @@ -48,16 +48,16 @@ class DateCellBloc extends Bloc { @freezed class DateCellEvent with _$DateCellEvent { const factory DateCellEvent.initial() = _InitialCell; - const factory DateCellEvent.didReceiveCellUpdate(DateCellData? data) = _DidReceiveCellUpdate; - const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; + const factory DateCellEvent.didReceiveCellUpdate(DateCellDataPB? data) = _DidReceiveCellUpdate; + const factory DateCellEvent.didReceiveFieldUpdate(GridFieldPB field) = _DidReceiveFieldUpdate; } @freezed class DateCellState with _$DateCellState { const factory DateCellState({ - required DateCellData? data, + required DateCellDataPB? data, required String dateStr, - required Field field, + required GridFieldPB field, }) = _DateCellState; factory DateCellState.initial(GridDateCellController context) { @@ -71,7 +71,7 @@ class DateCellState with _$DateCellState { } } -String _dateStrFromCellData(DateCellData? cellData) { +String _dateStrFromCellData(DateCellDataPB? cellData) { String dateStr = ""; if (cellData != null) { dateStr = cellData.date + " " + cellData.time; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart index a8a9a435e8..d0db8669fa 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_cell_bloc.dart @@ -56,14 +56,14 @@ class SelectOptionCellBloc extends Bloc selectedOptions, + List selectedOptions, ) = _DidReceiveOptions; } @freezed class SelectOptionCellState with _$SelectOptionCellState { const factory SelectOptionCellState({ - required List selectedOptions, + required List selectedOptions, }) = _SelectOptionCellState; factory SelectOptionCellState.initial(GridSelectOptionCellController context) { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart index 2daabe1a98..0990dca28a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_editor_bloc.dart @@ -70,7 +70,7 @@ class SelectOptionCellEditorBloc extends Bloc {}, (err) => Log.error(err)); } - void _deleteOption(SelectOption option) async { + void _deleteOption(SelectOptionPB option) async { final result = await _selectOptionService.delete( option: option, ); @@ -78,7 +78,7 @@ class SelectOptionCellEditorBloc extends Bloc null, (err) => Log.error(err)); } - void _updateOption(SelectOption option) async { + void _updateOption(SelectOptionPB option) async { final result = await _selectOptionService.update( option: option, ); @@ -122,8 +122,8 @@ class SelectOptionCellEditorBloc extends Bloc filter, List allOptions) { - final List options = List.from(allOptions); + _MakeOptionResult _makeOptions(Option filter, List allOptions) { + final List options = List.from(allOptions); Option createOption = filter; filter.foldRight(null, (filter, previous) { @@ -165,20 +165,20 @@ class SelectOptionCellEditorBloc extends Bloc options, List selectedOptions) = _DidReceiveOptions; + List options, List selectedOptions) = _DidReceiveOptions; const factory SelectOptionEditorEvent.newOption(String optionName) = _NewOption; const factory SelectOptionEditorEvent.selectOption(String optionId) = _SelectOption; - const factory SelectOptionEditorEvent.updateOption(SelectOption option) = _UpdateOption; - const factory SelectOptionEditorEvent.deleteOption(SelectOption option) = _DeleteOption; + const factory SelectOptionEditorEvent.updateOption(SelectOptionPB option) = _UpdateOption; + const factory SelectOptionEditorEvent.deleteOption(SelectOptionPB option) = _DeleteOption; const factory SelectOptionEditorEvent.filterOption(String optionName) = _SelectOptionFilter; } @freezed class SelectOptionEditorState with _$SelectOptionEditorState { const factory SelectOptionEditorState({ - required List options, - required List allOptions, - required List selectedOptions, + required List options, + required List allOptions, + required List selectedOptions, required Option createOption, required Option filter, }) = _SelectOptionEditorState; @@ -196,7 +196,7 @@ class SelectOptionEditorState with _$SelectOptionEditorState { } class _MakeOptionResult { - List options; + List options; Option createOption; _MakeOptionResult({ diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart index 7b6fffa310..54ac384267 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -19,11 +19,11 @@ class SelectOptionService { (result) { return result.fold( (option) { - final cellIdentifier = CellIdentifierPayload.create() + final cellIdentifier = GridCellIdentifierPayloadPB.create() ..gridId = gridId ..fieldId = fieldId ..rowId = rowId; - final payload = SelectOptionChangesetPayload.create() + final payload = SelectOptionChangesetPayloadPB.create() ..insertOption = option ..cellIdentifier = cellIdentifier; return GridEventUpdateSelectOption(payload).send(); @@ -35,26 +35,26 @@ class SelectOptionService { } Future> update({ - required SelectOption option, + required SelectOptionPB option, }) { - final payload = SelectOptionChangesetPayload.create() + final payload = SelectOptionChangesetPayloadPB.create() ..updateOption = option ..cellIdentifier = _cellIdentifier(); return GridEventUpdateSelectOption(payload).send(); } Future> delete({ - required SelectOption option, + required SelectOptionPB option, }) { - final payload = SelectOptionChangesetPayload.create() + final payload = SelectOptionChangesetPayloadPB.create() ..deleteOption = option ..cellIdentifier = _cellIdentifier(); return GridEventUpdateSelectOption(payload).send(); } - Future> getOpitonContext() { - final payload = CellIdentifierPayload.create() + Future> getOpitonContext() { + final payload = GridCellIdentifierPayloadPB.create() ..gridId = gridId ..fieldId = fieldId ..rowId = rowId; @@ -63,21 +63,21 @@ class SelectOptionService { } Future> select({required String optionId}) { - final payload = SelectOptionCellChangesetPayload.create() + final payload = SelectOptionCellChangesetPayloadPB.create() ..cellIdentifier = _cellIdentifier() ..insertOptionId = optionId; return GridEventUpdateSelectOptionCell(payload).send(); } Future> unSelect({required String optionId}) { - final payload = SelectOptionCellChangesetPayload.create() + final payload = SelectOptionCellChangesetPayloadPB.create() ..cellIdentifier = _cellIdentifier() ..deleteOptionId = optionId; return GridEventUpdateSelectOptionCell(payload).send(); } - CellIdentifierPayload _cellIdentifier() { - return CellIdentifierPayload.create() + GridCellIdentifierPayloadPB _cellIdentifier() { + return GridCellIdentifierPayloadPB.create() ..gridId = gridId ..fieldId = fieldId ..rowId = rowId; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart index ed81f697f8..e43f561542 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_bloc.dart @@ -57,7 +57,7 @@ class URLCellBloc extends Bloc { class URLCellEvent with _$URLCellEvent { const factory URLCellEvent.initial() = _InitialCell; const factory URLCellEvent.updateURL(String url) = _UpdateURL; - const factory URLCellEvent.didReceiveCellUpdate(URLCellData? cell) = _DidReceiveCellUpdate; + const factory URLCellEvent.didReceiveCellUpdate(URLCellDataPB? cell) = _DidReceiveCellUpdate; } @freezed diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart index e69a150a38..067be84b7b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/url_cell_editor_bloc.dart @@ -54,7 +54,7 @@ class URLCellEditorBloc extends Bloc { @freezed class URLCellEditorEvent with _$URLCellEditorEvent { const factory URLCellEditorEvent.initial() = _InitialCell; - const factory URLCellEditorEvent.didReceiveCellUpdate(URLCellData? cell) = _DidReceiveCellUpdate; + const factory URLCellEditorEvent.didReceiveCellUpdate(URLCellDataPB? cell) = _DidReceiveCellUpdate; const factory URLCellEditorEvent.updateText(String text) = _UpdateText; } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart index 801678d929..3caef12f73 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart @@ -10,8 +10,8 @@ part 'field_action_sheet_bloc.freezed.dart'; class FieldActionSheetBloc extends Bloc { final FieldService fieldService; - FieldActionSheetBloc({required Field field, required this.fieldService}) - : super(FieldActionSheetState.initial(FieldTypeOptionData.create()..field_2 = field)) { + FieldActionSheetBloc({required GridFieldPB field, required this.fieldService}) + : super(FieldActionSheetState.initial(FieldTypeOptionDataPB.create()..field_2 = field)) { on( (event, emit) async { await event.map( @@ -67,12 +67,12 @@ class FieldActionSheetEvent with _$FieldActionSheetEvent { @freezed class FieldActionSheetState with _$FieldActionSheetState { const factory FieldActionSheetState({ - required FieldTypeOptionData fieldTypeOptionData, + required FieldTypeOptionDataPB fieldTypeOptionData, required String errorText, required String fieldName, }) = _FieldActionSheetState; - factory FieldActionSheetState.initial(FieldTypeOptionData data) => FieldActionSheetState( + factory FieldActionSheetState.initial(FieldTypeOptionDataPB data) => FieldActionSheetState( fieldTypeOptionData: data, errorText: '', fieldName: data.field_2.name, diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart index 774a7fb82b..8a2a0e2d06 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart @@ -62,7 +62,7 @@ class FieldCellBloc extends Bloc { @freezed class FieldCellEvent with _$FieldCellEvent { const factory FieldCellEvent.initial() = _InitialCell; - const factory FieldCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; + const factory FieldCellEvent.didReceiveFieldUpdate(GridFieldPB field) = _DidReceiveFieldUpdate; const factory FieldCellEvent.startUpdateWidth(double offset) = _StartUpdateWidth; const factory FieldCellEvent.endUpdateWidth() = _EndUpdateWidth; } @@ -71,7 +71,7 @@ class FieldCellEvent with _$FieldCellEvent { class FieldCellState with _$FieldCellState { const factory FieldCellState({ required String gridId, - required Field field, + required GridFieldPB field, required double width, }) = _FieldCellState; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart index 19da67e557..8d44edf1ff 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart @@ -30,7 +30,7 @@ class FieldEditorBloc extends Bloc { dataController.fieldName = name; emit(state.copyWith(name: name)); }, - didReceiveFieldChanged: (Field field) { + didReceiveFieldChanged: (GridFieldPB field) { emit(state.copyWith(field: Some(field))); }, ); @@ -48,7 +48,7 @@ class FieldEditorBloc extends Bloc { class FieldEditorEvent with _$FieldEditorEvent { const factory FieldEditorEvent.initial() = _InitialField; const factory FieldEditorEvent.updateName(String name) = _UpdateName; - const factory FieldEditorEvent.didReceiveFieldChanged(Field field) = _DidReceiveFieldChanged; + const factory FieldEditorEvent.didReceiveFieldChanged(GridFieldPB field) = _DidReceiveFieldChanged; } @freezed @@ -57,7 +57,7 @@ class FieldEditorState with _$FieldEditorState { required String gridId, required String errorText, required String name, - required Option field, + required Option field, }) = _FieldEditorState; factory FieldEditorState.initial( diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart index 21bd5befeb..d3b35e2bfc 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_listener.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; -typedef UpdateFieldNotifiedValue = Either; +typedef UpdateFieldNotifiedValue = Either; class SingleFieldListener { final String fieldId; @@ -31,7 +31,7 @@ class SingleFieldListener { switch (ty) { case GridNotification.DidUpdateField: result.fold( - (payload) => _updateFieldNotifier?.value = left(Field.fromBuffer(payload)), + (payload) => _updateFieldNotifier?.value = left(GridFieldPB.fromBuffer(payload)), (error) => _updateFieldNotifier?.value = right(error), ); break; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index 828ea4cc74..a0c6fc7d21 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -39,7 +39,7 @@ class FieldService { double? width, List? typeOptionData, }) { - var payload = FieldChangesetPayload.create() + var payload = FieldChangesetPayloadPB.create() ..gridId = gridId ..fieldId = fieldId; @@ -73,11 +73,11 @@ class FieldService { // Create the field if it does not exist. Otherwise, update the field. static Future> insertField({ required String gridId, - required Field field, + required GridFieldPB field, List? typeOptionData, String? startFieldId, }) { - var payload = InsertFieldPayload.create() + var payload = InsertFieldPayloadPB.create() ..gridId = gridId ..field_2 = field ..typeOptionData = typeOptionData ?? []; @@ -94,7 +94,7 @@ class FieldService { required String fieldId, required List typeOptionData, }) { - var payload = UpdateFieldTypeOptionPayload.create() + var payload = UpdateFieldTypeOptionPayloadPB.create() ..gridId = gridId ..fieldId = fieldId ..typeOptionData = typeOptionData; @@ -103,7 +103,7 @@ class FieldService { } Future> deleteField() { - final payload = FieldIdentifierPayload.create() + final payload = GridFieldIdentifierPayloadPB.create() ..gridId = gridId ..fieldId = fieldId; @@ -111,17 +111,17 @@ class FieldService { } Future> duplicateField() { - final payload = FieldIdentifierPayload.create() + final payload = GridFieldIdentifierPayloadPB.create() ..gridId = gridId ..fieldId = fieldId; return GridEventDuplicateField(payload).send(); } - Future> getFieldTypeOptionData({ + Future> getFieldTypeOptionData({ required FieldType fieldType, }) { - final payload = EditFieldPayload.create() + final payload = EditFieldPayloadPB.create() ..gridId = gridId ..fieldId = fieldId ..fieldType = fieldType; @@ -138,16 +138,16 @@ class FieldService { class GridFieldCellContext with _$GridFieldCellContext { const factory GridFieldCellContext({ required String gridId, - required Field field, + required GridFieldPB field, }) = _GridFieldCellContext; } abstract class IFieldTypeOptionLoader { String get gridId; - Future> load(); + Future> load(); - Future> switchToField(String fieldId, FieldType fieldType) { - final payload = EditFieldPayload.create() + Future> switchToField(String fieldId, FieldType fieldType) { + final payload = EditFieldPayloadPB.create() ..gridId = gridId ..fieldId = fieldId ..fieldType = fieldType; @@ -164,8 +164,8 @@ class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader { }); @override - Future> load() { - final payload = EditFieldPayload.create() + Future> load() { + final payload = EditFieldPayloadPB.create() ..gridId = gridId ..fieldType = FieldType.RichText; @@ -176,7 +176,7 @@ class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader { class FieldTypeOptionLoader extends IFieldTypeOptionLoader { @override final String gridId; - final Field field; + final GridFieldPB field; FieldTypeOptionLoader({ required this.gridId, @@ -184,8 +184,8 @@ class FieldTypeOptionLoader extends IFieldTypeOptionLoader { }); @override - Future> load() { - final payload = EditFieldPayload.create() + Future> load() { + final payload = EditFieldPayloadPB.create() ..gridId = gridId ..fieldId = field.id ..fieldType = field.fieldType; @@ -198,8 +198,8 @@ class TypeOptionDataController { final String gridId; final IFieldTypeOptionLoader _loader; - late FieldTypeOptionData _data; - final PublishNotifier _fieldNotifier = PublishNotifier(); + late FieldTypeOptionDataPB _data; + final PublishNotifier _fieldNotifier = PublishNotifier(); TypeOptionDataController({ required this.gridId, @@ -222,9 +222,9 @@ class TypeOptionDataController { ); } - Field get field => _data.field_2; + GridFieldPB get field => _data.field_2; - set field(Field field) { + set field(GridFieldPB field) { _updateData(newField: field); } @@ -238,7 +238,7 @@ class TypeOptionDataController { _updateData(newTypeOptionData: typeOptionData); } - void _updateData({String? newName, Field? newField, List? newTypeOptionData}) { + void _updateData({String? newName, GridFieldPB? newField, List? newTypeOptionData}) { _data = _data.rebuild((rebuildData) { if (newName != null) { rebuildData.field_2 = rebuildData.field_2.rebuild((rebuildField) { @@ -280,7 +280,7 @@ class TypeOptionDataController { }); } - void Function() addFieldListener(void Function(Field) callback) { + void Function() addFieldListener(void Function(GridFieldPB) callback) { listener() { callback(field); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart index b9407ac2ad..e098f87d86 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_type_option_edit_bloc.dart @@ -42,13 +42,13 @@ class FieldTypeOptionEditBloc extends Bloc FieldTypeOptionEditState( diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart b/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart index 00e94bb3e1..67bec17be7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; -typedef UpdateFieldNotifiedValue = Either; +typedef UpdateFieldNotifiedValue = Either; class GridFieldsListener { final String gridId; @@ -27,7 +27,7 @@ class GridFieldsListener { switch (ty) { case GridNotification.DidUpdateGridField: result.fold( - (payload) => updateFieldsNotifier?.value = left(GridFieldChangeset.fromBuffer(payload)), + (payload) => updateFieldsNotifier?.value = left(GridFieldChangesetPB.fromBuffer(payload)), (error) => updateFieldsNotifier?.value = right(error), ); break; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/edit_select_option_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/edit_select_option_bloc.dart index f0969e2793..9f1dd4dd1d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/edit_select_option_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/edit_select_option_bloc.dart @@ -7,7 +7,7 @@ import 'package:dartz/dartz.dart'; part 'edit_select_option_bloc.freezed.dart'; class EditSelectOptionBloc extends Bloc { - EditSelectOptionBloc({required SelectOption option}) : super(EditSelectOptionState.initial(option)) { + EditSelectOptionBloc({required SelectOptionPB option}) : super(EditSelectOptionState.initial(option)) { on( (event, emit) async { event.map( @@ -30,14 +30,14 @@ class EditSelectOptionBloc extends Bloc deleted, }) = _EditSelectOptionState; - factory EditSelectOptionState.initial(SelectOption option) => EditSelectOptionState( + factory EditSelectOptionState.initial(SelectOptionPB option) => EditSelectOptionState( option: option, deleted: none(), ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart index 0d9d75d4c7..e0e242305b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart @@ -21,8 +21,8 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext Function(SelectOption) get deleteOption { - return (SelectOption option) { + List Function(SelectOptionPB) get deleteOption { + return (SelectOptionPB option) { typeOption.freeze(); typeOption = typeOption.rebuild((typeOption) { final index = typeOption.options.indexWhere((element) => element.id == option.id); @@ -35,7 +35,7 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext> Function(String) get insertOption { + Future> Function(String) get insertOption { return (String optionName) { return service.newOption(name: optionName).then((result) { return result.fold( @@ -57,8 +57,8 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext Function(SelectOption) get udpateOption { - return (SelectOption option) { + List Function(SelectOptionPB) get udpateOption { + return (SelectOptionPB option) { typeOption.freeze(); typeOption = typeOption.rebuild((typeOption) { final index = typeOption.options.indexWhere((element) => element.id == option.id); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/select_option_type_option_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/select_option_type_option_bloc.dart index ff8244546b..b77b9b86cd 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/select_option_type_option_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/select_option_type_option_bloc.dart @@ -6,25 +6,25 @@ import 'package:dartz/dartz.dart'; part 'select_option_type_option_bloc.freezed.dart'; abstract class SelectOptionTypeOptionAction { - Future> Function(String) get insertOption; + Future> Function(String) get insertOption; - List Function(SelectOption) get deleteOption; + List Function(SelectOptionPB) get deleteOption; - List Function(SelectOption) get udpateOption; + List Function(SelectOptionPB) get udpateOption; } class SelectOptionTypeOptionBloc extends Bloc { final SelectOptionTypeOptionAction typeOptionAction; SelectOptionTypeOptionBloc({ - required List options, + required List options, required this.typeOptionAction, }) : super(SelectOptionTypeOptionState.initial(options)) { on( (event, emit) async { await event.when( createOption: (optionName) async { - final List options = await typeOptionAction.insertOption(optionName); + final List options = await typeOptionAction.insertOption(optionName); emit(state.copyWith(options: options)); }, addingOption: () { @@ -34,11 +34,11 @@ class SelectOptionTypeOptionBloc extends Bloc options = typeOptionAction.udpateOption(option); + final List options = typeOptionAction.udpateOption(option); emit(state.copyWith(options: options)); }, deleteOption: (option) { - final List options = typeOptionAction.deleteOption(option); + final List options = typeOptionAction.deleteOption(option); emit(state.copyWith(options: options)); }, ); @@ -57,19 +57,19 @@ class SelectOptionTypeOptionEvent with _$SelectOptionTypeOptionEvent { const factory SelectOptionTypeOptionEvent.createOption(String optionName) = _CreateOption; const factory SelectOptionTypeOptionEvent.addingOption() = _AddingOption; const factory SelectOptionTypeOptionEvent.endAddingOption() = _EndAddingOption; - const factory SelectOptionTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption; - const factory SelectOptionTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption; + const factory SelectOptionTypeOptionEvent.updateOption(SelectOptionPB option) = _UpdateOption; + const factory SelectOptionTypeOptionEvent.deleteOption(SelectOptionPB option) = _DeleteOption; } @freezed class SelectOptionTypeOptionState with _$SelectOptionTypeOptionState { const factory SelectOptionTypeOptionState({ - required List options, + required List options, required bool isEditingOption, required Option newOptionName, }) = _SelectOptionTyepOptionState; - factory SelectOptionTypeOptionState.initial(List options) => SelectOptionTypeOptionState( + factory SelectOptionTypeOptionState.initial(List options) => SelectOptionTypeOptionState( options: options, isEditingOption: false, newOptionName: none(), diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart index b2b4581d96..857838de38 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart @@ -7,7 +7,7 @@ import 'package:protobuf/protobuf.dart'; import 'select_option_type_option_bloc.dart'; import 'type_option_service.dart'; -class SingleSelectTypeOptionContext extends TypeOptionWidgetContext +class SingleSelectTypeOptionContext extends TypeOptionWidgetContext with SelectOptionTypeOptionAction { final TypeOptionService service; @@ -21,8 +21,8 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext Function(SelectOption) get deleteOption { - return (SelectOption option) { + List Function(SelectOptionPB) get deleteOption { + return (SelectOptionPB option) { typeOption.freeze(); typeOption = typeOption.rebuild((typeOption) { final index = typeOption.options.indexWhere((element) => element.id == option.id); @@ -35,7 +35,7 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext> Function(String) get insertOption { + Future> Function(String) get insertOption { return (String optionName) { return service.newOption(name: optionName).then((result) { return result.fold( @@ -57,8 +57,8 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext Function(SelectOption) get udpateOption { - return (SelectOption option) { + List Function(SelectOptionPB) get udpateOption { + return (SelectOptionPB option) { typeOption.freeze(); typeOption = typeOption.rebuild((typeOption) { final index = typeOption.options.indexWhere((element) => element.id == option.id); @@ -71,9 +71,9 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext { +class SingleSelectTypeOptionWidgetDataParser extends TypeOptionDataParser { @override - SingleSelectTypeOption fromBuffer(List buffer) { - return SingleSelectTypeOption.fromBuffer(buffer); + SingleSelectTypeOptionPB fromBuffer(List buffer) { + return SingleSelectTypeOptionPB.fromBuffer(buffer); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart index c7c86ae661..b45cc6f869 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart @@ -18,14 +18,14 @@ class TypeOptionService { required this.fieldId, }); - Future> newOption({ + Future> newOption({ required String name, }) { - final fieldIdentifier = FieldIdentifierPayload.create() + final fieldIdentifier = GridFieldIdentifierPayloadPB.create() ..gridId = gridId ..fieldId = fieldId; - final payload = CreateSelectOptionPayload.create() + final payload = CreateSelectOptionPayloadPB.create() ..optionName = name ..fieldIdentifier = fieldIdentifier; @@ -49,7 +49,7 @@ class TypeOptionWidgetContext { String get gridId => _dataController.gridId; - Field get field => _dataController.field; + GridFieldPB get field => _dataController.field; T get typeOption { if (_typeOptionObject != null) { @@ -74,7 +74,7 @@ abstract class TypeOptionFieldDelegate { class TypeOptionContext2 { final String gridId; - final Field field; + final GridFieldPB field; final FieldService _fieldService; T? _data; final TypeOptionDataParser dataBuilder; 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 aaf47d8fc9..2129632338 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -93,8 +93,8 @@ class GridBloc extends Bloc { ); } - Future _loadFields(Grid grid, Emitter emit) async { - final result = await _gridService.getFields(fieldOrders: grid.fields); + Future _loadFields(GridPB grid, Emitter emit) async { + final result = await _gridService.getFields(fieldIds: grid.fields); return Future( () => result.fold( (fields) { @@ -112,7 +112,7 @@ class GridBloc extends Bloc { ); } - void _initialBlocks(List blocks) { + void _initialBlocks(List blocks) { for (final block in blocks) { if (_blocks[block.id] != null) { Log.warn("Intial duplicate block's cache: ${block.id}"); @@ -141,14 +141,14 @@ class GridEvent with _$GridEvent { const factory GridEvent.createRow() = _CreateRow; const factory GridEvent.didReceiveRowUpdate(List rows, GridRowChangeReason listState) = _DidReceiveRowUpdate; - const factory GridEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; + const factory GridEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; } @freezed class GridState with _$GridState { const factory GridState({ required String gridId, - required Option grid, + required Option grid, required GridFieldEquatable fields, required List rowInfos, required GridLoadingState loadingState, @@ -172,8 +172,8 @@ class GridLoadingState with _$GridLoadingState { } class GridFieldEquatable extends Equatable { - final List _fields; - const GridFieldEquatable(List fields) : _fields = fields; + final List _fields; + const GridFieldEquatable(List fields) : _fields = fields; @override List get props { @@ -183,5 +183,5 @@ class GridFieldEquatable extends Equatable { ]; } - UnmodifiableListView get value => UnmodifiableListView(_fields); + UnmodifiableListView get value => UnmodifiableListView(_fields); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index 3e4db25b3d..b34064da13 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -34,7 +34,7 @@ class GridHeaderBloc extends Bloc { } Future _moveField(_MoveField value, Emitter emit) async { - final fields = List.from(state.fields); + final fields = List.from(state.fields); fields.insert(value.toIndex, fields.removeAt(value.fromIndex)); emit(state.copyWith(fields: fields)); @@ -62,16 +62,16 @@ class GridHeaderBloc extends Bloc { @freezed class GridHeaderEvent with _$GridHeaderEvent { const factory GridHeaderEvent.initial() = _InitialHeader; - const factory GridHeaderEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; - const factory GridHeaderEvent.moveField(Field field, int fromIndex, int toIndex) = _MoveField; + const factory GridHeaderEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; + const factory GridHeaderEvent.moveField(GridFieldPB field, int fromIndex, int toIndex) = _MoveField; } @freezed class GridHeaderState with _$GridHeaderState { - const factory GridHeaderState({required List fields}) = _GridHeaderState; + const factory GridHeaderState({required List fields}) = _GridHeaderState; - factory GridHeaderState.initial(List fields) { - // final List newFields = List.from(fields); + factory GridHeaderState.initial(List fields) { + // final List newFields = List.from(fields); // newFields.retainWhere((field) => field.visibility); return GridHeaderState(fields: fields); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index 1d0c309d51..e270e32bac 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -26,16 +26,16 @@ class GridService { return GridEventGetGrid(payload).send(); } - Future> createRow({Option? startRowId}) { - CreateRowPayload payload = CreateRowPayload.create()..gridId = gridId; + Future> createRow({Option? startRowId}) { + CreateRowPayloadPB payload = CreateRowPayloadPB.create()..gridId = gridId; startRowId?.fold(() => null, (id) => payload.startRowId = id); return GridEventCreateRow(payload).send(); } - Future> getFields({required List fieldOrders}) { - final payload = QueryFieldPayload.create() + Future> getFields({required List fieldIds}) { + final payload = QueryFieldPayloadPB.create() ..gridId = gridId - ..fieldOrders = RepeatedFieldOrder(items: fieldOrders); + ..fieldIds = RepeatedGridFieldIdPB(items: fieldIds); return GridEventGetFields(payload).send(); } @@ -46,18 +46,18 @@ class GridService { } class FieldsNotifier extends ChangeNotifier { - List _fields = []; + List _fields = []; - set fields(List fields) { + set fields(List fields) { _fields = fields; notifyListeners(); } - List get fields => _fields; + List get fields => _fields; } -typedef FieldChangesetCallback = void Function(GridFieldChangeset); -typedef FieldsCallback = void Function(List); +typedef FieldChangesetCallback = void Function(GridFieldChangesetPB); +typedef FieldsCallback = void Function(List); class GridFieldCache { final String gridId; @@ -88,11 +88,11 @@ class GridFieldCache { _fieldNotifier = null; } - UnmodifiableListView get unmodifiableFields => UnmodifiableListView(_fieldNotifier?.fields ?? []); + UnmodifiableListView get unmodifiableFields => UnmodifiableListView(_fieldNotifier?.fields ?? []); - List get fields => [..._fieldNotifier?.fields ?? []]; + List get fields => [..._fieldNotifier?.fields ?? []]; - set fields(List fields) { + set fields(List fields) { _fieldNotifier?.fields = [...fields]; } @@ -141,12 +141,12 @@ class GridFieldCache { } } - void _deleteFields(List deletedFields) { + void _deleteFields(List deletedFields) { if (deletedFields.isEmpty) { return; } - final List newFields = fields; - final Map deletedFieldMap = { + final List newFields = fields; + final Map deletedFieldMap = { for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder }; @@ -154,11 +154,11 @@ class GridFieldCache { _fieldNotifier?.fields = newFields; } - void _insertFields(List insertedFields) { + void _insertFields(List insertedFields) { if (insertedFields.isEmpty) { return; } - final List newFields = fields; + final List newFields = fields; for (final indexField in insertedFields) { if (newFields.length > indexField.index) { newFields.insert(indexField.index, indexField.field_1); @@ -169,11 +169,11 @@ class GridFieldCache { _fieldNotifier?.fields = newFields; } - void _updateFields(List updatedFields) { + void _updateFields(List updatedFields) { if (updatedFields.isEmpty) { return; } - final List newFields = fields; + final List newFields = fields; for (final updatedField in updatedFields) { final index = newFields.indexWhere((field) => field.id == updatedField.id); if (index != -1) { @@ -192,7 +192,7 @@ class GridRowCacheFieldNotifierImpl extends GridRowCacheFieldNotifier { GridRowCacheFieldNotifierImpl(GridFieldCache cache) : _cache = cache; @override - UnmodifiableListView get fields => _cache.unmodifiableFields; + UnmodifiableListView get fields => _cache.unmodifiableFields; @override void onFieldsChanged(VoidCallback callback) { @@ -201,8 +201,8 @@ class GridRowCacheFieldNotifierImpl extends GridRowCacheFieldNotifier { } @override - void onFieldChanged(void Function(Field) callback) { - _onChangesetFn = (GridFieldChangeset changeset) { + void onFieldChanged(void Function(GridFieldPB) callback) { + _onChangesetFn = (GridFieldChangesetPB changeset) { for (final updatedField in changeset.updatedFields) { callback(updatedField); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 9c09a038e1..2a19ca1134 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -4,18 +4,18 @@ export 'row/row_service.dart'; export 'grid_service.dart'; export 'grid_header_bloc.dart'; -// Field +// GridFieldPB export 'field/field_service.dart'; export 'field/field_action_sheet_bloc.dart'; export 'field/field_editor_bloc.dart'; export 'field/field_type_option_edit_bloc.dart'; -// Field Type Option +// GridFieldPB Type Option export 'field/type_option/date_bloc.dart'; export 'field/type_option/number_bloc.dart'; export 'field/type_option/single_select_type_option.dart'; -// Cell +// GridCellPB export 'cell/text_cell_bloc.dart'; export 'cell/number_cell_bloc.dart'; export 'cell/select_option_cell_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 6fec53b441..1d7224383d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart @@ -90,9 +90,9 @@ class RowState with _$RowState { } class GridCellEquatable extends Equatable { - final Field _field; + final GridFieldPB _field; - const GridCellEquatable(Field field) : _field = field; + const GridCellEquatable(GridFieldPB field) : _field = field; @override List get props => [ diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart index 98fddaeccf..9aa829d617 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart @@ -8,8 +8,8 @@ import 'dart:typed_data'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; -typedef UpdateRowNotifiedValue = Either; -typedef UpdateFieldNotifiedValue = Either, FlowyError>; +typedef UpdateRowNotifiedValue = Either; +typedef UpdateFieldNotifiedValue = Either, FlowyError>; class RowListener { final String rowId; @@ -26,7 +26,7 @@ class RowListener { switch (ty) { case GridNotification.DidUpdateRow: result.fold( - (payload) => updateRowNotifier?.value = left(Row.fromBuffer(payload)), + (payload) => updateRowNotifier?.value = left(GridRowPB.fromBuffer(payload)), (error) => updateRowNotifier?.value = right(error), ); break; 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 e733c6c20a..f8f9c7ee3c 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 @@ -15,9 +15,9 @@ part 'row_service.freezed.dart'; typedef RowUpdateCallback = void Function(); abstract class GridRowCacheFieldNotifier { - UnmodifiableListView get fields; + UnmodifiableListView get fields; void onFieldsChanged(VoidCallback callback); - void onFieldChanged(void Function(Field) callback); + void onFieldChanged(void Function(GridFieldPB) callback); void dispose(); } @@ -28,14 +28,14 @@ abstract class GridRowCacheFieldNotifier { class GridRowCache { final String gridId; - final GridBlock block; + final GridBlockPB block; /// _rows containers the current block's rows /// Use List to reverse the order of the GridRow. List _rowInfos = []; /// Use Map for faster access the raw row data. - final HashMap _rowByRowId; + final HashMap _rowByRowId; final GridCellCache _cellCache; final GridRowCacheFieldNotifier _fieldNotifier; @@ -64,7 +64,7 @@ class GridRowCache { await _cellCache.dispose(); } - void applyChangesets(List changesets) { + void applyChangesets(List changesets) { for (final changeset in changesets) { _deleteRows(changeset.deletedRows); _insertRows(changeset.insertedRows); @@ -95,7 +95,7 @@ class GridRowCache { _rowChangeReasonNotifier.receive(GridRowChangeReason.delete(deletedIndex)); } - void _insertRows(List insertRows) { + void _insertRows(List insertRows) { if (insertRows.isEmpty) { return; } @@ -113,7 +113,7 @@ class GridRowCache { _rowChangeReasonNotifier.receive(GridRowChangeReason.insert(insertIndexs)); } - void _updateRows(List updatedRows) { + void _updateRows(List updatedRows) { if (updatedRows.isEmpty) { return; } @@ -183,7 +183,7 @@ class GridRowCache { } GridCellMap loadGridCells(String rowId) { - final Row? data = _rowByRowId[rowId]; + final GridRowPB? data = _rowByRowId[rowId]; if (data == null) { _loadRow(rowId); } @@ -191,7 +191,7 @@ class GridRowCache { } Future _loadRow(String rowId) async { - final payload = GridRowIdPayload.create() + final payload = GridRowIdPayloadPB.create() ..gridId = gridId ..blockId = block.id ..rowId = rowId; @@ -203,7 +203,7 @@ class GridRowCache { ); } - GridCellMap _makeGridCells(String rowId, Row? row) { + GridCellMap _makeGridCells(String rowId, GridRowPB? row) { var cellDataMap = GridCellMap.new(); for (final field in _fieldNotifier.fields) { if (field.visibility) { @@ -217,7 +217,7 @@ class GridRowCache { return cellDataMap; } - void _refreshRow(OptionalRow optionRow) { + void _refreshRow(OptionalRowPB optionRow) { if (!optionRow.hasRow()) { return; } @@ -277,8 +277,8 @@ class RowService { RowService({required this.gridId, required this.blockId, required this.rowId}); - Future> createRow() { - CreateRowPayload payload = CreateRowPayload.create() + Future> createRow() { + CreateRowPayloadPB payload = CreateRowPayloadPB.create() ..gridId = gridId ..startRowId = rowId; @@ -286,18 +286,18 @@ class RowService { } Future> moveRow(String rowId, int fromIndex, int toIndex) { - final payload = MoveItemPayload.create() + final payload = MoveItemPayloadPB.create() ..gridId = gridId ..itemId = rowId - ..ty = MoveItemType.MoveRow + ..ty = MoveItemTypePB.MoveRow ..fromIndex = fromIndex ..toIndex = toIndex; return GridEventMoveItem(payload).send(); } - Future> getRow() { - final payload = GridRowIdPayload.create() + Future> getRow() { + final payload = GridRowIdPayloadPB.create() ..gridId = gridId ..blockId = blockId ..rowId = rowId; @@ -306,7 +306,7 @@ class RowService { } Future> deleteRow() { - final payload = GridRowIdPayload.create() + final payload = GridRowIdPayloadPB.create() ..gridId = gridId ..blockId = blockId ..rowId = rowId; @@ -315,7 +315,7 @@ class RowService { } Future> duplicateRow() { - final payload = GridRowIdPayload.create() + final payload = GridRowIdPayloadPB.create() ..gridId = gridId ..blockId = blockId ..rowId = rowId; @@ -330,9 +330,9 @@ class GridRowInfo with _$GridRowInfo { required String gridId, required String blockId, required String id, - required UnmodifiableListView fields, + required UnmodifiableListView fields, required double height, - Row? rawRow, + GridRowPB? rawRow, }) = _GridRowInfo; } diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index 10c59559d3..ee16eb0455 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -10,7 +10,7 @@ part 'property_bloc.freezed.dart'; class GridPropertyBloc extends Bloc { final GridFieldCache _fieldCache; - Function(List)? _onFieldsFn; + Function(List)? _onFieldsFn; GridPropertyBloc({required String gridId, required GridFieldCache fieldCache}) : _fieldCache = fieldCache, @@ -62,7 +62,7 @@ class GridPropertyBloc extends Bloc { class GridPropertyEvent with _$GridPropertyEvent { const factory GridPropertyEvent.initial() = _Initial; const factory GridPropertyEvent.setFieldVisibility(String fieldId, bool visibility) = _SetFieldVisibility; - const factory GridPropertyEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; + const factory GridPropertyEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; const factory GridPropertyEvent.moveField(int fromIndex, int toIndex) = _MoveField; } @@ -70,10 +70,10 @@ class GridPropertyEvent with _$GridPropertyEvent { class GridPropertyState with _$GridPropertyState { const factory GridPropertyState({ required String gridId, - required List fields, + required List fields, }) = _GridPropertyState; - factory GridPropertyState.initial(String gridId, List fields) => GridPropertyState( + factory GridPropertyState.initial(String gridId, List fields) => GridPropertyState( gridId: gridId, fields: fields, ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart index 36c603b7b4..0b289ecd4b 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/layout.dart @@ -2,7 +2,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'sizes.dart'; class GridLayout { - static double headerWidth(List fields) { + static double headerWidth(List fields) { if (fields.isEmpty) return 0; final fieldsWidth = fields.map((field) => field.width.toDouble()).reduce((value, element) => value + element); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/extension.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/extension.dart index 90a6503079..6946993bae 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/extension.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/extension.dart @@ -7,27 +7,27 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -extension SelectOptionColorExtension on SelectOptionColor { +extension SelectOptionColorExtension on SelectOptionColorPB { Color make(BuildContext context) { final theme = context.watch(); switch (this) { - case SelectOptionColor.Purple: + case SelectOptionColorPB.Purple: return theme.tint1; - case SelectOptionColor.Pink: + case SelectOptionColorPB.Pink: return theme.tint2; - case SelectOptionColor.LightPink: + case SelectOptionColorPB.LightPink: return theme.tint3; - case SelectOptionColor.Orange: + case SelectOptionColorPB.Orange: return theme.tint4; - case SelectOptionColor.Yellow: + case SelectOptionColorPB.Yellow: return theme.tint5; - case SelectOptionColor.Lime: + case SelectOptionColorPB.Lime: return theme.tint6; - case SelectOptionColor.Green: + case SelectOptionColorPB.Green: return theme.tint7; - case SelectOptionColor.Aqua: + case SelectOptionColorPB.Aqua: return theme.tint8; - case SelectOptionColor.Blue: + case SelectOptionColorPB.Blue: return theme.tint9; default: throw ArgumentError; @@ -36,23 +36,23 @@ extension SelectOptionColorExtension on SelectOptionColor { String optionName() { switch (this) { - case SelectOptionColor.Purple: + case SelectOptionColorPB.Purple: return LocaleKeys.grid_selectOption_purpleColor.tr(); - case SelectOptionColor.Pink: + case SelectOptionColorPB.Pink: return LocaleKeys.grid_selectOption_pinkColor.tr(); - case SelectOptionColor.LightPink: + case SelectOptionColorPB.LightPink: return LocaleKeys.grid_selectOption_lightPinkColor.tr(); - case SelectOptionColor.Orange: + case SelectOptionColorPB.Orange: return LocaleKeys.grid_selectOption_orangeColor.tr(); - case SelectOptionColor.Yellow: + case SelectOptionColorPB.Yellow: return LocaleKeys.grid_selectOption_yellowColor.tr(); - case SelectOptionColor.Lime: + case SelectOptionColorPB.Lime: return LocaleKeys.grid_selectOption_limeColor.tr(); - case SelectOptionColor.Green: + case SelectOptionColorPB.Green: return LocaleKeys.grid_selectOption_greenColor.tr(); - case SelectOptionColor.Aqua: + case SelectOptionColorPB.Aqua: return LocaleKeys.grid_selectOption_aquaColor.tr(); - case SelectOptionColor.Blue: + case SelectOptionColorPB.Blue: return LocaleKeys.grid_selectOption_blueColor.tr(); default: throw ArgumentError; @@ -75,7 +75,7 @@ class SelectOptionTag extends StatelessWidget { factory SelectOptionTag.fromSelectOption({ required BuildContext context, - required SelectOption option, + required SelectOptionPB option, VoidCallback? onSelected, bool isSelected = false, }) { @@ -107,8 +107,8 @@ class SelectOptionTag extends StatelessWidget { class SelectOptionTagCell extends StatelessWidget { final List children; - final void Function(SelectOption) onSelected; - final SelectOption option; + final void Function(SelectOptionPB) onSelected; + final SelectOptionPB option; const SelectOptionTagCell({ required this.option, required this.onSelected, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart index 4068507f5a..6669e84576 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart @@ -128,7 +128,7 @@ class _MultiSelectCellState extends State { } class _SelectOptionCell extends StatelessWidget { - final List selectOptions; + final List selectOptions; final void Function(bool) onFocus; final SelectOptionCellStyle? cellStyle; final GridCellControllerBuilder cellContorllerBuilder; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_editor.dart index 45a641c39c..95f2bf1e03 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_editor.dart @@ -146,7 +146,7 @@ class _TextField extends StatelessWidget { Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { - final optionMap = LinkedHashMap.fromIterable(state.selectedOptions, + final optionMap = LinkedHashMap.fromIterable(state.selectedOptions, key: (option) => option.name, value: (option) => option); return SizedBox( @@ -216,7 +216,7 @@ class _CreateOptionCell extends StatelessWidget { } class _SelectOptionCell extends StatelessWidget { - final SelectOption option; + final SelectOptionPB option; final bool isSelected; const _SelectOptionCell(this.option, this.isSelected, {Key? key}) : super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/text_field.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/text_field.dart index 9bffd4554f..10b04cfb58 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/text_field.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/text_field.dart @@ -15,8 +15,8 @@ class SelectOptionTextField extends StatelessWidget { final FocusNode _focusNode; final TextEditingController _controller; final TextfieldTagsController tagController; - final List options; - final LinkedHashMap selectedOptionMap; + final List options; + final LinkedHashMap selectedOptionMap; final double distanceToText; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index 266ec5a619..8202a3537f 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -135,7 +135,7 @@ class _DragToExpandLine extends StatelessWidget { class FieldCellButton extends StatelessWidget { final VoidCallback onTap; - final Field field; + final GridFieldPB field; const FieldCellButton({ required this.field, required this.onTap, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart index 60592d1032..95dd39bae9 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_option_editor.dart @@ -15,8 +15,8 @@ import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header import 'field_type_extension.dart'; import 'type_option/builder.dart'; -typedef UpdateFieldCallback = void Function(Field, Uint8List); -typedef SwitchToFieldCallback = Future> Function( +typedef UpdateFieldCallback = void Function(GridFieldPB, Uint8List); +typedef SwitchToFieldCallback = Future> Function( String fieldId, FieldType fieldType, ); @@ -59,7 +59,7 @@ class _FieldTypeOptionEditorState extends State { ); } - Widget _switchFieldTypeButton(BuildContext context, Field field) { + Widget _switchFieldTypeButton(BuildContext context, GridFieldPB field) { final theme = context.watch(); return SizedBox( height: GridSize.typeOptionItemHeight, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 2240d7f6aa..5a888129b5 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -160,7 +160,7 @@ class CreateFieldButton extends StatelessWidget { class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate { final String gridId; - final List fields; + final List fields; SliverHeaderDelegateImplementation({required this.gridId, required this.fields}); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart index fea3e5df43..c0d54159e8 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart @@ -17,7 +17,7 @@ import 'builder.dart'; import 'select_option_editor.dart'; class SelectOptionTypeOptionWidget extends StatelessWidget { - final List options; + final List options; final VoidCallback beginEdit; final TypeOptionOverlayDelegate overlayDelegate; final SelectOptionTypeOptionAction typeOptionAction; @@ -131,7 +131,7 @@ class _OptionList extends StatelessWidget { ); } - _OptionCell _makeOptionCell(BuildContext context, SelectOption option) { + _OptionCell _makeOptionCell(BuildContext context, SelectOptionPB option) { return _OptionCell( option: option, onSelected: (option) { @@ -154,8 +154,8 @@ class _OptionList extends StatelessWidget { } class _OptionCell extends StatelessWidget { - final SelectOption option; - final Function(SelectOption) onSelected; + final SelectOptionPB option; + final Function(SelectOptionPB) onSelected; const _OptionCell({ required this.option, required this.onSelected, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option_editor.dart index 3abb0445c7..5381342d20 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option_editor.dart @@ -15,9 +15,9 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; class SelectOptionTypeOptionEditor extends StatelessWidget { - final SelectOption option; + final SelectOptionPB option; final VoidCallback onDeleted; - final Function(SelectOption) onUpdated; + final Function(SelectOptionPB) onUpdated; const SelectOptionTypeOptionEditor({ required this.option, required this.onDeleted, @@ -110,12 +110,12 @@ class _OptionNameTextField extends StatelessWidget { } class SelectOptionColorList extends StatelessWidget { - final SelectOptionColor selectedColor; + final SelectOptionColorPB selectedColor; const SelectOptionColorList({required this.selectedColor, Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final cells = SelectOptionColor.values.map((color) { + final cells = SelectOptionColorPB.values.map((color) { return _SelectOptionColorCell(color: color, isSelected: selectedColor == color); }).toList(); @@ -152,7 +152,7 @@ class SelectOptionColorList extends StatelessWidget { } class _SelectOptionColorCell extends StatelessWidget { - final SelectOptionColor color; + final SelectOptionColorPB color; final bool isSelected; const _SelectOptionColorCell({required this.color, required this.isSelected, Key? key}) : super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index 99d70e93c7..b34007493b 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -75,7 +75,7 @@ class GridPropertyList extends StatelessWidget with FlowyOverlayDelegate { } class _GridPropertyCell extends StatelessWidget { - final Field field; + final GridFieldPB field; final String gridId; const _GridPropertyCell({required this.gridId, required this.field, Key? key}) : super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/emoji_picker/src/emoji_lists.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/emoji_picker/src/emoji_lists.dart index 8bb45b51cd..b5d364f67e 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/emoji_picker/src/emoji_lists.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/emoji_picker/src/emoji_lists.dart @@ -1632,7 +1632,7 @@ final Map activities = Map.fromIterables([ 'Flying Disc', 'Bowling', 'Cricket Game', - 'Field Hockey', + 'GridFieldPB Hockey', 'Ice Hockey', 'Lacrosse', 'Ping Pong', diff --git a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs index 57993a27db..11cbdeb88e 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs @@ -1,4 +1,4 @@ -use crate::entities::{FieldIdentifier, FieldIdentifierPayloadPB}; +use crate::entities::{FieldIdentifierParams, GridFieldIdentifierPayloadPB}; use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; @@ -6,28 +6,28 @@ use flowy_grid_data_model::revision::{CellRevision, RowMetaChangeset}; use std::collections::HashMap; #[derive(ProtoBuf, Default)] -pub struct CreateSelectOptionPayload { +pub struct CreateSelectOptionPayloadPB { #[pb(index = 1)] - pub field_identifier: FieldIdentifierPayloadPB, + pub field_identifier: GridFieldIdentifierPayloadPB, #[pb(index = 2)] pub option_name: String, } pub struct CreateSelectOptionParams { - pub field_identifier: FieldIdentifier, + pub field_identifier: FieldIdentifierParams, pub option_name: String, } impl std::ops::Deref for CreateSelectOptionParams { - type Target = FieldIdentifier; + type Target = FieldIdentifierParams; fn deref(&self) -> &Self::Target { &self.field_identifier } } -impl TryInto for CreateSelectOptionPayload { +impl TryInto for CreateSelectOptionPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -41,7 +41,7 @@ impl TryInto for CreateSelectOptionPayload { } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct CellIdentifierPayload { +pub struct GridCellIdentifierPayloadPB { #[pb(index = 1)] pub grid_id: String, @@ -52,20 +52,20 @@ pub struct CellIdentifierPayload { pub row_id: String, } -pub struct CellIdentifier { +pub struct CellIdentifierParams { pub grid_id: String, pub field_id: String, pub row_id: String, } -impl TryInto for CellIdentifierPayload { +impl TryInto for GridCellIdentifierPayloadPB { type Error = ErrorCode; - fn try_into(self) -> Result { + fn try_into(self) -> Result { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; - Ok(CellIdentifier { + Ok(CellIdentifierParams { grid_id: grid_id.0, field_id: field_id.0, row_id: row_id.0, @@ -73,7 +73,7 @@ impl TryInto for CellIdentifierPayload { } } #[derive(Debug, Default, ProtoBuf)] -pub struct Cell { +pub struct GridCellPB { #[pb(index = 1)] pub field_id: String, @@ -81,7 +81,7 @@ pub struct Cell { pub data: Vec, } -impl Cell { +impl GridCellPB { pub fn new(field_id: &str, data: Vec) -> Self { Self { field_id: field_id.to_owned(), @@ -98,32 +98,32 @@ impl Cell { } #[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedCell { +pub struct RepeatedCellPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl std::ops::Deref for RepeatedCell { - type Target = Vec; +impl std::ops::Deref for RepeatedCellPB { + type Target = Vec; fn deref(&self) -> &Self::Target { &self.items } } -impl std::ops::DerefMut for RepeatedCell { +impl std::ops::DerefMut for RepeatedCellPB { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.items } } -impl std::convert::From> for RepeatedCell { - fn from(items: Vec) -> Self { +impl std::convert::From> for RepeatedCellPB { + fn from(items: Vec) -> Self { Self { items } } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct CellChangeset { +pub struct CellChangesetPB { #[pb(index = 1)] pub grid_id: String, @@ -137,8 +137,8 @@ pub struct CellChangeset { pub content: Option, } -impl std::convert::From for RowMetaChangeset { - fn from(changeset: CellChangeset) -> Self { +impl std::convert::From for RowMetaChangeset { + fn from(changeset: CellChangesetPB) -> Self { let mut cell_by_field_id = HashMap::with_capacity(1); let field_id = changeset.field_id; let cell_rev = CellRevision { diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index 1a4fac2e8c..c769b4f08b 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -9,7 +9,7 @@ use std::sync::Arc; use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString}; #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct FieldPB { +pub struct GridFieldPB { #[pb(index = 1)] pub id: String, @@ -35,7 +35,7 @@ pub struct FieldPB { pub is_primary: bool, } -impl std::convert::From for FieldPB { +impl std::convert::From for GridFieldPB { fn from(field_rev: FieldRevision) -> Self { Self { id: field_rev.id, @@ -50,31 +50,31 @@ impl std::convert::From for FieldPB { } } -impl std::convert::From> for FieldPB { +impl std::convert::From> for GridFieldPB { fn from(field_rev: Arc) -> Self { let field_rev = field_rev.as_ref().clone(); - FieldPB::from(field_rev) + GridFieldPB::from(field_rev) } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridFieldPB { +pub struct GridFieldIdPB { #[pb(index = 1)] pub field_id: String, } -impl std::convert::From<&str> for GridFieldPB { +impl std::convert::From<&str> for GridFieldIdPB { fn from(s: &str) -> Self { - GridFieldPB { field_id: s.to_owned() } + GridFieldIdPB { field_id: s.to_owned() } } } -impl std::convert::From for GridFieldPB { +impl std::convert::From for GridFieldIdPB { fn from(s: String) -> Self { - GridFieldPB { field_id: s } + GridFieldIdPB { field_id: s } } } -impl std::convert::From<&Arc> for GridFieldPB { +impl std::convert::From<&Arc> for GridFieldIdPB { fn from(field_rev: &Arc) -> Self { Self { field_id: field_rev.id.clone(), @@ -90,10 +90,10 @@ pub struct GridFieldChangesetPB { pub inserted_fields: Vec, #[pb(index = 3)] - pub deleted_fields: Vec, + pub deleted_fields: Vec, #[pb(index = 4)] - pub updated_fields: Vec, + pub updated_fields: Vec, } impl GridFieldChangesetPB { @@ -106,7 +106,7 @@ impl GridFieldChangesetPB { } } - pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { + pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { Self { grid_id: grid_id.to_string(), inserted_fields: vec![], @@ -115,7 +115,7 @@ impl GridFieldChangesetPB { } } - pub fn update(grid_id: &str, updated_fields: Vec) -> Self { + pub fn update(grid_id: &str, updated_fields: Vec) -> Self { Self { grid_id: grid_id.to_string(), inserted_fields: vec![], @@ -128,7 +128,7 @@ impl GridFieldChangesetPB { #[derive(Debug, Clone, Default, ProtoBuf)] pub struct IndexFieldPB { #[pb(index = 1)] - pub field: FieldPB, + pub field: GridFieldPB, #[pb(index = 2)] pub index: i32, @@ -137,7 +137,7 @@ pub struct IndexFieldPB { impl IndexFieldPB { pub fn from_field_rev(field_rev: &Arc, index: usize) -> Self { Self { - field: FieldPB::from(field_rev.as_ref().clone()), + field: GridFieldPB::from(field_rev.as_ref().clone()), index: index as i32, } } @@ -214,42 +214,17 @@ pub struct FieldTypeOptionDataPB { pub grid_id: String, #[pb(index = 2)] - pub field: FieldPB, + pub field: GridFieldPB, #[pb(index = 3)] pub type_option_data: Vec, } #[derive(Debug, Default, ProtoBuf)] -pub struct RepeatedFieldPB { - #[pb(index = 1)] - pub items: Vec, -} -impl std::ops::Deref for RepeatedFieldPB { - type Target = Vec; - fn deref(&self) -> &Self::Target { - &self.items - } -} - -impl std::ops::DerefMut for RepeatedFieldPB { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.items - } -} - -impl std::convert::From> for RepeatedFieldPB { - fn from(items: Vec) -> Self { - Self { items } - } -} - -#[derive(Debug, Clone, Default, ProtoBuf)] pub struct RepeatedGridFieldPB { #[pb(index = 1)] pub items: Vec, } - impl std::ops::Deref for RepeatedGridFieldPB { type Target = Vec; fn deref(&self) -> &Self::Target { @@ -257,16 +232,41 @@ impl std::ops::Deref for RepeatedGridFieldPB { } } -impl std::convert::From> for RepeatedGridFieldPB { - fn from(field_orders: Vec) -> Self { - RepeatedGridFieldPB { items: field_orders } +impl std::ops::DerefMut for RepeatedGridFieldPB { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.items } } -impl std::convert::From for RepeatedGridFieldPB { +impl std::convert::From> for RepeatedGridFieldPB { + fn from(items: Vec) -> Self { + Self { items } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct RepeatedGridFieldIdPB { + #[pb(index = 1)] + pub items: Vec, +} + +impl std::ops::Deref for RepeatedGridFieldIdPB { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.items + } +} + +impl std::convert::From> for RepeatedGridFieldIdPB { + fn from(items: Vec) -> Self { + RepeatedGridFieldIdPB { items } + } +} + +impl std::convert::From for RepeatedGridFieldIdPB { fn from(s: String) -> Self { - RepeatedGridFieldPB { - items: vec![GridFieldPB::from(s)], + RepeatedGridFieldIdPB { + items: vec![GridFieldIdPB::from(s)], } } } @@ -277,7 +277,7 @@ pub struct InsertFieldPayloadPB { pub grid_id: String, #[pb(index = 2)] - pub field: FieldPB, + pub field: GridFieldPB, #[pb(index = 3)] pub type_option_data: Vec, @@ -289,7 +289,7 @@ pub struct InsertFieldPayloadPB { #[derive(Clone)] pub struct InsertFieldParams { pub grid_id: String, - pub field: FieldPB, + pub field: GridFieldPB, pub type_option_data: Vec, pub start_field_id: Option, } @@ -355,12 +355,12 @@ pub struct QueryFieldPayloadPB { pub grid_id: String, #[pb(index = 2)] - pub field_orders: RepeatedGridFieldPB, + pub field_ids: RepeatedGridFieldIdPB, } pub struct QueryFieldParams { pub grid_id: String, - pub field_orders: RepeatedGridFieldPB, + pub field_ids: RepeatedGridFieldIdPB, } impl TryInto for QueryFieldPayloadPB { @@ -370,7 +370,7 @@ impl TryInto for QueryFieldPayloadPB { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; Ok(QueryFieldParams { grid_id: grid_id.0, - field_orders: self.field_orders, + field_ids: self.field_ids, }) } } @@ -557,7 +557,7 @@ impl std::convert::From for FieldType { } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct FieldIdentifierPayloadPB { +pub struct GridFieldIdentifierPayloadPB { #[pb(index = 1)] pub field_id: String, @@ -565,18 +565,18 @@ pub struct FieldIdentifierPayloadPB { pub grid_id: String, } -pub struct FieldIdentifier { +pub struct FieldIdentifierParams { pub field_id: String, pub grid_id: String, } -impl TryInto for FieldIdentifierPayloadPB { +impl TryInto for GridFieldIdentifierPayloadPB { type Error = ErrorCode; - fn try_into(self) -> Result { + fn try_into(self) -> Result { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; - Ok(FieldIdentifier { + Ok(FieldIdentifierParams { grid_id: grid_id.0, field_id: field_id.0, }) diff --git a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs index d333f201a4..1be0412503 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs @@ -1,4 +1,4 @@ -use crate::entities::{GridBlockPB, GridFieldPB}; +use crate::entities::{GridBlockPB, GridFieldIdPB}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; @@ -8,7 +8,7 @@ pub struct GridPB { pub id: String, #[pb(index = 2)] - pub fields: Vec, + pub fields: Vec, #[pb(index = 3)] pub blocks: Vec, diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 81f74c8e32..4c4bfe5559 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -3,9 +3,9 @@ use crate::manager::GridManager; use crate::services::cell::AnyCellData; use crate::services::field::{ default_type_option_builder_from_type, select_option_operation, type_option_builder_from_json_str, - DateChangesetParams, DateChangesetPayloadPB, SelectOptionPB, SelectOptionCellChangeset, - SelectOptionCellChangesetParams, SelectOptionCellChangesetPayloadPB, SelectOptionCellDataPB, SelectOptionChangeset, - SelectOptionChangesetPayloadPB, + DateChangesetParams, DateChangesetPayloadPB, SelectOptionCellChangeset, SelectOptionCellChangesetParams, + SelectOptionCellChangesetPayloadPB, SelectOptionCellDataPB, SelectOptionChangeset, SelectOptionChangesetPayloadPB, + SelectOptionPB, }; use crate::services::row::make_row_from_row_rev; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; @@ -62,17 +62,17 @@ pub(crate) async fn get_grid_blocks_handler( pub(crate) async fn get_fields_handler( data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: QueryFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let field_orders = params - .field_orders + .field_ids .items .into_iter() .map(|field_order| field_order.field_id) .collect(); let field_revs = editor.get_field_revs(Some(field_orders)).await?; - let repeated_field: RepeatedFieldPB = field_revs.into_iter().map(FieldPB::from).collect::>().into(); + let repeated_field: RepeatedGridFieldPB = field_revs.into_iter().map(GridFieldPB::from).collect::>().into(); data_result(repeated_field) } @@ -113,10 +113,10 @@ pub(crate) async fn update_field_type_option_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn delete_field_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: FieldIdentifier = data.into_inner().try_into()?; + let params: FieldIdentifierParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.delete_field(¶ms.field_id).await?; Ok(()) @@ -151,10 +151,10 @@ pub(crate) async fn switch_to_field_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn duplicate_field_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: FieldIdentifier = data.into_inner().try_into()?; + let params: FieldIdentifierParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.duplicate_field(¶ms.field_id).await?; Ok(()) @@ -275,23 +275,23 @@ pub(crate) async fn create_row_handler( // #[tracing::instrument(level = "debug", skip_all, err)] pub(crate) async fn get_cell_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { - let params: CellIdentifier = data.into_inner().try_into()?; +) -> DataResult { + let params: CellIdentifierParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_cell(¶ms).await { - None => data_result(Cell::empty(¶ms.field_id)), + None => data_result(GridCellPB::empty(¶ms.field_id)), Some(cell) => data_result(cell), } } #[tracing::instrument(level = "trace", skip_all, err)] pub(crate) async fn update_cell_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let changeset: CellChangeset = data.into_inner(); + let changeset: CellChangesetPB = data.into_inner(); let editor = manager.get_grid_editor(&changeset.grid_id)?; let _ = editor.update_cell(changeset).await?; Ok(()) @@ -299,7 +299,7 @@ pub(crate) async fn update_cell_handler( #[tracing::instrument(level = "trace", skip_all, err)] pub(crate) async fn new_select_option_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { let params: CreateSelectOptionParams = data.into_inner().try_into()?; @@ -344,7 +344,7 @@ pub(crate) async fn update_select_option_handler( mut_field_rev.insert_type_option_entry(&*type_option); let _ = editor.replace_field(field_rev).await?; - let changeset = CellChangeset { + let changeset = CellChangesetPB { grid_id: changeset.cell_identifier.grid_id, row_id: changeset.cell_identifier.row_id, field_id: changeset.cell_identifier.field_id, @@ -357,10 +357,10 @@ pub(crate) async fn update_select_option_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn get_select_option_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { - let params: CellIdentifier = data.into_inner().try_into()?; + let params: CellIdentifierParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_field_rev(¶ms.field_id).await { None => { diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index 8739be5257..5abda48c1b 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -45,78 +45,78 @@ pub fn create(grid_manager: Arc) -> Module { #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] #[event_err = "FlowyError"] pub enum GridEvent { - #[event(input = "GridId", output = "Grid")] + #[event(input = "GridIdPB", output = "GridPB")] GetGrid = 0, - #[event(input = "QueryGridBlocksPayload", output = "RepeatedGridBlock")] + #[event(input = "QueryGridBlocksPayloadPB", output = "RepeatedGridBlockPB")] GetGridBlocks = 1, - #[event(input = "GridId", output = "GridSetting")] + #[event(input = "GridIdPB", output = "GridSettingPB")] GetGridSetting = 2, - #[event(input = "GridId", input = "GridSettingChangesetPayload")] + #[event(input = "GridIdPB", input = "GridSettingChangesetPayloadPB")] UpdateGridSetting = 3, - #[event(input = "QueryFieldPayload", output = "RepeatedField")] + #[event(input = "QueryFieldPayloadPB", output = "RepeatedGridFieldPB")] GetFields = 10, - #[event(input = "FieldChangesetPayload")] + #[event(input = "FieldChangesetPayloadPB")] UpdateField = 11, - #[event(input = "UpdateFieldTypeOptionPayload")] + #[event(input = "UpdateFieldTypeOptionPayloadPB")] UpdateFieldTypeOption = 12, - #[event(input = "InsertFieldPayload")] + #[event(input = "InsertFieldPayloadPB")] InsertField = 13, - #[event(input = "FieldIdentifierPayload")] + #[event(input = "GridFieldIdentifierPayloadPB")] DeleteField = 14, - #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")] + #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")] SwitchToField = 20, - #[event(input = "FieldIdentifierPayload")] + #[event(input = "GridFieldIdentifierPayloadPB")] DuplicateField = 21, - #[event(input = "MoveItemPayload")] + #[event(input = "MoveItemPayloadPB")] MoveItem = 22, - #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")] + #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")] GetFieldTypeOption = 23, - #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")] + #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")] CreateFieldTypeOption = 24, - #[event(input = "CreateSelectOptionPayload", output = "SelectOption")] + #[event(input = "CreateSelectOptionPayloadPB", output = "SelectOptionPB")] NewSelectOption = 30, - #[event(input = "CellIdentifierPayload", output = "SelectOptionCellData")] + #[event(input = "GridCellIdentifierPayloadPB", output = "SelectOptionCellDataPB")] GetSelectOptionCellData = 31, - #[event(input = "SelectOptionChangesetPayload")] + #[event(input = "SelectOptionChangesetPayloadPB")] UpdateSelectOption = 32, - #[event(input = "CreateRowPayload", output = "Row")] + #[event(input = "CreateRowPayloadPB", output = "GridRowPB")] CreateRow = 50, - #[event(input = "GridRowIdPayload", output = "OptionalRow")] + #[event(input = "GridRowIdPayloadPB", output = "OptionalRowPB")] GetRow = 51, - #[event(input = "GridRowIdPayload")] + #[event(input = "GridRowIdPayloadPB")] DeleteRow = 52, - #[event(input = "GridRowIdPayload")] + #[event(input = "GridRowIdPayloadPB")] DuplicateRow = 53, - #[event(input = "CellIdentifierPayload", output = "Cell")] + #[event(input = "GridCellIdentifierPayloadPB", output = "GridCellPB")] GetCell = 70, - #[event(input = "CellChangeset")] + #[event(input = "CellChangesetPB")] UpdateCell = 71, - #[event(input = "SelectOptionCellChangesetPayload")] + #[event(input = "SelectOptionCellChangesetPayloadPB")] UpdateSelectOptionCell = 72, - #[event(input = "DateChangesetPayload")] + #[event(input = "DateChangesetPayloadPB")] UpdateDateCell = 80, } 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 0bbd3b09f0..39c1a442b5 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs @@ -1,5 +1,5 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; -use crate::entities::{CellChangeset, GridBlockChangesetPB, GridRowPB, InsertedRowPB, UpdatedRowPB}; +use crate::entities::{CellChangesetPB, GridBlockChangesetPB, GridRowPB, InsertedRowPB, UpdatedRowPB}; use crate::manager::GridUser; use crate::services::block_revision_editor::GridBlockRevisionEditor; use crate::services::persistence::block_index::BlockIndexCache; @@ -196,7 +196,7 @@ impl GridBlockManager { Ok(()) } - pub async fn update_cell(&self, changeset: CellChangeset, row_builder: F) -> FlowyResult<()> + pub async fn update_cell(&self, changeset: CellChangesetPB, row_builder: F) -> FlowyResult<()> where F: FnOnce(Arc) -> Option, { @@ -254,7 +254,7 @@ impl GridBlockManager { Ok(()) } - async fn notify_did_update_cell(&self, changeset: CellChangeset) -> FlowyResult<()> { + async fn notify_did_update_cell(&self, changeset: CellChangesetPB) -> FlowyResult<()> { let id = format!("{}:{}", changeset.row_id, changeset.field_id); send_dart_notification(&id, GridNotification::DidUpdateCell).send(); Ok(()) diff --git a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs index dea6686915..de1f37b04f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/field_builder.rs @@ -1,4 +1,4 @@ -use crate::entities::{FieldPB, FieldType}; +use crate::entities::{FieldType, GridFieldPB}; use crate::services::field::type_options::*; use bytes::Bytes; use flowy_grid_data_model::revision::{FieldRevision, TypeOptionDataEntry}; @@ -28,7 +28,7 @@ impl FieldBuilder { Self::new(type_option_builder) } - pub fn from_field(field: FieldPB, type_option_builder: Box) -> Self { + pub fn from_field(field: GridFieldPB, type_option_builder: Box) -> Self { let field_rev = FieldRevision { id: field.id, name: field.name, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs index 28dfd90dcf..aa8fab221a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs @@ -1,5 +1,5 @@ -use crate::entities::CellChangeset; -use crate::entities::{CellIdentifier, CellIdentifierPayload}; +use crate::entities::CellChangesetPB; +use crate::entities::{CellIdentifierParams, GridCellIdentifierPayloadPB}; use crate::services::cell::{CellBytesParser, FromCellChangeset, FromCellString}; use bytes::Bytes; @@ -24,7 +24,7 @@ pub struct DateCellDataPB { #[derive(Clone, Debug, Default, ProtoBuf)] pub struct DateChangesetPayloadPB { #[pb(index = 1)] - pub cell_identifier: CellIdentifierPayload, + pub cell_identifier: GridCellIdentifierPayloadPB, #[pb(index = 2, one_of)] pub date: Option, @@ -34,7 +34,7 @@ pub struct DateChangesetPayloadPB { } pub struct DateChangesetParams { - pub cell_identifier: CellIdentifier, + pub cell_identifier: CellIdentifierParams, pub date: Option, pub time: Option, } @@ -43,7 +43,7 @@ impl TryInto for DateChangesetPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { - let cell_identifier: CellIdentifier = self.cell_identifier.try_into()?; + let cell_identifier: CellIdentifierParams = self.cell_identifier.try_into()?; Ok(DateChangesetParams { cell_identifier, date: self.date, @@ -52,14 +52,14 @@ impl TryInto for DateChangesetPayloadPB { } } -impl std::convert::From for CellChangeset { +impl std::convert::From for CellChangesetPB { fn from(params: DateChangesetParams) -> Self { let changeset = DateCellChangesetPB { date: params.date, time: params.time, }; let s = serde_json::to_string(&changeset).unwrap(); - CellChangeset { + CellChangesetPB { grid_id: params.cell_identifier.grid_id, row_id: params.cell_identifier.row_id, field_id: params.cell_identifier.field_id, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index e3dd16ef2f..dbffe79f56 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -1,4 +1,4 @@ -use crate::entities::{CellChangeset, CellIdentifier, CellIdentifierPayload, FieldType}; +use crate::entities::{CellChangesetPB, CellIdentifierParams, FieldType, GridCellIdentifierPayloadPB}; use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; use bytes::Bytes; @@ -225,7 +225,7 @@ impl CellBytesParser for SelectOptionCellDataParser { #[derive(Clone, Debug, Default, ProtoBuf)] pub struct SelectOptionCellChangesetPayloadPB { #[pb(index = 1)] - pub cell_identifier: CellIdentifierPayload, + pub cell_identifier: GridCellIdentifierPayloadPB, #[pb(index = 2, one_of)] pub insert_option_id: Option, @@ -235,19 +235,19 @@ pub struct SelectOptionCellChangesetPayloadPB { } pub struct SelectOptionCellChangesetParams { - pub cell_identifier: CellIdentifier, + pub cell_identifier: CellIdentifierParams, pub insert_option_id: Option, pub delete_option_id: Option, } -impl std::convert::From for CellChangeset { +impl std::convert::From for CellChangesetPB { fn from(params: SelectOptionCellChangesetParams) -> Self { let changeset = SelectOptionCellChangeset { insert_option_id: params.insert_option_id, delete_option_id: params.delete_option_id, }; let s = serde_json::to_string(&changeset).unwrap(); - CellChangeset { + CellChangesetPB { grid_id: params.cell_identifier.grid_id, row_id: params.cell_identifier.row_id, field_id: params.cell_identifier.field_id, @@ -260,7 +260,7 @@ impl TryInto for SelectOptionCellChangesetPaylo type Error = ErrorCode; fn try_into(self) -> Result { - let cell_identifier: CellIdentifier = self.cell_identifier.try_into()?; + let cell_identifier: CellIdentifierParams = self.cell_identifier.try_into()?; let insert_option_id = match self.insert_option_id { None => None, Some(insert_option_id) => Some( @@ -334,7 +334,7 @@ pub struct SelectOptionCellDataPB { #[derive(Clone, Debug, Default, ProtoBuf)] pub struct SelectOptionChangesetPayloadPB { #[pb(index = 1)] - pub cell_identifier: CellIdentifierPayload, + pub cell_identifier: GridCellIdentifierPayloadPB, #[pb(index = 2, one_of)] pub insert_option: Option, @@ -347,7 +347,7 @@ pub struct SelectOptionChangesetPayloadPB { } pub struct SelectOptionChangeset { - pub cell_identifier: CellIdentifier, + pub cell_identifier: CellIdentifierParams, pub insert_option: Option, pub update_option: Option, pub delete_option: Option, 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 a292ffa1ff..0fef3230de 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -1,5 +1,5 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; -use crate::entities::CellIdentifier; +use crate::entities::CellIdentifierParams; use crate::entities::*; use crate::manager::{GridTaskSchedulerRwLock, GridUser}; use crate::services::block_manager::GridBlockManager; @@ -188,7 +188,7 @@ impl GridRevisionEditor { pub async fn delete_field(&self, field_id: &str) -> FlowyResult<()> { let _ = self.modify(|grid_pad| Ok(grid_pad.delete_field_rev(field_id)?)).await?; - let field_order = GridFieldPB::from(field_id); + let field_order = GridFieldIdPB::from(field_id); let notified_changeset = GridFieldChangesetPB::delete(&self.grid_id, vec![field_order]); let _ = self.notify_did_update_grid(notified_changeset).await?; Ok(()) @@ -339,12 +339,12 @@ impl GridRevisionEditor { Ok(()) } - pub async fn get_cell(&self, params: &CellIdentifier) -> Option { + pub async fn get_cell(&self, params: &CellIdentifierParams) -> Option { let cell_bytes = self.get_cell_bytes(params).await?; - Some(Cell::new(¶ms.field_id, cell_bytes.to_vec())) + Some(GridCellPB::new(¶ms.field_id, cell_bytes.to_vec())) } - pub async fn get_cell_bytes(&self, params: &CellIdentifier) -> Option { + pub async fn get_cell_bytes(&self, params: &CellIdentifierParams) -> Option { let field_rev = self.get_field_rev(¶ms.field_id).await?; let row_rev = self.block_manager.get_row_rev(¶ms.row_id).await.ok()??; @@ -364,12 +364,12 @@ impl GridRevisionEditor { } #[tracing::instrument(level = "trace", skip_all, err)] - pub async fn update_cell(&self, cell_changeset: CellChangeset) -> FlowyResult<()> { + pub async fn update_cell(&self, cell_changeset: CellChangesetPB) -> FlowyResult<()> { if cell_changeset.content.as_ref().is_none() { return Ok(()); } - let CellChangeset { + let CellChangesetPB { grid_id, row_id, field_id, @@ -387,7 +387,7 @@ impl GridRevisionEditor { let cell_rev = self.get_cell_rev(&row_id, &field_id).await?; // Update the changeset.data property with the return value. content = Some(apply_cell_data_changeset(content.unwrap(), cell_rev, field_rev)?); - let cell_changeset = CellChangeset { + let cell_changeset = CellChangesetPB { grid_id, row_id, field_id, @@ -425,7 +425,7 @@ impl GridRevisionEditor { let field_orders = pad_read_guard .get_field_revs(None)? .iter() - .map(GridFieldPB::from) + .map(GridFieldIdPB::from) .collect(); let mut block_orders = vec![]; for block_rev in pad_read_guard.get_block_meta_revs() { @@ -508,7 +508,7 @@ impl GridRevisionEditor { .modify(|grid_pad| Ok(grid_pad.move_field(field_id, from as usize, to as usize)?)) .await?; if let Some((index, field_rev)) = self.grid_pad.read().await.get_field_rev(field_id) { - let delete_field_order = GridFieldPB::from(field_id); + let delete_field_order = GridFieldIdPB::from(field_id); let insert_field = IndexFieldPB::from_field_rev(field_rev, index); let notified_changeset = GridFieldChangesetPB { grid_id: self.grid_id.clone(), @@ -615,7 +615,7 @@ impl GridRevisionEditor { .get_field_rev(field_id) .map(|(index, field)| (index, field.clone())) { - let updated_field = FieldPB::from(field_rev); + let updated_field = GridFieldPB::from(field_rev); let notified_changeset = GridFieldChangesetPB::update(&self.grid_id, vec![updated_field.clone()]); let _ = self.notify_did_update_grid(notified_changeset).await?; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 318910f217..33548f97c5 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -2,7 +2,7 @@ use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow}; use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; -use flowy_grid::entities::{CellIdentifier, FieldType, GridRowPB}; +use flowy_grid::entities::{CellIdentifierParams, FieldType, GridRowPB}; use flowy_grid::services::field::*; use flowy_grid_data_model::revision::{ GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, @@ -109,7 +109,7 @@ impl GridRowTest { field_type, expected, } => { - let id = CellIdentifier { + let id = CellIdentifierParams { grid_id: self.grid_id.clone(), field_id, row_id, @@ -154,7 +154,7 @@ impl GridRowTest { } } - async fn compare_cell_content(&self, cell_id: CellIdentifier, field_type: FieldType, expected: String) { + async fn compare_cell_content(&self, cell_id: CellIdentifierParams, field_type: FieldType, expected: String) { match field_type { FieldType::RichText => { let cell_data = self diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs index a6c88ef1c9..4def72696d 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs @@ -1,8 +1,8 @@ use crate::grid::grid_editor::GridEditorTest; -use flowy_grid::entities::CellChangeset; +use flowy_grid::entities::CellChangesetPB; pub enum CellScript { - UpdateCell { changeset: CellChangeset, is_err: bool }, + UpdateCell { changeset: CellChangesetPB, is_err: bool }, } pub struct GridCellTest { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs index 2334c89f9a..e8435c2d00 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/cell_test/test.rs @@ -1,7 +1,7 @@ use crate::grid::cell_test::script::CellScript::*; use crate::grid::cell_test::script::GridCellTest; use crate::grid::field_test::util::make_date_cell_string; -use flowy_grid::entities::{CellChangeset, FieldType}; +use flowy_grid::entities::{CellChangesetPB, FieldType}; use flowy_grid::services::field::selection_type_option::SelectOptionCellChangeset; use flowy_grid::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; @@ -36,7 +36,7 @@ async fn grid_cell_update() { }; scripts.push(UpdateCell { - changeset: CellChangeset { + changeset: CellChangesetPB { grid_id: block_id.to_string(), row_id: row_rev.id.clone(), field_id: field_rev.id.clone(), diff --git a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs index 95b6759950..01424cef74 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs @@ -17,7 +17,7 @@ pub fn create_text_field(grid_id: &str) -> (InsertFieldParams, FieldRevision) { .protobuf_bytes() .to_vec(); - let field = FieldPB { + let field = GridFieldPB { id: field_rev.id, name: field_rev.name, desc: field_rev.desc, @@ -50,7 +50,7 @@ pub fn create_single_select_field(grid_id: &str) -> (InsertFieldParams, FieldRev .protobuf_bytes() .to_vec(); - let field = FieldPB { + let field = GridFieldPB { id: field_rev.id, name: field_rev.name, desc: field_rev.desc, From 6fcc37e15ce80a73cda68ee3a1bfdff2ce6e7c38 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Sun, 17 Jul 2022 16:54:49 -0400 Subject: [PATCH 029/112] fix: Made githook scripts executable --- .githooks/pre-commit | 4 +++- .githooks/pre-push | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) mode change 100644 => 100755 .githooks/pre-commit mode change 100644 => 100755 .githooks/pre-push diff --git a/.githooks/pre-commit b/.githooks/pre-commit old mode 100644 new mode 100755 index d7617246c9..d27345fe71 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -1,5 +1,7 @@ #!/usr/bin/env bash +echo "Running local AppFlowy pre-commit hook." + #flutter format . ##https://gist.github.com/benmccallum/28e4f216d9d72f5965133e6c43aaff6e limit=$(( 1 * 2**20 )) # 1MB @@ -31,4 +33,4 @@ for file in $( git diff-index --cached --name-only $against ); do file_too_large $filename $file_size exit 1; fi -done \ No newline at end of file +done diff --git a/.githooks/pre-push b/.githooks/pre-push old mode 100644 new mode 100755 index 1636fb8661..ad7d19a16e --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -1,15 +1,20 @@ #!/usr/bin/env bash +echo "Running local AppFlowy pre-push hook." + if [[ `git status --porcelain` ]]; then printf "\e[31;1m%s\e[0m\n" 'This script needs to run against committed code only. Please commit or stash you changes.' exit 1 fi + printf "\e[33;1m%s\e[0m\n" 'Running the Flutter analyzer' flutter analyze + if [ $? -ne 0 ]; then printf "\e[31;1m%s\e[0m\n" 'Flutter analyzer error' exit 1 fi + printf "\e[33;1m%s\e[0m\n" 'Finished running the Flutter analyzer' printf "\e[33;1m%s\e[0m\n" 'Running unit tests' From ff0c6a9d98be7d59dc4589ba3ff0bcf1238025bd Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Sun, 17 Jul 2022 20:16:12 -0400 Subject: [PATCH 030/112] feat: Added commit-msg hook This will call commitlint to validate commit messages --- .githooks/commit-msg | 26 ++++++++++++++++++++++++++ package.json | 4 ++-- 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100755 .githooks/commit-msg diff --git a/.githooks/commit-msg b/.githooks/commit-msg new file mode 100755 index 0000000000..24cd55c6b6 --- /dev/null +++ b/.githooks/commit-msg @@ -0,0 +1,26 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. + +echo "Running the AppFlowy commit-msg hook." + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} + +npx --no -- commitlint --edit $1 + +if [ $? -ne 0 ] +then + echo "Please fix your commit message to match AppFlowy coding standards" + exit 1 +fi + diff --git a/package.json b/package.json index c891bb7d81..0f3afaccbc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "devDependencies": { - "@commitlint/cli": "16.1.0", - "@commitlint/config-conventional": "16.0.0", + "@commitlint/cli": "^16.1.0", + "@commitlint/config-conventional": "^16.0.0", "husky": "7.0.4" } } From 5035075e143b84e48924180bb0be076f4e34e9f2 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Sun, 17 Jul 2022 20:36:51 -0400 Subject: [PATCH 031/112] fix: removed references to Husky --- .husky/commit-msg | 4 ---- package.json | 3 +-- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100755 .husky/commit-msg diff --git a/.husky/commit-msg b/.husky/commit-msg deleted file mode 100755 index 7fed48507b..0000000000 --- a/.husky/commit-msg +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -npx --no -- commitlint --edit diff --git a/package.json b/package.json index 0f3afaccbc..0f6a7fcafe 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "devDependencies": { "@commitlint/cli": "^16.1.0", - "@commitlint/config-conventional": "^16.0.0", - "husky": "7.0.4" + "@commitlint/config-conventional": "^16.0.0" } } From 67f88fab0b3458209fa6ee2398fbea29396c03da Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 18 Jul 2022 11:58:39 +0800 Subject: [PATCH 032/112] refactor: add PB suffix to flowy-editor crate's structs --- .../application/doc/doc_service.dart | 8 +++--- .../workspace/application/doc/share_bloc.dart | 4 +-- .../application/doc/share_service.dart | 10 +++---- .../presentation/plugins/doc/document.dart | 2 +- .../src/services/view/controller.rs | 4 +-- .../flowy-folder/tests/workspace/script.rs | 6 ++-- .../flowy-net/src/http_server/document.rs | 8 +++--- .../flowy-net/src/local_server/persistence.rs | 6 ++-- .../flowy-net/src/local_server/server.rs | 6 ++-- .../rust-lib/flowy-text-block/src/editor.rs | 6 ++-- .../rust-lib/flowy-text-block/src/entities.rs | 6 ++-- .../flowy-text-block/src/event_handler.rs | 22 +++++++-------- .../flowy-text-block/src/event_map.rs | 6 ++-- frontend/rust-lib/flowy-text-block/src/lib.rs | 4 +-- .../rust-lib/flowy-text-block/src/manager.rs | 8 +++--- .../flowy-sync/src/entities/text_block.rs | 28 +++++++++---------- .../src/server_document/document_manager.rs | 13 +++++---- shared-lib/flowy-sync/src/util.rs | 15 ++++------ 18 files changed, 81 insertions(+), 81 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart b/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart index 992dfdeb63..7cf6d4412a 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart @@ -6,17 +6,17 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-sync/text_block.pb.dart'; class DocumentService { - Future> openDocument({ + Future> openDocument({ required String docId, }) async { await FolderEventSetLatestView(ViewId(value: docId)).send(); - final payload = TextBlockId(value: docId); + final payload = TextBlockIdPB(value: docId); return TextBlockEventGetBlockData(payload).send(); } - Future> composeDelta({required String docId, required String data}) { - final payload = TextBlockDelta.create() + Future> composeDelta({required String docId, required String data}) { + final payload = TextBlockDeltaPB.create() ..blockId = docId ..deltaStr = data; return TextBlockEventApplyDelta(payload).send(); diff --git a/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart b/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart index 90c041eb75..a940846f5a 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart @@ -33,7 +33,7 @@ class DocShareBloc extends Bloc { }); } - ExportData _convertDeltaToMarkdown(ExportData value) { + ExportDataPB _convertDeltaToMarkdown(ExportDataPB value) { final result = deltaToMarkdown(value.data); value.data = result; writeFile(result); @@ -73,5 +73,5 @@ class DocShareEvent with _$DocShareEvent { class DocShareState with _$DocShareState { const factory DocShareState.initial() = _Initial; const factory DocShareState.loading() = _Loading; - const factory DocShareState.finish(Either successOrFail) = _Finish; + const factory DocShareState.finish(Either successOrFail) = _Finish; } diff --git a/frontend/app_flowy/lib/workspace/application/doc/share_service.dart b/frontend/app_flowy/lib/workspace/application/doc/share_service.dart index 7e5545f109..db6ad406b7 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/share_service.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/share_service.dart @@ -5,23 +5,23 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-text-block/protobuf.dart'; class ShareService { - Future> export(String docId, ExportType type) { - final request = ExportPayload.create() + Future> export(String docId, ExportType type) { + final request = ExportPayloadPB.create() ..viewId = docId ..exportType = type; return TextBlockEventExportDocument(request).send(); } - Future> exportText(String docId) { + Future> exportText(String docId) { return export(docId, ExportType.Text); } - Future> exportMarkdown(String docId) { + Future> exportMarkdown(String docId) { return export(docId, ExportType.Markdown); } - Future> exportURL(String docId) { + Future> exportURL(String docId) { return export(docId, ExportType.Link); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart index 0759894844..f5376f52fc 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart @@ -160,7 +160,7 @@ class DocumentShareButton extends StatelessWidget { ); } - void _handleExportData(ExportData exportData) { + void _handleExportData(ExportDataPB exportData) { switch (exportData.exportType) { case ExportType.Link: break; diff --git a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs index d573b096f6..0df71c320f 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs @@ -17,7 +17,7 @@ use crate::{ use bytes::Bytes; use flowy_database::kv::KV; use flowy_folder_data_model::revision::{gen_view_id, ViewRevision}; -use flowy_sync::entities::text_block::TextBlockId; +use flowy_sync::entities::text_block::TextBlockIdPB; use futures::{FutureExt, StreamExt}; use std::{collections::HashSet, sync::Arc}; @@ -177,7 +177,7 @@ impl ViewController { } #[tracing::instrument(level = "debug", skip(self,params), fields(doc_id = %params.value), err)] - pub(crate) async fn delete_view(&self, params: TextBlockId) -> Result<(), FlowyError> { + pub(crate) async fn delete_view(&self, params: TextBlockIdPB) -> Result<(), FlowyError> { if let Some(view_id) = KV::get_str(LATEST_VIEW_ID) { if view_id == params.value { let _ = KV::remove(LATEST_VIEW_ID); diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs index b461730cf9..7b6091b7b5 100644 --- a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs +++ b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs @@ -17,7 +17,7 @@ use flowy_folder::{errors::ErrorCode, services::folder_editor::FolderEditor}; use flowy_revision::disk::RevisionState; use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; -use flowy_sync::entities::text_block::TextBlockInfo; +use flowy_sync::entities::text_block::TextBlockInfoPB; use flowy_test::{event_builder::*, FlowySDKTest}; use std::{sync::Arc, time::Duration}; use tokio::time::sleep; @@ -399,14 +399,14 @@ pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec) { } #[allow(dead_code)] -pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> TextBlockInfo { +pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> TextBlockInfoPB { let view_id: ViewId = view_id.into(); FolderEventBuilder::new(sdk.clone()) .event(SetLatestView) .payload(view_id) .async_send() .await - .parse::() + .parse::() } pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrash { diff --git a/frontend/rust-lib/flowy-net/src/http_server/document.rs b/frontend/rust-lib/flowy-net/src/http_server/document.rs index fe9f31f2ca..c8d18b07b2 100644 --- a/frontend/rust-lib/flowy-net/src/http_server/document.rs +++ b/frontend/rust-lib/flowy-net/src/http_server/document.rs @@ -3,7 +3,7 @@ use crate::{ request::{HttpRequestBuilder, ResponseMiddleware}, }; use flowy_error::FlowyError; -use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}; +use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockIdPB, TextBlockInfoPB}; use flowy_text_block::BlockCloudService; use http_flowy::response::FlowyResponse; use lazy_static::lazy_static; @@ -27,7 +27,7 @@ impl BlockCloudService for BlockHttpCloudService { FutureResult::new(async move { create_document_request(&token, params, &url).await }) } - fn read_block(&self, token: &str, params: TextBlockId) -> FutureResult, FlowyError> { + fn read_block(&self, token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError> { let token = token.to_owned(); let url = self.config.doc_url(); FutureResult::new(async move { read_document_request(&token, params, &url).await }) @@ -52,9 +52,9 @@ pub async fn create_document_request(token: &str, params: CreateTextBlockParams, pub async fn read_document_request( token: &str, - params: TextBlockId, + params: TextBlockIdPB, url: &str, -) -> Result, FlowyError> { +) -> Result, FlowyError> { let doc = request_builder() .get(&url.to_owned()) .header(HEADER_TOKEN, token) diff --git a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs index 28151af2f4..d8bae35401 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs @@ -1,5 +1,5 @@ use flowy_sync::{ - entities::{folder::FolderInfo, text_block::TextBlockInfo}, + entities::{folder::FolderInfo, text_block::TextBlockInfoPB}, errors::CollaborateError, protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::*, @@ -111,7 +111,7 @@ impl FolderCloudPersistence for LocalTextBlockCloudPersistence { } impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { - fn read_text_block(&self, doc_id: &str) -> BoxResultFuture { + fn read_text_block(&self, doc_id: &str) -> BoxResultFuture { let storage = self.storage.clone(); let doc_id = doc_id.to_owned(); Box::pin(async move { @@ -127,7 +127,7 @@ impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { &self, doc_id: &str, repeated_revision: RepeatedRevisionPB, - ) -> BoxResultFuture, CollaborateError> { + ) -> BoxResultFuture, CollaborateError> { let doc_id = doc_id.to_owned(); let storage = self.storage.clone(); Box::pin(async move { diff --git a/frontend/rust-lib/flowy-net/src/local_server/server.rs b/frontend/rust-lib/flowy-net/src/local_server/server.rs index cdec4d0c48..66a7682584 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/server.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/server.rs @@ -6,7 +6,7 @@ use flowy_folder::event_map::FolderCouldServiceV1; use flowy_sync::{ client_document::default::initial_quill_delta_string, entities::{ - text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}, + text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockIdPB, TextBlockInfoPB}, ws_data::{ClientRevisionWSData, ClientRevisionWSDataType}, }, errors::CollaborateError, @@ -419,8 +419,8 @@ impl BlockCloudService for LocalServer { FutureResult::new(async { Ok(()) }) } - fn read_block(&self, _token: &str, params: TextBlockId) -> FutureResult, FlowyError> { - let doc = TextBlockInfo { + fn read_block(&self, _token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError> { + let doc = TextBlockInfoPB { block_id: params.value, text: initial_quill_delta_string(), rev_id: 0, diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 111808109d..84b30a0047 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -9,7 +9,7 @@ use flowy_error::{internal_error, FlowyResult}; use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket}; use flowy_sync::entities::ws_data::ServerRevisionWSData; use flowy_sync::{ - entities::{revision::Revision, text_block::TextBlockInfo}, + entities::{revision::Revision, text_block::TextBlockInfoPB}, errors::CollaborateResult, util::make_delta_from_revisions, }; @@ -229,14 +229,14 @@ impl TextBlockEditor { struct TextBlockInfoBuilder(); impl RevisionObjectBuilder for TextBlockInfoBuilder { - type Output = TextBlockInfo; + type Output = TextBlockInfoPB; fn build_object(object_id: &str, revisions: Vec) -> FlowyResult { let (base_rev_id, rev_id) = revisions.last().unwrap().pair_rev_id(); let mut delta = make_delta_from_revisions(revisions)?; correct_delta(&mut delta); - Result::::Ok(TextBlockInfo { + Result::::Ok(TextBlockInfoPB { block_id: object_id.to_owned(), text: delta.to_delta_str(), rev_id, diff --git a/frontend/rust-lib/flowy-text-block/src/entities.rs b/frontend/rust-lib/flowy-text-block/src/entities.rs index 61dade5113..ec8767285b 100644 --- a/frontend/rust-lib/flowy-text-block/src/entities.rs +++ b/frontend/rust-lib/flowy-text-block/src/entities.rs @@ -30,7 +30,7 @@ impl std::convert::From for ExportType { } #[derive(Default, ProtoBuf)] -pub struct ExportPayload { +pub struct ExportPayloadPB { #[pb(index = 1)] pub view_id: String, @@ -44,7 +44,7 @@ pub struct ExportParams { pub export_type: ExportType, } -impl TryInto for ExportPayload { +impl TryInto for ExportPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { Ok(ExportParams { @@ -55,7 +55,7 @@ impl TryInto for ExportPayload { } #[derive(Default, ProtoBuf)] -pub struct ExportData { +pub struct ExportDataPB { #[pb(index = 1)] pub data: String, diff --git a/frontend/rust-lib/flowy-text-block/src/event_handler.rs b/frontend/rust-lib/flowy-text-block/src/event_handler.rs index 0934d20a29..dc9812d862 100644 --- a/frontend/rust-lib/flowy-text-block/src/event_handler.rs +++ b/frontend/rust-lib/flowy-text-block/src/event_handler.rs @@ -1,41 +1,41 @@ -use crate::entities::{ExportData, ExportParams, ExportPayload}; +use crate::entities::{ExportDataPB, ExportParams, ExportPayloadPB}; use crate::TextBlockManager; use flowy_error::FlowyError; -use flowy_sync::entities::text_block::{TextBlockDelta, TextBlockId}; +use flowy_sync::entities::text_block::{TextBlockDeltaPB, TextBlockIdPB}; use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::convert::TryInto; use std::sync::Arc; pub(crate) async fn get_block_data_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { - let block_id: TextBlockId = data.into_inner(); +) -> DataResult { + let block_id: TextBlockIdPB = data.into_inner(); let editor = manager.open_block(&block_id).await?; let delta_str = editor.delta_str().await?; - data_result(TextBlockDelta { + data_result(TextBlockDeltaPB { block_id: block_id.into(), delta_str, }) } pub(crate) async fn apply_delta_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let block_delta = manager.receive_local_delta(data.into_inner()).await?; data_result(block_delta) } #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn export_handler( - data: Data, + data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: ExportParams = data.into_inner().try_into()?; let editor = manager.open_block(¶ms.view_id).await?; let delta_json = editor.delta_str().await?; - data_result(ExportData { + data_result(ExportDataPB { data: delta_json, export_type: params.export_type, }) diff --git a/frontend/rust-lib/flowy-text-block/src/event_map.rs b/frontend/rust-lib/flowy-text-block/src/event_map.rs index f995fd282b..cfc06bf32c 100644 --- a/frontend/rust-lib/flowy-text-block/src/event_map.rs +++ b/frontend/rust-lib/flowy-text-block/src/event_map.rs @@ -19,12 +19,12 @@ pub fn create(block_manager: Arc) -> Module { #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] #[event_err = "FlowyError"] pub enum TextBlockEvent { - #[event(input = "TextBlockId", output = "TextBlockDelta")] + #[event(input = "TextBlockIdPB", output = "TextBlockDeltaPB")] GetBlockData = 0, - #[event(input = "TextBlockDelta", output = "TextBlockDelta")] + #[event(input = "TextBlockDeltaPB", output = "TextBlockDeltaPB")] ApplyDelta = 1, - #[event(input = "ExportPayload", output = "ExportData")] + #[event(input = "ExportPayloadPB", output = "ExportDataPB")] ExportDocument = 2, } diff --git a/frontend/rust-lib/flowy-text-block/src/lib.rs b/frontend/rust-lib/flowy-text-block/src/lib.rs index f470739d85..808bc2d6f9 100644 --- a/frontend/rust-lib/flowy-text-block/src/lib.rs +++ b/frontend/rust-lib/flowy-text-block/src/lib.rs @@ -15,13 +15,13 @@ pub mod errors { pub const TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS: u64 = 1000; use crate::errors::FlowyError; -use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockId, TextBlockInfo}; +use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockIdPB, TextBlockInfoPB}; use lib_infra::future::FutureResult; pub trait BlockCloudService: Send + Sync { fn create_block(&self, token: &str, params: CreateTextBlockParams) -> FutureResult<(), FlowyError>; - fn read_block(&self, token: &str, params: TextBlockId) -> FutureResult, FlowyError>; + fn read_block(&self, token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError>; fn update_block(&self, token: &str, params: ResetTextBlockParams) -> FutureResult<(), FlowyError>; } diff --git a/frontend/rust-lib/flowy-text-block/src/manager.rs b/frontend/rust-lib/flowy-text-block/src/manager.rs index ead24857be..4ccf015a7f 100644 --- a/frontend/rust-lib/flowy-text-block/src/manager.rs +++ b/frontend/rust-lib/flowy-text-block/src/manager.rs @@ -7,7 +7,7 @@ use flowy_revision::disk::SQLiteTextBlockRevisionPersistence; use flowy_revision::{RevisionCloudService, RevisionManager, RevisionPersistence, RevisionWebSocket}; use flowy_sync::entities::{ revision::{md5, RepeatedRevision, Revision}, - text_block::{TextBlockDelta, TextBlockId}, + text_block::{TextBlockDeltaPB, TextBlockIdPB}, ws_data::ServerRevisionWSData, }; use lib_infra::future::FutureResult; @@ -71,11 +71,11 @@ impl TextBlockManager { } #[tracing::instrument(level = "debug", skip(self, delta), fields(doc_id = %delta.block_id), err)] - pub async fn receive_local_delta(&self, delta: TextBlockDelta) -> Result { + pub async fn receive_local_delta(&self, delta: TextBlockDeltaPB) -> Result { let editor = self.get_block_editor(&delta.block_id).await?; let _ = editor.compose_local_delta(Bytes::from(delta.delta_str)).await?; let document_json = editor.delta_str().await?; - Ok(TextBlockDelta { + Ok(TextBlockDeltaPB { block_id: delta.block_id.clone(), delta_str: document_json, }) @@ -153,7 +153,7 @@ struct TextBlockRevisionCloudService { impl RevisionCloudService for TextBlockRevisionCloudService { #[tracing::instrument(level = "trace", skip(self))] fn fetch_object(&self, user_id: &str, object_id: &str) -> FutureResult, FlowyError> { - let params: TextBlockId = object_id.to_string().into(); + let params: TextBlockIdPB = object_id.to_string().into(); let server = self.server.clone(); let token = self.token.clone(); let user_id = user_id.to_string(); diff --git a/shared-lib/flowy-sync/src/entities/text_block.rs b/shared-lib/flowy-sync/src/entities/text_block.rs index c325fdad07..cef3cd30f7 100644 --- a/shared-lib/flowy-sync/src/entities/text_block.rs +++ b/shared-lib/flowy-sync/src/entities/text_block.rs @@ -15,7 +15,7 @@ pub struct CreateTextBlockParams { } #[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)] -pub struct TextBlockInfo { +pub struct TextBlockInfoPB { #[pb(index = 1)] pub block_id: String, @@ -29,14 +29,14 @@ pub struct TextBlockInfo { pub base_rev_id: i64, } -impl TextBlockInfo { +impl TextBlockInfoPB { pub fn delta(&self) -> Result { let delta = RichTextDelta::from_bytes(&self.text)?; Ok(delta) } } -impl std::convert::TryFrom for TextBlockInfo { +impl std::convert::TryFrom for TextBlockInfoPB { type Error = CollaborateError; fn try_from(revision: Revision) -> Result { @@ -48,7 +48,7 @@ impl std::convert::TryFrom for TextBlockInfo { let delta = RichTextDelta::from_bytes(&revision.delta_data)?; let doc_json = delta.to_delta_str(); - Ok(TextBlockInfo { + Ok(TextBlockInfoPB { block_id: revision.object_id, text: doc_json, rev_id: revision.rev_id, @@ -67,7 +67,7 @@ pub struct ResetTextBlockParams { } #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct TextBlockDelta { +pub struct TextBlockDeltaPB { #[pb(index = 1)] pub block_id: String, @@ -76,7 +76,7 @@ pub struct TextBlockDelta { } #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct NewDocUser { +pub struct NewDocUserPB { #[pb(index = 1)] pub user_id: String, @@ -88,30 +88,30 @@ pub struct NewDocUser { } #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct TextBlockId { +pub struct TextBlockIdPB { #[pb(index = 1)] pub value: String, } -impl AsRef for TextBlockId { +impl AsRef for TextBlockIdPB { fn as_ref(&self) -> &str { &self.value } } -impl std::convert::From for TextBlockId { +impl std::convert::From for TextBlockIdPB { fn from(value: String) -> Self { - TextBlockId { value } + TextBlockIdPB { value } } } -impl std::convert::From for String { - fn from(block_id: TextBlockId) -> Self { +impl std::convert::From for String { + fn from(block_id: TextBlockIdPB) -> Self { block_id.value } } -impl std::convert::From<&String> for TextBlockId { +impl std::convert::From<&String> for TextBlockIdPB { fn from(s: &String) -> Self { - TextBlockId { value: s.to_owned() } + TextBlockIdPB { value: s.to_owned() } } } diff --git a/shared-lib/flowy-sync/src/server_document/document_manager.rs b/shared-lib/flowy-sync/src/server_document/document_manager.rs index 8d547a9484..8aed39e993 100644 --- a/shared-lib/flowy-sync/src/server_document/document_manager.rs +++ b/shared-lib/flowy-sync/src/server_document/document_manager.rs @@ -1,5 +1,5 @@ use crate::{ - entities::{text_block::TextBlockInfo, ws_data::ServerRevisionWSDataBuilder}, + entities::{text_block::TextBlockInfoPB, ws_data::ServerRevisionWSDataBuilder}, errors::{internal_error, CollaborateError, CollaborateResult}, protobuf::{ClientRevisionWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::document_pad::ServerDocument, @@ -18,13 +18,13 @@ use tokio::{ }; pub trait TextBlockCloudPersistence: Send + Sync + Debug { - fn read_text_block(&self, doc_id: &str) -> BoxResultFuture; + fn read_text_block(&self, doc_id: &str) -> BoxResultFuture; fn create_text_block( &self, doc_id: &str, repeated_revision: RepeatedRevisionPB, - ) -> BoxResultFuture, CollaborateError>; + ) -> BoxResultFuture, CollaborateError>; fn read_text_block_revisions( &self, @@ -182,7 +182,10 @@ impl ServerDocumentManager { } #[tracing::instrument(level = "debug", skip(self, doc), err)] - async fn create_document_handler(&self, doc: TextBlockInfo) -> Result, CollaborateError> { + async fn create_document_handler( + &self, + doc: TextBlockInfoPB, + ) -> Result, CollaborateError> { let persistence = self.persistence.clone(); let handle = spawn_blocking(|| OpenDocumentHandler::new(doc, persistence)) .await @@ -206,7 +209,7 @@ struct OpenDocumentHandler { } impl OpenDocumentHandler { - fn new(doc: TextBlockInfo, persistence: Arc) -> Result { + fn new(doc: TextBlockInfoPB, persistence: Arc) -> Result { let doc_id = doc.block_id.clone(); let (sender, receiver) = mpsc::channel(1000); let users = DashMap::new(); diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index 3fc09c5932..824f1f945b 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -2,13 +2,10 @@ use crate::{ entities::{ folder::{FolderDelta, FolderInfo}, revision::{RepeatedRevision, Revision}, - text_block::TextBlockInfo, + text_block::TextBlockInfoPB, }, errors::{CollaborateError, CollaborateResult}, - protobuf::{ - FolderInfo as FolderInfoPB, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB, - TextBlockInfo as TextBlockInfoPB, - }, + protobuf::{FolderInfo as FolderInfoPB, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, }; use dissimilar::Chunk; use lib_ot::core::{DeltaBuilder, FlowyStr}; @@ -202,11 +199,11 @@ pub fn make_folder_pb_from_revisions_pb( pub fn make_document_info_from_revisions_pb( doc_id: &str, revisions: RepeatedRevisionPB, -) -> Result, CollaborateError> { +) -> Result, CollaborateError> { match make_document_info_pb_from_revisions_pb(doc_id, revisions)? { None => Ok(None), Some(pb) => { - let document_info: TextBlockInfo = pb.try_into().map_err(|e| { + let document_info: TextBlockInfoPB = pb.try_into().map_err(|e| { CollaborateError::internal().context(format!("Deserialize document info from pb failed: {}", e)) })?; Ok(Some(document_info)) @@ -218,7 +215,7 @@ pub fn make_document_info_from_revisions_pb( pub fn make_document_info_pb_from_revisions_pb( doc_id: &str, mut revisions: RepeatedRevisionPB, -) -> Result, CollaborateError> { +) -> Result, CollaborateError> { let revisions = revisions.take_items(); if revisions.is_empty() { return Ok(None); @@ -240,7 +237,7 @@ pub fn make_document_info_pb_from_revisions_pb( } let text = document_delta.to_delta_str(); - let mut block_info = TextBlockInfoPB::new(); + let mut block_info = crate::protobuf::TextBlockInfoPB::new(); block_info.set_block_id(doc_id.to_owned()); block_info.set_text(text); block_info.set_base_rev_id(base_rev_id); From cefd64034db40ea544381eb51b9a430380f89d94 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 18 Jul 2022 17:48:33 +0800 Subject: [PATCH 033/112] refactor: add Grid prefix to some Grid cells --- .../grid/src/widgets/cell/cell_builder.dart | 10 +++++----- .../grid/src/widgets/cell/checkbox_cell.dart | 8 ++++---- .../src/widgets/cell/date_cell/date_cell.dart | 8 ++++---- .../grid/src/widgets/cell/number_cell.dart | 8 ++++---- .../select_option_cell/select_option_cell.dart | 16 ++++++++-------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index 10efcbb0de..f785672f71 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -30,15 +30,15 @@ class GridCellBuilder { final key = cell.key(); switch (cell.fieldType) { case FieldType.Checkbox: - return CheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key); + return GridCheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key); case FieldType.DateTime: - return DateCell(cellControllerBuilder: cellControllerBuilder, key: key, style: style); + return GridDateCell(cellControllerBuilder: cellControllerBuilder, key: key, style: style); case FieldType.SingleSelect: - return SingleSelectCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); + return GridSingleSelectCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); case FieldType.MultiSelect: - return MultiSelectCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); + return GridMultiSelectCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); case FieldType.Number: - return NumberCell(cellContorllerBuilder: cellControllerBuilder, key: key); + return GridNumberCell(cellContorllerBuilder: cellControllerBuilder, key: key); case FieldType.RichText: return GridTextCell(cellContorllerBuilder: cellControllerBuilder, style: style, key: key); case FieldType.URL: diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart index ac2a2fb979..9fcbaf751f 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart @@ -6,18 +6,18 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_builder.dart'; -class CheckboxCell extends GridCellWidget { +class GridCheckboxCell extends GridCellWidget { final GridCellControllerBuilder cellControllerBuilder; - CheckboxCell({ + GridCheckboxCell({ required this.cellControllerBuilder, Key? key, }) : super(key: key); @override - GridCellState createState() => _CheckboxCellState(); + GridCellState createState() => _CheckboxCellState(); } -class _CheckboxCellState extends GridCellState { +class _CheckboxCellState extends GridCellState { late CheckboxCellBloc _cellBloc; @override diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart index 7436d0ac7f..78d18a50e8 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart @@ -18,11 +18,11 @@ abstract class GridCellDelegate { GridCellDelegate get delegate; } -class DateCell extends GridCellWidget { +class GridDateCell extends GridCellWidget { final GridCellControllerBuilder cellControllerBuilder; late final DateCellStyle? cellStyle; - DateCell({ + GridDateCell({ GridCellStyle? style, required this.cellControllerBuilder, Key? key, @@ -35,10 +35,10 @@ class DateCell extends GridCellWidget { } @override - GridCellState createState() => _DateCellState(); + GridCellState createState() => _DateCellState(); } -class _DateCellState extends GridCellState { +class _DateCellState extends GridCellState { late DateCellBloc _cellBloc; @override diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart index 6b1cf4ceae..573a4168c9 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart @@ -6,19 +6,19 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_builder.dart'; -class NumberCell extends GridCellWidget { +class GridNumberCell extends GridCellWidget { final GridCellControllerBuilder cellContorllerBuilder; - NumberCell({ + GridNumberCell({ required this.cellContorllerBuilder, Key? key, }) : super(key: key); @override - GridFocusNodeCellState createState() => _NumberCellState(); + GridFocusNodeCellState createState() => _NumberCellState(); } -class _NumberCellState extends GridFocusNodeCellState { +class _NumberCellState extends GridFocusNodeCellState { late NumberCellBloc _cellBloc; late TextEditingController _controller; Timer? _delayOperation; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart index 6669e84576..f822e503d2 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/select_option_cell/select_option_cell.dart @@ -20,11 +20,11 @@ class SelectOptionCellStyle extends GridCellStyle { }); } -class SingleSelectCell extends GridCellWidget { +class GridSingleSelectCell extends GridCellWidget { final GridCellControllerBuilder cellContorllerBuilder; late final SelectOptionCellStyle? cellStyle; - SingleSelectCell({ + GridSingleSelectCell({ required this.cellContorllerBuilder, GridCellStyle? style, Key? key, @@ -37,10 +37,10 @@ class SingleSelectCell extends GridCellWidget { } @override - State createState() => _SingleSelectCellState(); + State createState() => _SingleSelectCellState(); } -class _SingleSelectCellState extends State { +class _SingleSelectCellState extends State { late SelectOptionCellBloc _cellBloc; @override @@ -74,11 +74,11 @@ class _SingleSelectCellState extends State { } //---------------------------------------------------------------- -class MultiSelectCell extends GridCellWidget { +class GridMultiSelectCell extends GridCellWidget { final GridCellControllerBuilder cellContorllerBuilder; late final SelectOptionCellStyle? cellStyle; - MultiSelectCell({ + GridMultiSelectCell({ required this.cellContorllerBuilder, GridCellStyle? style, Key? key, @@ -91,10 +91,10 @@ class MultiSelectCell extends GridCellWidget { } @override - State createState() => _MultiSelectCellState(); + State createState() => _MultiSelectCellState(); } -class _MultiSelectCellState extends State { +class _MultiSelectCellState extends State { late SelectOptionCellBloc _cellBloc; @override From 8683c2f343eb109cbd18b6e5accc90d2c499f6f6 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 18 Jul 2022 19:15:40 +0800 Subject: [PATCH 034/112] fix: reload number cell --- .../grid/cell/cell_service/cell_data_loader.dart | 12 ++++++------ .../grid/cell/cell_service/context_builder.dart | 13 +++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart index b779d227b1..c4b3430199 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_loader.dart @@ -5,14 +5,14 @@ abstract class IGridCellDataConfig { bool get reloadOnFieldChanged; } -abstract class ICellDataParser { +abstract class IGridCellDataParser { T? parserData(List data); } class GridCellDataLoader { final CellService service = CellService(); final GridCellIdentifier cellId; - final ICellDataParser parser; + final IGridCellDataParser parser; final bool reloadOnFieldChanged; GridCellDataLoader({ @@ -40,7 +40,7 @@ class GridCellDataLoader { } } -class StringCellDataParser implements ICellDataParser { +class StringCellDataParser implements IGridCellDataParser { @override String? parserData(List data) { final s = utf8.decode(data); @@ -48,7 +48,7 @@ class StringCellDataParser implements ICellDataParser { } } -class DateCellDataParser implements ICellDataParser { +class DateCellDataParser implements IGridCellDataParser { @override DateCellDataPB? parserData(List data) { if (data.isEmpty) { @@ -58,7 +58,7 @@ class DateCellDataParser implements ICellDataParser { } } -class SelectOptionCellDataParser implements ICellDataParser { +class SelectOptionCellDataParser implements IGridCellDataParser { @override SelectOptionCellDataPB? parserData(List data) { if (data.isEmpty) { @@ -68,7 +68,7 @@ class SelectOptionCellDataParser implements ICellDataParser { +class URLCellDataParser implements IGridCellDataParser { @override URLCellDataPB? parserData(List data) { if (data.isEmpty) { 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 8e51e33f29..48e88e56ac 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 @@ -52,6 +52,7 @@ class GridCellControllerBuilder { final cellDataLoader = GridCellDataLoader( cellId: _cellId, parser: StringCellDataParser(), + reloadOnFieldChanged: true, ); return GridCellController( cellId: _cellId, @@ -170,16 +171,13 @@ class IGridCellController extends Equatable { } isListening = true; - /// The cell data will be changed by two reasons: - /// 1. User edit the cell - /// 2. User edit the field - /// For example: The number cell reload the cell data that carries the format - /// user input: 12 - /// cell display: $12 _cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey)); _cellListener = CellListener(rowId: cellId.rowId, fieldId: cellId.field.id); /// 1.Listen on user edit event and load the new cell data if needed. + /// For example: + /// user input: 12 + /// cell display: $12 _cellListener.start(onCellChanged: (result) { result.fold( (_) => _loadData(), @@ -193,6 +191,9 @@ class IGridCellController extends Equatable { onCellFieldChanged(); } + /// reloadOnFieldChanged should be true if you need to load the data when the corresponding field is changed + /// For example: + /// ¥12 -> $12 if (_cellDataLoader.reloadOnFieldChanged) { _loadData(); } From 39900022db9fb05e11d2e394f778c772d4067a85 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 18 Jul 2022 14:31:13 -0400 Subject: [PATCH 035/112] fix: improved development environment installation moved and renamed /Makefile.toml to githooks.toml added install script for Linux --- Makefile.toml | 35 ------------- frontend/Makefile.toml | 1 + .../scripts/install_dev_env/install_linux.sh | 50 +++++++++++++++++++ frontend/scripts/makefile/githooks.toml | 39 +++++++++++++++ 4 files changed, 90 insertions(+), 35 deletions(-) delete mode 100644 Makefile.toml create mode 100755 frontend/scripts/install_dev_env/install_linux.sh create mode 100644 frontend/scripts/makefile/githooks.toml diff --git a/Makefile.toml b/Makefile.toml deleted file mode 100644 index 2e75c10277..0000000000 --- a/Makefile.toml +++ /dev/null @@ -1,35 +0,0 @@ -[tasks.install-commitlint.mac] -script = [ - """ - brew install npm - yarn install - yarn husky install - """, -] -script_runner = "@shell" - -[tasks.install-commitlint.windows] -script = [ - """ - echo "WIP" - """, -] -script_runner = "@duckscript" - -[tasks.install-commitlint.linux] -script = [ - """ - if command -v apt &> /dev/null - then - echo "Installing node.js and yarn (sudo apt install nodejs yarn)" - sudo apt install nodejs yarn - else - echo "Installing node.js and yarn (sudo pacman -S nodejs yarn)" - sudo pacman -S nodejs yarn - fi - - yarn install - yarn husky install - """, -] -script_runner = "@shell" diff --git a/frontend/Makefile.toml b/frontend/Makefile.toml index 337b9efd76..7449bfeef3 100644 --- a/frontend/Makefile.toml +++ b/frontend/Makefile.toml @@ -8,6 +8,7 @@ extend = [ { path = "scripts/makefile/env.toml" }, { path = "scripts/makefile/flutter.toml" }, { path = "scripts/makefile/tool.toml" }, + { path = "scripts/makefile/githooks.toml" }, ] [config] diff --git a/frontend/scripts/install_dev_env/install_linux.sh b/frontend/scripts/install_dev_env/install_linux.sh new file mode 100755 index 0000000000..1d8e7f810d --- /dev/null +++ b/frontend/scripts/install_dev_env/install_linux.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +BLUE="\e[34m" +GREEN="\e[32m" +ENDCOLOR="\e[0m" + + +# Install rust on Linux +read -p 'Do you want to install Rust? [y/N] ' installrust + + +if [ ${installrust^^} == "Y" ]; then + echo -e "${BLUE}AppFlowy : Installing Rust.${ENDCOLOR}" + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + source $HOME/.cargo/env + rustup toolchain install stable + rustup default stable +else + echo -e "${BLUE}AppFlowy : Skipping Rust installation.${ENDCOLOR}" +fi + +# Enable the flutter stable channel +echo -e "${BLUE}AppFlowy : Checking Flutter installation.${ENDCOLOR}" +flutter channel stable + +# Enable linux desktop +flutter config --enable-linux-desktop + +# Fix any problems reported by flutter doctor +flutter doctor + +# Add the githooks directory to your git configuration +echo -e "${BLUE}AppFlowy : Setting up githooks.${ENDCOLOR}" +git config core.hooksPath .githooks + +# Change to the frontend directory +cd frontend + +# Install cargo make +echo -e "${BLUE}AppFlowy : Installing cargo-make.${ENDCOLOR}" +cargo install --force cargo-make + +# Install duckscript +echo -e "${BLUE}AppFlowy : Installing duckscript.${ENDCOLOR}" +cargo install --force duckscript_cli + +# Install CommitLint +echo -e "${BLUE}AppFlowy : Installing CommitLint.${ENDCOLOR}" +npm install @commitlint/cli @commitlint/config-conventional --save-dev + diff --git a/frontend/scripts/makefile/githooks.toml b/frontend/scripts/makefile/githooks.toml new file mode 100644 index 0000000000..f6b066ec49 --- /dev/null +++ b/frontend/scripts/makefile/githooks.toml @@ -0,0 +1,39 @@ +[tasks.install-commitlint.mac] +script = [ + """ + brew install npm + npm install @commitlint/cli @commitlint/config-conventional --save-dev + + git config core.hooksPath .githooks + """, +] +script_runner = "@shell" + +[tasks.install-commitlint.windows] +script = [ + """ + echo "WIP" + + git config core.hooksPath .githooks + """, +] +script_runner = "@duckscript" + +[tasks.install-commitlint.linux] +script = [ + """ + if command -v apt &> /dev/null + then + echo "Installing node.js (sudo apt install nodejs)" + sudo apt install nodejs + else + echo "Installing node.js (sudo pacman -S nodejs)" + sudo pacman -S nodejs + fi + + npm install @commitlint/cli @commitlint/config-conventional --save-dev + + git config core.hooksPath .githooks + """, +] +script_runner = "@shell" From 1cb8dbcfa4b8faf8009d29182b5b02bcb77f6ad0 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 18 Jul 2022 15:24:25 -0400 Subject: [PATCH 036/112] fix: improved installation on MacOs added MacOs install script Removed Makefile, since we now use a bash script. This removes the dependency on make. Removed Brewfile, since we now use a bash script --- frontend/Brewfile | 2 - frontend/Makefile | 14 ----- .../scripts/install_dev_env/install_linux.sh | 10 +++- .../scripts/install_dev_env/install_macos.sh | 56 +++++++++++++++++++ 4 files changed, 64 insertions(+), 18 deletions(-) delete mode 100644 frontend/Brewfile delete mode 100644 frontend/Makefile create mode 100755 frontend/scripts/install_dev_env/install_macos.sh diff --git a/frontend/Brewfile b/frontend/Brewfile deleted file mode 100644 index 470312025d..0000000000 --- a/frontend/Brewfile +++ /dev/null @@ -1,2 +0,0 @@ -brew 'sqlite3' -brew 'rustup-init' diff --git a/frontend/Makefile b/frontend/Makefile deleted file mode 100644 index c393bec0e0..0000000000 --- a/frontend/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -.PHONY: flowy_dev_install flowy_clean - -flowy_dev_install: - brew bundle - rustup-init -y --default-toolchain=stable - cargo install --force cargo-make - cargo install --force duckscript_cli - cargo make flowy_dev - - -flowy_clean: - sh ./scripts/clean.sh - - diff --git a/frontend/scripts/install_dev_env/install_linux.sh b/frontend/scripts/install_dev_env/install_linux.sh index 1d8e7f810d..0446655c02 100755 --- a/frontend/scripts/install_dev_env/install_linux.sh +++ b/frontend/scripts/install_dev_env/install_linux.sh @@ -1,13 +1,16 @@ #!/bin/bash BLUE="\e[34m" -GREEN="\e[32m" +RED="\e[31m" ENDCOLOR="\e[0m" +# Note: This script does not install applications which are installed by the package manager. There are too many package managers out there. # Install rust on Linux -read -p 'Do you want to install Rust? [y/N] ' installrust +echo -e "${BLUE}AppFlowy : The Rust programming language is required to compile AppFlowy.${ENDCOLOR}" +echo -e "${BLUE}AppFlowy : We can install it now if you don't already have it on your system.${ENDCOLOR}" +read -p "${BLUE}AppFlowy : Do you want to install Rust? [y/N]${ENDCOLOR} " installrust if [ ${installrust^^} == "Y" ]; then echo -e "${BLUE}AppFlowy : Installing Rust.${ENDCOLOR}" @@ -48,3 +51,6 @@ cargo install --force duckscript_cli echo -e "${BLUE}AppFlowy : Installing CommitLint.${ENDCOLOR}" npm install @commitlint/cli @commitlint/config-conventional --save-dev +# Check prerequisites +echo -e "${BLUE}AppFlowy : Checking prerequisites.${ENDCOLOR}" +cargo make flowy_dev diff --git a/frontend/scripts/install_dev_env/install_macos.sh b/frontend/scripts/install_dev_env/install_macos.sh new file mode 100755 index 0000000000..a4f325094e --- /dev/null +++ b/frontend/scripts/install_dev_env/install_macos.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +BLUE="\e[34m" +RED="\e[31m" +ENDCOLOR="\e[0m" + +# Install rust on Linux +echo -e "${BLUE}AppFlowy : The Rust programming language is required to compile AppFlowy.${ENDCOLOR}" +echo -e "${BLUE}AppFlowy : We can install it now if you don't already have it on your system.${ENDCOLOR}" + +read -p "${BLUE}AppFlowy : Do you want to install Rust? [y/N]${ENDCOLOR} " installrust + +if [ ${installrust^^} == "Y" ]; then + echo -e "${BLUE}AppFlowy : Installing Rust.${ENDCOLOR}" + brew 'rustup-init' + rustup-init -y --default-toolchain=stable +else + echo -e "${BLUE}AppFlowy : Skipping Rust installation.${ENDCOLOR}" +fi + +# Install sqllite +echo -e "${BLUE}AppFlowy : Installing SqlLite3.${ENDCOLOR}" +brew 'sqlite3' + +# Enable the flutter stable channel +echo -e "${BLUE}AppFlowy : Checking Flutter installation.${ENDCOLOR}" +flutter channel stable + +# Enable linux desktop +flutter config --enable-linux-desktop + +# Fix any problems reported by flutter doctor +flutter doctor + +# Add the githooks directory to your git configuration +echo -e "${BLUE}AppFlowy : Setting up githooks.${ENDCOLOR}" +git config core.hooksPath .githooks + +# Change to the frontend directory +cd frontend + +# Install cargo make +echo -e "${BLUE}AppFlowy : Installing cargo-make.${ENDCOLOR}" +cargo install --force cargo-make + +# Install duckscript +echo -e "${BLUE}AppFlowy : Installing duckscript.${ENDCOLOR}" +cargo install --force duckscript_cli + +# Install CommitLint +echo -e "${BLUE}AppFlowy : Installing CommitLint.${ENDCOLOR}" +npm install @commitlint/cli @commitlint/config-conventional --save-dev + +# Check prerequisites +echo -e "${BLUE}AppFlowy : Checking prerequisites.${ENDCOLOR}" +cargo make flowy_dev From f30f2485c68655df7fcc1b7c93826d1d12df5d1e Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 18 Jul 2022 20:08:13 -0400 Subject: [PATCH 037/112] fix: fixed colors when asking to install Rust --- frontend/scripts/install_dev_env/install_linux.sh | 5 +++-- frontend/scripts/install_dev_env/install_macos.sh | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/scripts/install_dev_env/install_linux.sh b/frontend/scripts/install_dev_env/install_linux.sh index 0446655c02..405c8b85c5 100755 --- a/frontend/scripts/install_dev_env/install_linux.sh +++ b/frontend/scripts/install_dev_env/install_linux.sh @@ -1,16 +1,17 @@ #!/bin/bash BLUE="\e[34m" +GREEN="\e[32m" RED="\e[31m" ENDCOLOR="\e[0m" # Note: This script does not install applications which are installed by the package manager. There are too many package managers out there. -# Install rust on Linux +# Install Rust echo -e "${BLUE}AppFlowy : The Rust programming language is required to compile AppFlowy.${ENDCOLOR}" echo -e "${BLUE}AppFlowy : We can install it now if you don't already have it on your system.${ENDCOLOR}" -read -p "${BLUE}AppFlowy : Do you want to install Rust? [y/N]${ENDCOLOR} " installrust +read -p "$(echo -e $GREEN"AppFlowy : Do you want to install Rust? [y/N]"$ENDCOLOR) " installrust if [ ${installrust^^} == "Y" ]; then echo -e "${BLUE}AppFlowy : Installing Rust.${ENDCOLOR}" diff --git a/frontend/scripts/install_dev_env/install_macos.sh b/frontend/scripts/install_dev_env/install_macos.sh index a4f325094e..8fc25f9227 100755 --- a/frontend/scripts/install_dev_env/install_macos.sh +++ b/frontend/scripts/install_dev_env/install_macos.sh @@ -1,14 +1,15 @@ #!/bin/bash BLUE="\e[34m" +GREEN="\e[32m" RED="\e[31m" ENDCOLOR="\e[0m" -# Install rust on Linux +# Install Rust echo -e "${BLUE}AppFlowy : The Rust programming language is required to compile AppFlowy.${ENDCOLOR}" echo -e "${BLUE}AppFlowy : We can install it now if you don't already have it on your system.${ENDCOLOR}" -read -p "${BLUE}AppFlowy : Do you want to install Rust? [y/N]${ENDCOLOR} " installrust +read -p "$(echo -e $GREEN"AppFlowy : Do you want to install Rust? [y/N]"$ENDCOLOR) " installrust if [ ${installrust^^} == "Y" ]; then echo -e "${BLUE}AppFlowy : Installing Rust.${ENDCOLOR}" From 6d9c4619e49d5e1abb6a841c35c84afa0d41bbc0 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 18 Jul 2022 21:44:11 -0400 Subject: [PATCH 038/112] fix: fixed flutter config variable for mac --- frontend/scripts/install_dev_env/install_macos.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/scripts/install_dev_env/install_macos.sh b/frontend/scripts/install_dev_env/install_macos.sh index 8fc25f9227..36c8f062f4 100755 --- a/frontend/scripts/install_dev_env/install_macos.sh +++ b/frontend/scripts/install_dev_env/install_macos.sh @@ -28,7 +28,7 @@ echo -e "${BLUE}AppFlowy : Checking Flutter installation.${ENDCOLOR}" flutter channel stable # Enable linux desktop -flutter config --enable-linux-desktop +flutter config --enable-macos-desktop # Fix any problems reported by flutter doctor flutter doctor From e7c672cb7e6246b6533d58fb05779f7e528e5e86 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 19 Jul 2022 11:31:04 +0800 Subject: [PATCH 039/112] chore: replace try_from with from --- .../flowy-folder/tests/workspace/script.rs | 6 +- .../flowy-net/src/http_server/document.rs | 6 +- .../flowy-net/src/local_server/persistence.rs | 12 +-- .../flowy-net/src/local_server/server.rs | 6 +- .../rust-lib/flowy-text-block/src/editor.rs | 6 +- frontend/rust-lib/flowy-text-block/src/lib.rs | 4 +- .../flowy-derive/src/proto_buf/deserialize.rs | 32 ++++---- .../flowy-derive/src/proto_buf/enum_serde.rs | 18 ++--- .../flowy-derive/src/proto_buf/serialize.rs | 21 +++-- .../flowy-sync/src/entities/revision.rs | 6 ++ .../flowy-sync/src/entities/text_block.rs | 8 +- .../src/server_document/document_manager.rs | 13 ++-- shared-lib/flowy-sync/src/util.rs | 76 ++++++------------- 13 files changed, 97 insertions(+), 117 deletions(-) diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs index 7b6091b7b5..cdcd3cfa8e 100644 --- a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs +++ b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs @@ -17,7 +17,7 @@ use flowy_folder::{errors::ErrorCode, services::folder_editor::FolderEditor}; use flowy_revision::disk::RevisionState; use flowy_revision::REVISION_WRITE_INTERVAL_IN_MILLIS; -use flowy_sync::entities::text_block::TextBlockInfoPB; +use flowy_sync::entities::text_block::DocumentPB; use flowy_test::{event_builder::*, FlowySDKTest}; use std::{sync::Arc, time::Duration}; use tokio::time::sleep; @@ -399,14 +399,14 @@ pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec) { } #[allow(dead_code)] -pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> TextBlockInfoPB { +pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> DocumentPB { let view_id: ViewId = view_id.into(); FolderEventBuilder::new(sdk.clone()) .event(SetLatestView) .payload(view_id) .async_send() .await - .parse::() + .parse::() } pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrash { diff --git a/frontend/rust-lib/flowy-net/src/http_server/document.rs b/frontend/rust-lib/flowy-net/src/http_server/document.rs index c8d18b07b2..ca9cb47955 100644 --- a/frontend/rust-lib/flowy-net/src/http_server/document.rs +++ b/frontend/rust-lib/flowy-net/src/http_server/document.rs @@ -3,7 +3,7 @@ use crate::{ request::{HttpRequestBuilder, ResponseMiddleware}, }; use flowy_error::FlowyError; -use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockIdPB, TextBlockInfoPB}; +use flowy_sync::entities::text_block::{CreateTextBlockParams, DocumentPB, ResetTextBlockParams, TextBlockIdPB}; use flowy_text_block::BlockCloudService; use http_flowy::response::FlowyResponse; use lazy_static::lazy_static; @@ -27,7 +27,7 @@ impl BlockCloudService for BlockHttpCloudService { FutureResult::new(async move { create_document_request(&token, params, &url).await }) } - fn read_block(&self, token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError> { + fn read_block(&self, token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError> { let token = token.to_owned(); let url = self.config.doc_url(); FutureResult::new(async move { read_document_request(&token, params, &url).await }) @@ -54,7 +54,7 @@ pub async fn read_document_request( token: &str, params: TextBlockIdPB, url: &str, -) -> Result, FlowyError> { +) -> Result, FlowyError> { let doc = request_builder() .get(&url.to_owned()) .header(HEADER_TOKEN, token) diff --git a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs index d8bae35401..4cd305f2a6 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs @@ -1,10 +1,10 @@ use flowy_sync::{ - entities::{folder::FolderInfo, text_block::TextBlockInfoPB}, + entities::{folder::FolderInfo, text_block::DocumentPB}, errors::CollaborateError, protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::*, server_folder::FolderCloudPersistence, - util::{make_document_info_from_revisions_pb, make_folder_from_revisions_pb}, + util::{make_document_from_revision_pbs, make_folder_from_revisions_pb}, }; use lib_infra::future::BoxResultFuture; use std::{ @@ -111,12 +111,12 @@ impl FolderCloudPersistence for LocalTextBlockCloudPersistence { } impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { - fn read_text_block(&self, doc_id: &str) -> BoxResultFuture { + fn read_text_block(&self, doc_id: &str) -> BoxResultFuture { let storage = self.storage.clone(); let doc_id = doc_id.to_owned(); Box::pin(async move { let repeated_revision = storage.get_revisions(&doc_id, None).await?; - match make_document_info_from_revisions_pb(&doc_id, repeated_revision)? { + match make_document_from_revision_pbs(&doc_id, repeated_revision)? { Some(document_info) => Ok(document_info), None => Err(CollaborateError::record_not_found()), } @@ -127,12 +127,12 @@ impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { &self, doc_id: &str, repeated_revision: RepeatedRevisionPB, - ) -> BoxResultFuture, CollaborateError> { + ) -> BoxResultFuture, CollaborateError> { let doc_id = doc_id.to_owned(); let storage = self.storage.clone(); Box::pin(async move { let _ = storage.set_revisions(repeated_revision.clone()).await?; - make_document_info_from_revisions_pb(&doc_id, repeated_revision) + make_document_from_revision_pbs(&doc_id, repeated_revision) }) } diff --git a/frontend/rust-lib/flowy-net/src/local_server/server.rs b/frontend/rust-lib/flowy-net/src/local_server/server.rs index 66a7682584..7625a8ee84 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/server.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/server.rs @@ -6,7 +6,7 @@ use flowy_folder::event_map::FolderCouldServiceV1; use flowy_sync::{ client_document::default::initial_quill_delta_string, entities::{ - text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockIdPB, TextBlockInfoPB}, + text_block::{CreateTextBlockParams, DocumentPB, ResetTextBlockParams, TextBlockIdPB}, ws_data::{ClientRevisionWSData, ClientRevisionWSDataType}, }, errors::CollaborateError, @@ -419,8 +419,8 @@ impl BlockCloudService for LocalServer { FutureResult::new(async { Ok(()) }) } - fn read_block(&self, _token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError> { - let doc = TextBlockInfoPB { + fn read_block(&self, _token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError> { + let doc = DocumentPB { block_id: params.value, text: initial_quill_delta_string(), rev_id: 0, diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 84b30a0047..6fed85c913 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -9,7 +9,7 @@ use flowy_error::{internal_error, FlowyResult}; use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket}; use flowy_sync::entities::ws_data::ServerRevisionWSData; use flowy_sync::{ - entities::{revision::Revision, text_block::TextBlockInfoPB}, + entities::{revision::Revision, text_block::DocumentPB}, errors::CollaborateResult, util::make_delta_from_revisions, }; @@ -229,14 +229,14 @@ impl TextBlockEditor { struct TextBlockInfoBuilder(); impl RevisionObjectBuilder for TextBlockInfoBuilder { - type Output = TextBlockInfoPB; + type Output = DocumentPB; fn build_object(object_id: &str, revisions: Vec) -> FlowyResult { let (base_rev_id, rev_id) = revisions.last().unwrap().pair_rev_id(); let mut delta = make_delta_from_revisions(revisions)?; correct_delta(&mut delta); - Result::::Ok(TextBlockInfoPB { + Result::::Ok(DocumentPB { block_id: object_id.to_owned(), text: delta.to_delta_str(), rev_id, diff --git a/frontend/rust-lib/flowy-text-block/src/lib.rs b/frontend/rust-lib/flowy-text-block/src/lib.rs index 808bc2d6f9..37ddf6ea1e 100644 --- a/frontend/rust-lib/flowy-text-block/src/lib.rs +++ b/frontend/rust-lib/flowy-text-block/src/lib.rs @@ -15,13 +15,13 @@ pub mod errors { pub const TEXT_BLOCK_SYNC_INTERVAL_IN_MILLIS: u64 = 1000; use crate::errors::FlowyError; -use flowy_sync::entities::text_block::{CreateTextBlockParams, ResetTextBlockParams, TextBlockIdPB, TextBlockInfoPB}; +use flowy_sync::entities::text_block::{CreateTextBlockParams, DocumentPB, ResetTextBlockParams, TextBlockIdPB}; use lib_infra::future::FutureResult; pub trait BlockCloudService: Send + Sync { fn create_block(&self, token: &str, params: CreateTextBlockParams) -> FutureResult<(), FlowyError>; - fn read_block(&self, token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError>; + fn read_block(&self, token: &str, params: TextBlockIdPB) -> FutureResult, FlowyError>; fn update_block(&self, token: &str, params: ResetTextBlockParams) -> FutureResult<(), FlowyError>; } diff --git a/shared-lib/flowy-derive/src/proto_buf/deserialize.rs b/shared-lib/flowy-derive/src/proto_buf/deserialize.rs index f0325db3b0..4fbbb1b3a7 100644 --- a/shared-lib/flowy-derive/src/proto_buf/deserialize.rs +++ b/shared-lib/flowy-derive/src/proto_buf/deserialize.rs @@ -25,8 +25,15 @@ pub fn make_de_token_steam(ctxt: &Ctxt, ast: &ASTContainer) -> Option for #struct_ident { type Error = ::protobuf::ProtobufError; fn try_from(bytes: bytes::Bytes) -> Result { - let pb: crate::protobuf::#pb_ty = ::protobuf::Message::parse_from_bytes(&bytes)?; - #struct_ident::try_from(pb) + Self::try_from(&bytes) + } + } + + impl std::convert::TryFrom<&bytes::Bytes> for #struct_ident { + type Error = ::protobuf::ProtobufError; + fn try_from(bytes: &bytes::Bytes) -> Result { + let pb: crate::protobuf::#pb_ty = ::protobuf::Message::parse_from_bytes(bytes)?; + Ok(#struct_ident::from(pb)) } } @@ -34,16 +41,15 @@ pub fn make_de_token_steam(ctxt: &Ctxt, ast: &ASTContainer) -> Option Result { let pb: crate::protobuf::#pb_ty = ::protobuf::Message::parse_from_bytes(bytes)?; - #struct_ident::try_from(pb) + Ok(#struct_ident::from(pb)) } } - impl std::convert::TryFrom for #struct_ident { - type Error = ::protobuf::ProtobufError; - fn try_from(mut pb: crate::protobuf::#pb_ty) -> Result { + impl std::convert::From for #struct_ident { + fn from(mut pb: crate::protobuf::#pb_ty) -> Self { let mut o = Self::default(); #(#build_take_fields)* - Ok(o) + o } } }; @@ -70,7 +76,7 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option let ty = bracketed_ty_info.unwrap().ty; Some(quote! { if pb.#has_func() { - let enum_de_from_pb = #ty::try_from(&pb.#get_func()).unwrap(); + let enum_de_from_pb = #ty::from(&pb.#get_func()); o.#member = Some(enum_de_from_pb); } }) @@ -104,7 +110,7 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option let ty = bracketed_ty_info.unwrap().ty; Some(quote! { if pb.#has_func() { - let val = #ty::try_from(pb.#take_func()).unwrap(); + let val = #ty::from(pb.#take_func()); o.#member=Some(val); } }) @@ -138,7 +144,7 @@ fn token_stream_for_field(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_ Some(quote! { let some_value = pb.#member.#take(); if some_value.is_some() { - let struct_de_from_pb = #ty::try_from(some_value.unwrap()).unwrap(); + let struct_de_from_pb = #ty::from(some_value.unwrap()); o.#member = struct_de_from_pb; } }) @@ -147,7 +153,7 @@ fn token_stream_for_field(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_ TypeCategory::Enum => { let ty = ty_info.ty; Some(quote! { - let enum_de_from_pb = #ty::try_from(&pb.#member).unwrap(); + let enum_de_from_pb = #ty::from(&pb.#member); o.#member = enum_de_from_pb; }) @@ -192,7 +198,7 @@ fn token_stream_for_vec(ctxt: &Ctxt, member: &syn::Member, bracketed_type: &TyIn Some(quote! { o.#member = pb.#take_ident() .into_iter() - .map(|m| #ty::try_from(m).unwrap()) + .map(|m| #ty::from(m)) .collect(); }) } @@ -221,7 +227,7 @@ fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, ty_info: &TyInfo) -> TypeCategory::Protobuf => Some(quote! { let mut m: std::collections::HashMap = std::collections::HashMap::new(); pb.#take_ident().into_iter().for_each(|(k,v)| { - m.insert(k.clone(), #ty::try_from(v).unwrap()); + m.insert(k.clone(), #ty::from(v)); }); o.#member = m; }), diff --git a/shared-lib/flowy-derive/src/proto_buf/enum_serde.rs b/shared-lib/flowy-derive/src/proto_buf/enum_serde.rs index 498be05e51..902af74ee8 100644 --- a/shared-lib/flowy-derive/src/proto_buf/enum_serde.rs +++ b/shared-lib/flowy-derive/src/proto_buf/enum_serde.rs @@ -20,21 +20,19 @@ pub fn make_enum_token_stream(_ctxt: &Ctxt, cont: &ASTContainer) -> Option for #enum_ident { - type Error = String; - fn try_from(pb:&crate::protobuf::#pb_enum) -> Result { - Ok(match pb { + impl std::convert::From<&crate::protobuf::#pb_enum> for #enum_ident { + fn from(pb:&crate::protobuf::#pb_enum) -> Self { + match pb { #(#build_from_pb_enum)* - }) + } } } - impl std::convert::TryInto for #enum_ident { - type Error = String; - fn try_into(self) -> Result { - Ok(match self { + impl std::convert::Into for #enum_ident { + fn into(self) -> crate::protobuf::#pb_enum { + match self { #(#build_to_pb_enum)* - }) + } } } }) diff --git a/shared-lib/flowy-derive/src/proto_buf/serialize.rs b/shared-lib/flowy-derive/src/proto_buf/serialize.rs index 324c26651b..0bf1469a3c 100644 --- a/shared-lib/flowy-derive/src/proto_buf/serialize.rs +++ b/shared-lib/flowy-derive/src/proto_buf/serialize.rs @@ -19,18 +19,17 @@ pub fn make_se_token_stream(ctxt: &Ctxt, ast: &ASTContainer) -> Option Result { use protobuf::Message; - let pb: crate::protobuf::#pb_ty = self.try_into()?; + let pb: crate::protobuf::#pb_ty = self.into(); let bytes = pb.write_to_bytes()?; Ok(bytes::Bytes::from(bytes)) } } - impl std::convert::TryInto for #struct_ident { - type Error = ::protobuf::ProtobufError; - fn try_into(self) -> Result { + impl std::convert::Into for #struct_ident { + fn into(self) -> crate::protobuf::#pb_ty { let mut pb = crate::protobuf::#pb_ty::new(); #(#build_set_pb_fields)* - Ok(pb) + pb } } }; @@ -67,13 +66,13 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option match ident_category(bracketed_ty_info.unwrap().ident) { TypeCategory::Protobuf => Some(quote! { match self.#member { - Some(s) => { pb.#set_func(s.try_into().unwrap()) } + Some(s) => { pb.#set_func(s.into()) } None => {} } }), TypeCategory::Enum => Some(quote! { match self.#member { - Some(s) => { pb.#set_func(s.try_into().unwrap()) } + Some(s) => { pb.#set_func(s.into()) } None => {} } }), @@ -110,7 +109,7 @@ fn gen_token_stream(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_option } } TypeCategory::Protobuf => { - Some(quote! { pb.#member = ::protobuf::SingularPtrField::some(self.#member.try_into().unwrap()); }) + Some(quote! { pb.#member = ::protobuf::SingularPtrField::some(self.#member.into()); }) } TypeCategory::Opt => gen_token_stream(ctxt, member, ty_info.bracket_ty_info.unwrap().ty, true), TypeCategory::Enum => { @@ -119,7 +118,7 @@ fn gen_token_stream(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_option // flowy_protobuf::#pb_enum_ident::from_i32(self.#member.value()).unwrap(); // }) Some(quote! { - pb.#member = self.#member.try_into().unwrap(); + pb.#member = self.#member.into(); }) } _ => Some(quote! { pb.#member = self.#member; }), @@ -141,7 +140,7 @@ fn token_stream_for_vec(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Op pb.#member = ::protobuf::RepeatedField::from_vec( self.#member .into_iter() - .map(|m| m.try_into().unwrap()) + .map(|m| m.into()) .collect()); }), TypeCategory::Bytes => Some(quote! { pb.#member = self.#member.clone(); }), @@ -167,7 +166,7 @@ fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Op TypeCategory::Protobuf => Some(quote! { let mut m: std::collections::HashMap = std::collections::HashMap::new(); self.#member.into_iter().for_each(|(k,v)| { - m.insert(k.clone(), v.try_into().unwrap()); + m.insert(k.clone(), v.into()); }); pb.#member = m; }), diff --git a/shared-lib/flowy-sync/src/entities/revision.rs b/shared-lib/flowy-sync/src/entities/revision.rs index 57276bba1b..d909efa3d5 100644 --- a/shared-lib/flowy-sync/src/entities/revision.rs +++ b/shared-lib/flowy-sync/src/entities/revision.rs @@ -125,6 +125,12 @@ impl std::convert::From for RepeatedRevision { } } +impl std::convert::From> for RepeatedRevision { + fn from(revisions: Vec) -> Self { + Self { items: revisions } + } +} + impl RepeatedRevision { pub fn new(mut items: Vec) -> Self { items.sort_by(|a, b| a.rev_id.cmp(&b.rev_id)); diff --git a/shared-lib/flowy-sync/src/entities/text_block.rs b/shared-lib/flowy-sync/src/entities/text_block.rs index cef3cd30f7..8753103369 100644 --- a/shared-lib/flowy-sync/src/entities/text_block.rs +++ b/shared-lib/flowy-sync/src/entities/text_block.rs @@ -15,7 +15,7 @@ pub struct CreateTextBlockParams { } #[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)] -pub struct TextBlockInfoPB { +pub struct DocumentPB { #[pb(index = 1)] pub block_id: String, @@ -29,14 +29,14 @@ pub struct TextBlockInfoPB { pub base_rev_id: i64, } -impl TextBlockInfoPB { +impl DocumentPB { pub fn delta(&self) -> Result { let delta = RichTextDelta::from_bytes(&self.text)?; Ok(delta) } } -impl std::convert::TryFrom for TextBlockInfoPB { +impl std::convert::TryFrom for DocumentPB { type Error = CollaborateError; fn try_from(revision: Revision) -> Result { @@ -48,7 +48,7 @@ impl std::convert::TryFrom for TextBlockInfoPB { let delta = RichTextDelta::from_bytes(&revision.delta_data)?; let doc_json = delta.to_delta_str(); - Ok(TextBlockInfoPB { + Ok(DocumentPB { block_id: revision.object_id, text: doc_json, rev_id: revision.rev_id, diff --git a/shared-lib/flowy-sync/src/server_document/document_manager.rs b/shared-lib/flowy-sync/src/server_document/document_manager.rs index 8aed39e993..9a5499f862 100644 --- a/shared-lib/flowy-sync/src/server_document/document_manager.rs +++ b/shared-lib/flowy-sync/src/server_document/document_manager.rs @@ -1,5 +1,5 @@ use crate::{ - entities::{text_block::TextBlockInfoPB, ws_data::ServerRevisionWSDataBuilder}, + entities::{text_block::DocumentPB, ws_data::ServerRevisionWSDataBuilder}, errors::{internal_error, CollaborateError, CollaborateResult}, protobuf::{ClientRevisionWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::document_pad::ServerDocument, @@ -18,13 +18,13 @@ use tokio::{ }; pub trait TextBlockCloudPersistence: Send + Sync + Debug { - fn read_text_block(&self, doc_id: &str) -> BoxResultFuture; + fn read_text_block(&self, doc_id: &str) -> BoxResultFuture; fn create_text_block( &self, doc_id: &str, repeated_revision: RepeatedRevisionPB, - ) -> BoxResultFuture, CollaborateError>; + ) -> BoxResultFuture, CollaborateError>; fn read_text_block_revisions( &self, @@ -182,10 +182,7 @@ impl ServerDocumentManager { } #[tracing::instrument(level = "debug", skip(self, doc), err)] - async fn create_document_handler( - &self, - doc: TextBlockInfoPB, - ) -> Result, CollaborateError> { + async fn create_document_handler(&self, doc: DocumentPB) -> Result, CollaborateError> { let persistence = self.persistence.clone(); let handle = spawn_blocking(|| OpenDocumentHandler::new(doc, persistence)) .await @@ -209,7 +206,7 @@ struct OpenDocumentHandler { } impl OpenDocumentHandler { - fn new(doc: TextBlockInfoPB, persistence: Arc) -> Result { + fn new(doc: DocumentPB, persistence: Arc) -> Result { let doc_id = doc.block_id.clone(); let (sender, receiver) = mpsc::channel(1000); let users = DashMap::new(); diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index 824f1f945b..e0c8e0a5fa 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -2,10 +2,10 @@ use crate::{ entities::{ folder::{FolderDelta, FolderInfo}, revision::{RepeatedRevision, Revision}, - text_block::TextBlockInfoPB, + text_block::DocumentPB, }, errors::{CollaborateError, CollaborateResult}, - protobuf::{FolderInfo as FolderInfoPB, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, + protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, }; use dissimilar::Chunk; use lib_ot::core::{DeltaBuilder, FlowyStr}; @@ -102,6 +102,9 @@ where pub fn repeated_revision_from_revision_pbs(revisions: Vec) -> CollaborateResult { let repeated_revision_pb = repeated_revision_pb_from_revisions(revisions); + + // let repeated_revision: RepeatedRevision = revisions.into_iter().map(Revision::); + repeated_revision_from_repeated_revision_pb(repeated_revision_pb) } @@ -151,23 +154,9 @@ pub fn pair_rev_id_from_revisions(revisions: &[Revision]) -> (i64, i64) { #[inline] pub fn make_folder_from_revisions_pb( - folder_id: &str, - revisions: RepeatedRevisionPB, -) -> Result, CollaborateError> { - match make_folder_pb_from_revisions_pb(folder_id, revisions)? { - None => Ok(None), - Some(pb) => { - let folder_info: FolderInfo = pb.try_into().map_err(|e| CollaborateError::internal().context(e))?; - Ok(Some(folder_info)) - } - } -} - -#[inline] -pub fn make_folder_pb_from_revisions_pb( folder_id: &str, mut revisions: RepeatedRevisionPB, -) -> Result, CollaborateError> { +) -> Result, CollaborateError> { let revisions = revisions.take_items(); if revisions.is_empty() { return Ok(None); @@ -187,41 +176,25 @@ pub fn make_folder_pb_from_revisions_pb( } let text = folder_delta.to_delta_str(); - let mut folder_info = FolderInfoPB::new(); - folder_info.set_folder_id(folder_id.to_owned()); - folder_info.set_text(text); - folder_info.set_base_rev_id(base_rev_id); - folder_info.set_rev_id(rev_id); - Ok(Some(folder_info)) + Ok(Some(FolderInfo { + folder_id: folder_id.to_string(), + text, + rev_id, + base_rev_id, + })) } #[inline] -pub fn make_document_info_from_revisions_pb( - doc_id: &str, - revisions: RepeatedRevisionPB, -) -> Result, CollaborateError> { - match make_document_info_pb_from_revisions_pb(doc_id, revisions)? { - None => Ok(None), - Some(pb) => { - let document_info: TextBlockInfoPB = pb.try_into().map_err(|e| { - CollaborateError::internal().context(format!("Deserialize document info from pb failed: {}", e)) - })?; - Ok(Some(document_info)) - } - } -} - -#[inline] -pub fn make_document_info_pb_from_revisions_pb( +pub fn make_document_from_revision_pbs( doc_id: &str, mut revisions: RepeatedRevisionPB, -) -> Result, CollaborateError> { +) -> Result, CollaborateError> { let revisions = revisions.take_items(); if revisions.is_empty() { return Ok(None); } - let mut document_delta = RichTextDelta::new(); + let mut delta = RichTextDelta::new(); let mut base_rev_id = 0; let mut rev_id = 0; for revision in revisions { @@ -232,17 +205,18 @@ pub fn make_document_info_pb_from_revisions_pb( tracing::warn!("revision delta_data is empty"); } - let delta = RichTextDelta::from_bytes(revision.delta_data)?; - document_delta = document_delta.compose(&delta)?; + let new_delta = RichTextDelta::from_bytes(revision.delta_data)?; + delta = delta.compose(&new_delta)?; } - let text = document_delta.to_delta_str(); - let mut block_info = crate::protobuf::TextBlockInfoPB::new(); - block_info.set_block_id(doc_id.to_owned()); - block_info.set_text(text); - block_info.set_base_rev_id(base_rev_id); - block_info.set_rev_id(rev_id); - Ok(Some(block_info)) + let text = delta.to_delta_str(); + + Ok(Some(DocumentPB { + block_id: doc_id.to_owned(), + text, + rev_id, + base_rev_id, + })) } #[inline] From 0ecff26636f6630a1f7d07f40a1373ae61a51eb4 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 19 Jul 2022 13:07:30 +0800 Subject: [PATCH 040/112] chore: remove pb reference in util.rs --- .../flowy-net/src/local_server/persistence.rs | 45 +++++++++---------- .../flowy-derive/src/proto_buf/enum_serde.rs | 6 +-- .../flowy-derive/src/proto_buf/serialize.rs | 34 +++++++------- .../src/server_document/document_manager.rs | 35 ++++++++------- .../src/server_folder/folder_manager.rs | 25 ++++++----- shared-lib/flowy-sync/src/synchronizer.rs | 42 ++++++++--------- shared-lib/flowy-sync/src/util.rs | 40 +++-------------- 7 files changed, 95 insertions(+), 132 deletions(-) diff --git a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs index 4cd305f2a6..17008481b5 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/persistence.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/persistence.rs @@ -1,7 +1,7 @@ +use flowy_sync::entities::revision::{RepeatedRevision, Revision}; use flowy_sync::{ entities::{folder::FolderInfo, text_block::DocumentPB}, errors::CollaborateError, - protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, server_document::*, server_folder::FolderCloudPersistence, util::{make_document_from_revision_pbs, make_folder_from_revisions_pb}, @@ -15,17 +15,17 @@ use std::{ // For the moment, we use memory to cache the data, it will be implemented with // other storage. Like the Firestore,Dropbox.etc. pub trait RevisionCloudStorage: Send + Sync { - fn set_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError>; + fn set_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError>; fn get_revisions( &self, object_id: &str, rev_ids: Option>, - ) -> BoxResultFuture; + ) -> BoxResultFuture; fn reset_object( &self, object_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture<(), CollaborateError>; } @@ -64,7 +64,7 @@ impl FolderCloudPersistence for LocalTextBlockCloudPersistence { &self, _user_id: &str, folder_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture, CollaborateError> { let folder_id = folder_id.to_owned(); let storage = self.storage.clone(); @@ -74,7 +74,7 @@ impl FolderCloudPersistence for LocalTextBlockCloudPersistence { }) } - fn save_folder_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { + fn save_folder_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> { let storage = self.storage.clone(); Box::pin(async move { let _ = storage.set_revisions(repeated_revision).await?; @@ -86,20 +86,19 @@ impl FolderCloudPersistence for LocalTextBlockCloudPersistence { &self, folder_id: &str, rev_ids: Option>, - ) -> BoxResultFuture, CollaborateError> { + ) -> BoxResultFuture, CollaborateError> { let folder_id = folder_id.to_owned(); let storage = self.storage.clone(); Box::pin(async move { - let mut repeated_revision = storage.get_revisions(&folder_id, rev_ids).await?; - let revisions: Vec = repeated_revision.take_items().into(); - Ok(revisions) + let repeated_revision = storage.get_revisions(&folder_id, rev_ids).await?; + Ok(repeated_revision.into_inner()) }) } fn reset_folder( &self, folder_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture<(), CollaborateError> { let storage = self.storage.clone(); let folder_id = folder_id.to_owned(); @@ -126,7 +125,7 @@ impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { fn create_text_block( &self, doc_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture, CollaborateError> { let doc_id = doc_id.to_owned(); let storage = self.storage.clone(); @@ -140,20 +139,16 @@ impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { &self, doc_id: &str, rev_ids: Option>, - ) -> BoxResultFuture, CollaborateError> { + ) -> BoxResultFuture, CollaborateError> { let doc_id = doc_id.to_owned(); let storage = self.storage.clone(); Box::pin(async move { - let mut repeated_revision = storage.get_revisions(&doc_id, rev_ids).await?; - let revisions: Vec = repeated_revision.take_items().into(); - Ok(revisions) + let repeated_revision = storage.get_revisions(&doc_id, rev_ids).await?; + Ok(repeated_revision.into_inner()) }) } - fn save_text_block_revisions( - &self, - repeated_revision: RepeatedRevisionPB, - ) -> BoxResultFuture<(), CollaborateError> { + fn save_text_block_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> { let storage = self.storage.clone(); Box::pin(async move { let _ = storage.set_revisions(repeated_revision).await?; @@ -161,7 +156,7 @@ impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { }) } - fn reset_text_block(&self, doc_id: &str, revisions: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { + fn reset_text_block(&self, doc_id: &str, revisions: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> { let storage = self.storage.clone(); let doc_id = doc_id.to_owned(); Box::pin(async move { @@ -174,7 +169,7 @@ impl TextBlockCloudPersistence for LocalTextBlockCloudPersistence { #[derive(Default)] struct MemoryDocumentCloudStorage {} impl RevisionCloudStorage for MemoryDocumentCloudStorage { - fn set_revisions(&self, _repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { + fn set_revisions(&self, _repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> { Box::pin(async move { Ok(()) }) } @@ -182,9 +177,9 @@ impl RevisionCloudStorage for MemoryDocumentCloudStorage { &self, _doc_id: &str, _rev_ids: Option>, - ) -> BoxResultFuture { + ) -> BoxResultFuture { Box::pin(async move { - let repeated_revisions = RepeatedRevisionPB::new(); + let repeated_revisions = RepeatedRevision::default(); Ok(repeated_revisions) }) } @@ -192,7 +187,7 @@ impl RevisionCloudStorage for MemoryDocumentCloudStorage { fn reset_object( &self, _doc_id: &str, - _repeated_revision: RepeatedRevisionPB, + _repeated_revision: RepeatedRevision, ) -> BoxResultFuture<(), CollaborateError> { Box::pin(async move { Ok(()) }) } diff --git a/shared-lib/flowy-derive/src/proto_buf/enum_serde.rs b/shared-lib/flowy-derive/src/proto_buf/enum_serde.rs index 902af74ee8..fb0870fde8 100644 --- a/shared-lib/flowy-derive/src/proto_buf/enum_serde.rs +++ b/shared-lib/flowy-derive/src/proto_buf/enum_serde.rs @@ -28,9 +28,9 @@ pub fn make_enum_token_stream(_ctxt: &Ctxt, cont: &ASTContainer) -> Option for #enum_ident { - fn into(self) -> crate::protobuf::#pb_enum { - match self { + impl std::convert::From<#enum_ident> for crate::protobuf::#pb_enum{ + fn from(o: #enum_ident) -> crate::protobuf::#pb_enum { + match o { #(#build_to_pb_enum)* } } diff --git a/shared-lib/flowy-derive/src/proto_buf/serialize.rs b/shared-lib/flowy-derive/src/proto_buf/serialize.rs index 0bf1469a3c..a43f337f8f 100644 --- a/shared-lib/flowy-derive/src/proto_buf/serialize.rs +++ b/shared-lib/flowy-derive/src/proto_buf/serialize.rs @@ -25,8 +25,8 @@ pub fn make_se_token_stream(ctxt: &Ctxt, ast: &ASTContainer) -> Option for #struct_ident { - fn into(self) -> crate::protobuf::#pb_ty { + impl std::convert::From<#struct_ident> for crate::protobuf::#pb_ty { + fn from(mut o: #struct_ident) -> crate::protobuf::#pb_ty { let mut pb = crate::protobuf::#pb_ty::new(); #(#build_set_pb_fields)* pb @@ -40,7 +40,7 @@ pub fn make_se_token_stream(ctxt: &Ctxt, ast: &ASTContainer) -> Option Option { if let Some(func) = &field.attrs.serialize_with() { let member = &field.member; - Some(quote! { pb.#member=self.#func(); }) + Some(quote! { pb.#member=o.#func(); }) } else if field.attrs.is_one_of() { token_stream_for_one_of(ctxt, field) } else { @@ -65,19 +65,19 @@ fn token_stream_for_one_of(ctxt: &Ctxt, field: &ASTField) -> Option match ident_category(bracketed_ty_info.unwrap().ident) { TypeCategory::Protobuf => Some(quote! { - match self.#member { + match o.#member { Some(s) => { pb.#set_func(s.into()) } None => {} } }), TypeCategory::Enum => Some(quote! { - match self.#member { + match o.#member { Some(s) => { pb.#set_func(s.into()) } None => {} } }), _ => Some(quote! { - match self.#member { + match o.#member { Some(ref s) => { pb.#set_func(s.clone()) } None => {} } @@ -99,18 +99,16 @@ fn gen_token_stream(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_option TypeCategory::Str => { if is_option { Some(quote! { - match self.#member { + match o.#member { Some(ref s) => { pb.#member = s.to_string().clone(); } None => { pb.#member = String::new(); } } }) } else { - Some(quote! { pb.#member = self.#member.clone(); }) + Some(quote! { pb.#member = o.#member.clone(); }) } } - TypeCategory::Protobuf => { - Some(quote! { pb.#member = ::protobuf::SingularPtrField::some(self.#member.into()); }) - } + TypeCategory::Protobuf => Some(quote! { pb.#member = ::protobuf::SingularPtrField::some(o.#member.into()); }), TypeCategory::Opt => gen_token_stream(ctxt, member, ty_info.bracket_ty_info.unwrap().ty, true), TypeCategory::Enum => { // let pb_enum_ident = format_ident!("{}", ty_info.ident.to_string()); @@ -118,10 +116,10 @@ fn gen_token_stream(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type, is_option // flowy_protobuf::#pb_enum_ident::from_i32(self.#member.value()).unwrap(); // }) Some(quote! { - pb.#member = self.#member.into(); + pb.#member = o.#member.into(); }) } - _ => Some(quote! { pb.#member = self.#member; }), + _ => Some(quote! { pb.#member = o.#member; }), } } @@ -138,15 +136,15 @@ fn token_stream_for_vec(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Op match ident_category(ty_info.ident) { TypeCategory::Protobuf => Some(quote! { pb.#member = ::protobuf::RepeatedField::from_vec( - self.#member + o.#member .into_iter() .map(|m| m.into()) .collect()); }), - TypeCategory::Bytes => Some(quote! { pb.#member = self.#member.clone(); }), + TypeCategory::Bytes => Some(quote! { pb.#member = o.#member.clone(); }), _ => Some(quote! { - pb.#member = ::protobuf::RepeatedField::from_vec(self.#member.clone()); + pb.#member = ::protobuf::RepeatedField::from_vec(o.#member.clone()); }), } } @@ -165,14 +163,14 @@ fn token_stream_for_map(ctxt: &Ctxt, member: &syn::Member, ty: &syn::Type) -> Op match ident_category(ty_info.ident) { TypeCategory::Protobuf => Some(quote! { let mut m: std::collections::HashMap = std::collections::HashMap::new(); - self.#member.into_iter().for_each(|(k,v)| { + o.#member.into_iter().for_each(|(k,v)| { m.insert(k.clone(), v.into()); }); pb.#member = m; }), _ => Some(quote! { let mut m: std::collections::HashMap = std::collections::HashMap::new(); - self.#member.iter().for_each(|(k,v)| { + o.#member.iter().for_each(|(k,v)| { m.insert(k.clone(), v.clone()); }); pb.#member = m; diff --git a/shared-lib/flowy-sync/src/server_document/document_manager.rs b/shared-lib/flowy-sync/src/server_document/document_manager.rs index 9a5499f862..59d3dd3c97 100644 --- a/shared-lib/flowy-sync/src/server_document/document_manager.rs +++ b/shared-lib/flowy-sync/src/server_document/document_manager.rs @@ -1,7 +1,8 @@ +use crate::entities::revision::{RepeatedRevision, Revision}; use crate::{ entities::{text_block::DocumentPB, ws_data::ServerRevisionWSDataBuilder}, errors::{internal_error, CollaborateError, CollaborateResult}, - protobuf::{ClientRevisionWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, + protobuf::ClientRevisionWSData, server_document::document_pad::ServerDocument, synchronizer::{RevisionSyncPersistence, RevisionSyncResponse, RevisionSynchronizer, RevisionUser}, util::rev_id_from_str, @@ -23,22 +24,21 @@ pub trait TextBlockCloudPersistence: Send + Sync + Debug { fn create_text_block( &self, doc_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture, CollaborateError>; fn read_text_block_revisions( &self, doc_id: &str, rev_ids: Option>, - ) -> BoxResultFuture, CollaborateError>; + ) -> BoxResultFuture, CollaborateError>; - fn save_text_block_revisions(&self, repeated_revision: RepeatedRevisionPB) - -> BoxResultFuture<(), CollaborateError>; + fn save_text_block_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError>; fn reset_text_block( &self, doc_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture<(), CollaborateError>; } @@ -47,18 +47,18 @@ impl RevisionSyncPersistence for Arc { &self, object_id: &str, rev_ids: Option>, - ) -> BoxResultFuture, CollaborateError> { + ) -> BoxResultFuture, CollaborateError> { (**self).read_text_block_revisions(object_id, rev_ids) } - fn save_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { + fn save_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> { (**self).save_text_block_revisions(repeated_revision) } fn reset_object( &self, object_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture<(), CollaborateError> { (**self).reset_text_block(object_id, repeated_revision) } @@ -82,7 +82,7 @@ impl ServerDocumentManager { user: Arc, mut client_data: ClientRevisionWSData, ) -> Result<(), CollaborateError> { - let repeated_revision = client_data.take_revisions(); + let repeated_revision: RepeatedRevision = client_data.take_revisions().into(); let cloned_user = user.clone(); let ack_id = rev_id_from_str(&client_data.data_id)?; let object_id = client_data.object_id; @@ -131,9 +131,10 @@ impl ServerDocumentManager { pub async fn handle_document_reset( &self, doc_id: &str, - mut repeated_revision: RepeatedRevisionPB, + mut repeated_revision: RepeatedRevision, ) -> Result<(), CollaborateError> { - repeated_revision.mut_items().sort_by(|a, b| a.rev_id.cmp(&b.rev_id)); + repeated_revision.sort_by(|a, b| a.rev_id.cmp(&b.rev_id)); + match self.get_document_handler(doc_id).await { None => { tracing::warn!("Document:{} doesn't exist, ignore document reset", doc_id); @@ -166,7 +167,7 @@ impl ServerDocumentManager { async fn create_document( &self, doc_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> Result, CollaborateError> { match self.persistence.create_text_block(doc_id, repeated_revision).await? { None => Err(CollaborateError::internal().context("Create document info from revisions failed")), @@ -229,7 +230,7 @@ impl OpenDocumentHandler { async fn apply_revisions( &self, user: Arc, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> Result<(), CollaborateError> { let (ret, rx) = oneshot::channel(); self.users.insert(user.user_id(), user.clone()); @@ -252,7 +253,7 @@ impl OpenDocumentHandler { } #[tracing::instrument(level = "debug", skip(self, repeated_revision), err)] - async fn apply_document_reset(&self, repeated_revision: RepeatedRevisionPB) -> Result<(), CollaborateError> { + async fn apply_document_reset(&self, repeated_revision: RepeatedRevision) -> Result<(), CollaborateError> { let (ret, rx) = oneshot::channel(); let msg = DocumentCommand::Reset { repeated_revision, ret }; let result = self.send(msg, rx).await?; @@ -279,7 +280,7 @@ impl std::ops::Drop for OpenDocumentHandler { enum DocumentCommand { ApplyRevisions { user: Arc, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ret: oneshot::Sender>, }, Ping { @@ -288,7 +289,7 @@ enum DocumentCommand { ret: oneshot::Sender>, }, Reset { - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ret: oneshot::Sender>, }, } diff --git a/shared-lib/flowy-sync/src/server_folder/folder_manager.rs b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs index 0a1a5e117a..16b753f50b 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_manager.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs @@ -1,10 +1,11 @@ +use crate::entities::revision::{RepeatedRevision, Revision}; use crate::{ entities::{ folder::{FolderDelta, FolderInfo}, ws_data::ServerRevisionWSDataBuilder, }, errors::{internal_error, CollaborateError, CollaborateResult}, - protobuf::{ClientRevisionWSData, RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, + protobuf::ClientRevisionWSData, server_folder::folder_pad::ServerFolder, synchronizer::{RevisionSyncPersistence, RevisionSyncResponse, RevisionSynchronizer, RevisionUser}, util::rev_id_from_str, @@ -26,21 +27,21 @@ pub trait FolderCloudPersistence: Send + Sync + Debug { &self, user_id: &str, folder_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture, CollaborateError>; - fn save_folder_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError>; + fn save_folder_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError>; fn read_folder_revisions( &self, folder_id: &str, rev_ids: Option>, - ) -> BoxResultFuture, CollaborateError>; + ) -> BoxResultFuture, CollaborateError>; fn reset_folder( &self, folder_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture<(), CollaborateError>; } @@ -49,18 +50,18 @@ impl RevisionSyncPersistence for Arc { &self, object_id: &str, rev_ids: Option>, - ) -> BoxResultFuture, CollaborateError> { + ) -> BoxResultFuture, CollaborateError> { (**self).read_folder_revisions(object_id, rev_ids) } - fn save_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError> { + fn save_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError> { (**self).save_folder_revisions(repeated_revision) } fn reset_object( &self, object_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture<(), CollaborateError> { (**self).reset_folder(object_id, repeated_revision) } @@ -84,7 +85,7 @@ impl ServerFolderManager { user: Arc, mut client_data: ClientRevisionWSData, ) -> Result<(), CollaborateError> { - let repeated_revision = client_data.take_revisions(); + let repeated_revision: RepeatedRevision = client_data.take_revisions().into(); let cloned_user = user.clone(); let ack_id = rev_id_from_str(&client_data.data_id)?; let folder_id = client_data.object_id; @@ -167,7 +168,7 @@ impl ServerFolderManager { &self, user_id: &str, folder_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> Result, CollaborateError> { match self .persistence @@ -221,7 +222,7 @@ impl OpenFolderHandler { async fn apply_revisions( &self, user: Arc, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> CollaborateResult<()> { let (ret, rx) = oneshot::channel(); let msg = FolderCommand::ApplyRevisions { @@ -258,7 +259,7 @@ impl std::ops::Drop for OpenFolderHandler { enum FolderCommand { ApplyRevisions { user: Arc, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ret: oneshot::Sender>, }, Ping { diff --git a/shared-lib/flowy-sync/src/synchronizer.rs b/shared-lib/flowy-sync/src/synchronizer.rs index 1305c471b2..eca422296a 100644 --- a/shared-lib/flowy-sync/src/synchronizer.rs +++ b/shared-lib/flowy-sync/src/synchronizer.rs @@ -1,10 +1,11 @@ +use crate::entities::revision::{RepeatedRevision, Revision}; use crate::{ entities::{ revision::RevisionRange, ws_data::{ServerRevisionWSData, ServerRevisionWSDataBuilder}, }, errors::CollaborateError, - protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, + protobuf::Revision as RevisionPB, util::*, }; use lib_infra::future::BoxResultFuture; @@ -31,14 +32,14 @@ pub trait RevisionSyncPersistence: Send + Sync + 'static { &self, object_id: &str, rev_ids: Option>, - ) -> BoxResultFuture, CollaborateError>; + ) -> BoxResultFuture, CollaborateError>; - fn save_revisions(&self, repeated_revision: RepeatedRevisionPB) -> BoxResultFuture<(), CollaborateError>; + fn save_revisions(&self, repeated_revision: RepeatedRevision) -> BoxResultFuture<(), CollaborateError>; fn reset_object( &self, object_id: &str, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> BoxResultFuture<(), CollaborateError>; } @@ -87,20 +88,20 @@ where pub async fn sync_revisions( &self, user: Arc, - repeated_revision: RepeatedRevisionPB, + repeated_revision: RepeatedRevision, ) -> Result<(), CollaborateError> { let object_id = self.object_id.clone(); - if repeated_revision.get_items().is_empty() { + if repeated_revision.is_empty() { // Return all the revisions to client let revisions = self.persistence.read_revisions(&object_id, None).await?; - let repeated_revision = repeated_revision_from_revision_pbs(revisions)?; + let repeated_revision = RepeatedRevision::from(revisions); let data = ServerRevisionWSDataBuilder::build_push_message(&object_id, repeated_revision); user.receive(RevisionSyncResponse::Push(data)); return Ok(()); } let server_base_rev_id = self.rev_id.load(SeqCst); - let first_revision = repeated_revision.get_items().first().unwrap().clone(); + let first_revision = repeated_revision.first().unwrap().clone(); if self.is_applied_before(&first_revision, &self.persistence).await { // Server has received this revision before, so ignore the following revisions return Ok(()); @@ -111,7 +112,7 @@ where let server_rev_id = next(server_base_rev_id); if server_base_rev_id == first_revision.base_rev_id || server_rev_id == first_revision.rev_id { // The rev is in the right order, just compose it. - for revision in repeated_revision.get_items() { + for revision in repeated_revision.iter() { let _ = self.compose_revision(revision)?; } let _ = self.persistence.save_revisions(repeated_revision).await?; @@ -165,10 +166,10 @@ where } #[tracing::instrument(level = "debug", skip(self, repeated_revision), fields(object_id), err)] - pub async fn reset(&self, repeated_revision: RepeatedRevisionPB) -> Result<(), CollaborateError> { + pub async fn reset(&self, repeated_revision: RepeatedRevision) -> Result<(), CollaborateError> { let object_id = self.object_id.clone(); tracing::Span::current().record("object_id", &object_id.as_str()); - let revisions: Vec = repeated_revision.get_items().to_vec(); + let revisions: Vec = repeated_revision.clone().into_inner(); let (_, rev_id) = pair_rev_id_from_revision_pbs(&revisions); let delta = make_delta_from_revision_pb(revisions)?; let _ = self.persistence.reset_object(&object_id, repeated_revision).await?; @@ -181,7 +182,7 @@ where self.object.read().to_json() } - fn compose_revision(&self, revision: &RevisionPB) -> Result<(), CollaborateError> { + fn compose_revision(&self, revision: &Revision) -> Result<(), CollaborateError> { let delta = Delta::::from_bytes(&revision.delta_data)?; let _ = self.compose_delta(delta)?; let _ = self.rev_id.fetch_update(SeqCst, SeqCst, |_e| Some(revision.rev_id)); @@ -213,11 +214,7 @@ where self.rev_id.load(SeqCst) } - async fn is_applied_before( - &self, - new_revision: &RevisionPB, - persistence: &Arc, - ) -> bool { + async fn is_applied_before(&self, new_revision: &Revision, persistence: &Arc) -> bool { let rev_ids = Some(vec![new_revision.rev_id]); if let Ok(revisions) = persistence.read_revisions(&self.object_id, rev_ids).await { if let Some(revision) = revisions.first() { @@ -243,13 +240,10 @@ where tracing::trace!("{}: can not read the revisions in range {:?}", self.object_id, rev_ids); // assert_eq!(revisions.is_empty(), rev_ids.is_empty(),); } - match repeated_revision_from_revision_pbs(revisions) { - Ok(repeated_revision) => { - let data = ServerRevisionWSDataBuilder::build_push_message(&self.object_id, repeated_revision); - user.receive(RevisionSyncResponse::Push(data)); - } - Err(e) => tracing::error!("{}", e), - } + + let repeated_revision = RepeatedRevision::from(revisions); + let data = ServerRevisionWSDataBuilder::build_push_message(&self.object_id, repeated_revision); + user.receive(RevisionSyncResponse::Push(data)); } Err(e) => { tracing::error!("{}", e); diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index e0c8e0a5fa..c4504a806a 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -5,7 +5,6 @@ use crate::{ text_block::DocumentPB, }, errors::{CollaborateError, CollaborateResult}, - protobuf::{RepeatedRevision as RepeatedRevisionPB, Revision as RevisionPB}, }; use dissimilar::Chunk; use lib_ot::core::{DeltaBuilder, FlowyStr}; @@ -14,10 +13,7 @@ use lib_ot::{ rich_text::RichTextDelta, }; use serde::de::DeserializeOwned; -use std::{ - convert::TryInto, - sync::atomic::{AtomicI64, Ordering::SeqCst}, -}; +use std::sync::atomic::{AtomicI64, Ordering::SeqCst}; #[inline] pub fn find_newline(s: &str) -> Option { @@ -85,7 +81,7 @@ where Ok(delta) } -pub fn make_delta_from_revision_pb(revisions: Vec) -> CollaborateResult> +pub fn make_delta_from_revision_pb(revisions: Vec) -> CollaborateResult> where T: Attributes + DeserializeOwned, { @@ -100,29 +96,7 @@ where Ok(new_delta) } -pub fn repeated_revision_from_revision_pbs(revisions: Vec) -> CollaborateResult { - let repeated_revision_pb = repeated_revision_pb_from_revisions(revisions); - - // let repeated_revision: RepeatedRevision = revisions.into_iter().map(Revision::); - - repeated_revision_from_repeated_revision_pb(repeated_revision_pb) -} - -pub fn repeated_revision_pb_from_revisions(revisions: Vec) -> RepeatedRevisionPB { - let mut repeated_revision_pb = RepeatedRevisionPB::new(); - repeated_revision_pb.set_items(revisions.into()); - repeated_revision_pb -} - -pub fn repeated_revision_from_repeated_revision_pb( - repeated_revision: RepeatedRevisionPB, -) -> CollaborateResult { - repeated_revision - .try_into() - .map_err(|e| CollaborateError::internal().context(format!("Cast repeated revision failed: {:?}", e))) -} - -pub fn pair_rev_id_from_revision_pbs(revisions: &[RevisionPB]) -> (i64, i64) { +pub fn pair_rev_id_from_revision_pbs(revisions: &[Revision]) -> (i64, i64) { let mut rev_id = 0; revisions.iter().for_each(|revision| { if rev_id < revision.rev_id { @@ -155,9 +129,9 @@ pub fn pair_rev_id_from_revisions(revisions: &[Revision]) -> (i64, i64) { #[inline] pub fn make_folder_from_revisions_pb( folder_id: &str, - mut revisions: RepeatedRevisionPB, + revisions: RepeatedRevision, ) -> Result, CollaborateError> { - let revisions = revisions.take_items(); + let revisions = revisions.into_inner(); if revisions.is_empty() { return Ok(None); } @@ -187,9 +161,9 @@ pub fn make_folder_from_revisions_pb( #[inline] pub fn make_document_from_revision_pbs( doc_id: &str, - mut revisions: RepeatedRevisionPB, + revisions: RepeatedRevision, ) -> Result, CollaborateError> { - let revisions = revisions.take_items(); + let revisions = revisions.into_inner(); if revisions.is_empty() { return Ok(None); } From 193527e043d69c0716b7945a7ad3dc993a4d91b5 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 19 Jul 2022 14:11:29 +0800 Subject: [PATCH 041/112] chore: rename flowy-folder structs --- .../app_flowy/lib/startup/deps_resolver.dart | 16 +- .../lib/user/application/user_listener.dart | 8 +- .../lib/user/application/user_service.dart | 12 +- .../lib/user/presentation/router.dart | 4 +- .../user/presentation/skip_log_in_screen.dart | 2 +- .../lib/user/presentation/welcome_screen.dart | 8 +- .../workspace/application/app/app_bloc.dart | 32 ++-- .../application/app/app_listener.dart | 8 +- .../application/app/app_service.dart | 18 +- .../workspace/application/doc/doc_bloc.dart | 2 +- .../application/doc/doc_service.dart | 4 +- .../workspace/application/doc/share_bloc.dart | 2 +- .../workspace/application/grid/grid_bloc.dart | 2 +- .../application/grid/grid_service.dart | 4 +- .../workspace/application/home/home_bloc.dart | 10 +- .../workspace/application/menu/menu_bloc.dart | 8 +- .../application/menu/menu_user_bloc.dart | 4 +- .../menu/menu_view_section_bloc.dart | 10 +- .../application/trash/trash_bloc.dart | 8 +- .../application/trash/trash_listener.dart | 4 +- .../application/trash/trash_service.dart | 8 +- .../workspace/application/view/view_bloc.dart | 8 +- .../workspace/application/view/view_ext.dart | 2 +- .../application/view/view_listener.dart | 14 +- .../application/view/view_service.dart | 12 +- .../application/workspace/welcome_bloc.dart | 8 +- .../workspace/workspace_listener.dart | 8 +- .../workspace/workspace_service.dart | 16 +- .../presentation/home/home_screen.dart | 4 +- .../home/menu/app/header/header.dart | 4 +- .../presentation/home/menu/app/menu_app.dart | 2 +- .../home/menu/app/section/item.dart | 4 +- .../presentation/home/menu/menu.dart | 12 +- .../presentation/plugins/board/board.dart | 10 +- .../plugins/board/src/board_page.dart | 4 +- .../presentation/plugins/doc/document.dart | 12 +- .../plugins/doc/src/document_page.dart | 2 +- .../presentation/plugins/grid/grid.dart | 10 +- .../plugins/grid/src/grid_page.dart | 2 +- .../plugins/trash/src/trash_cell.dart | 2 +- .../presentation/plugins/trash/trash.dart | 2 +- .../plugins/widgets/left_bar_item.dart | 4 +- .../rust-lib/flowy-folder/src/entities/app.rs | 69 ++++---- .../flowy-folder/src/entities/trash.rs | 54 +++--- .../flowy-folder/src/entities/view.rs | 66 +++----- .../flowy-folder/src/entities/view_info.rs | 6 +- .../flowy-folder/src/entities/workspace.rs | 46 +++--- .../rust-lib/flowy-folder/src/event_map.rs | 68 ++++---- frontend/rust-lib/flowy-folder/src/manager.rs | 4 +- .../src/services/app/controller.rs | 16 +- .../src/services/app/event_handler.rs | 18 +- .../services/persistence/version_1/app_sql.rs | 6 +- .../persistence/version_1/view_sql.rs | 6 +- .../src/services/trash/controller.rs | 40 ++--- .../src/services/trash/event_handler.rs | 8 +- .../src/services/view/controller.rs | 30 ++-- .../src/services/view/event_handler.rs | 47 +++--- .../src/services/workspace/controller.rs | 18 +- .../src/services/workspace/event_handler.rs | 38 ++--- .../tests/workspace/folder_test.rs | 4 +- .../flowy-folder/tests/workspace/script.rs | 96 +++++------ .../flowy-net/src/http_server/folder.rs | 154 +++++++++--------- .../flowy-net/src/local_server/server.rs | 24 +-- frontend/rust-lib/flowy-test/src/helper.rs | 30 ++-- 64 files changed, 565 insertions(+), 599 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index bdb76996e9..6f1d7e64a4 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -67,7 +67,7 @@ void _resolveHomeDeps(GetIt getIt) { // share getIt.registerLazySingleton(() => ShareService()); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (view, _) => DocShareBloc(view: view, service: getIt())); } @@ -76,12 +76,12 @@ void _resolveFolderDeps(GetIt getIt) { getIt.registerFactoryParam( (user, workspaceId) => WorkspaceListener(user: user, workspaceId: workspaceId)); - // View - getIt.registerFactoryParam( + // ViewPB + getIt.registerFactoryParam( (view, _) => ViewListener(view: view), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (view, _) => ViewBloc( view: view, service: ViewService(), @@ -101,8 +101,8 @@ void _resolveFolderDeps(GetIt getIt) { (user, _) => MenuUserBloc(user), ); - // App - getIt.registerFactoryParam( + // AppPB + getIt.registerFactoryParam( (app, _) => AppBloc( app: app, appService: AppService(appId: app.id), @@ -123,7 +123,7 @@ void _resolveFolderDeps(GetIt getIt) { void _resolveDocDeps(GetIt getIt) { // Doc - getIt.registerFactoryParam( + getIt.registerFactoryParam( (view, _) => DocumentBloc( view: view, service: DocumentService(), @@ -135,7 +135,7 @@ void _resolveDocDeps(GetIt getIt) { void _resolveGridDeps(GetIt getIt) { // GridPB - getIt.registerFactoryParam( + getIt.registerFactoryParam( (view, _) => GridBloc(view: view), ); diff --git a/frontend/app_flowy/lib/user/application/user_listener.dart b/frontend/app_flowy/lib/user/application/user_listener.dart index 89fc393e2d..ec3cd5ac1d 100644 --- a/frontend/app_flowy/lib/user/application/user_listener.dart +++ b/frontend/app_flowy/lib/user/application/user_listener.dart @@ -75,8 +75,8 @@ class UserListener { } } -typedef WorkspaceListNotifyValue = Either, FlowyError>; -typedef WorkspaceSettingNotifyValue = Either; +typedef WorkspaceListNotifyValue = Either, FlowyError>; +typedef WorkspaceSettingNotifyValue = Either; class UserWorkspaceListener { PublishNotifier? _authNotifier = PublishNotifier(); @@ -119,13 +119,13 @@ class UserWorkspaceListener { case FolderNotification.UserDeleteWorkspace: case FolderNotification.WorkspaceListUpdated: result.fold( - (payload) => _workspacesChangedNotifier?.value = left(RepeatedWorkspace.fromBuffer(payload).items), + (payload) => _workspacesChangedNotifier?.value = left(RepeatedWorkspacePB.fromBuffer(payload).items), (error) => _workspacesChangedNotifier?.value = right(error), ); break; case FolderNotification.WorkspaceSetting: result.fold( - (payload) => _settingChangedNotifier?.value = left(CurrentWorkspaceSetting.fromBuffer(payload)), + (payload) => _settingChangedNotifier?.value = left(CurrentWorkspaceSettingPB.fromBuffer(payload)), (error) => _settingChangedNotifier?.value = right(error), ); break; diff --git a/frontend/app_flowy/lib/user/application/user_service.dart b/frontend/app_flowy/lib/user/application/user_service.dart index 8417a069f9..8685205567 100644 --- a/frontend/app_flowy/lib/user/application/user_service.dart +++ b/frontend/app_flowy/lib/user/application/user_service.dart @@ -49,8 +49,8 @@ class UserService { return UserEventInitUser().send(); } - Future, FlowyError>> getWorkspaces() { - final request = WorkspaceId.create(); + Future, FlowyError>> getWorkspaces() { + final request = WorkspaceIdPB.create(); return FolderEventReadWorkspaces(request).send().then((result) { return result.fold( @@ -60,8 +60,8 @@ class UserService { }); } - Future> openWorkspace(String workspaceId) { - final request = WorkspaceId.create()..value = workspaceId; + Future> openWorkspace(String workspaceId) { + final request = WorkspaceIdPB.create()..value = workspaceId; return FolderEventOpenWorkspace(request).send().then((result) { return result.fold( (workspace) => left(workspace), @@ -70,8 +70,8 @@ class UserService { }); } - Future> createWorkspace(String name, String desc) { - final request = CreateWorkspacePayload.create() + Future> createWorkspace(String name, String desc) { + final request = CreateWorkspacePayloadPB.create() ..name = name ..desc = desc; return FolderEventCreateWorkspace(request).send().then((result) { diff --git a/frontend/app_flowy/lib/user/presentation/router.dart b/frontend/app_flowy/lib/user/presentation/router.dart index 3bcfa11502..5f863a8d99 100644 --- a/frontend/app_flowy/lib/user/presentation/router.dart +++ b/frontend/app_flowy/lib/user/presentation/router.dart @@ -28,7 +28,7 @@ class AuthRouter { ); } - void pushHomeScreen(BuildContext context, UserProfile profile, CurrentWorkspaceSetting workspaceSetting) { + void pushHomeScreen(BuildContext context, UserProfile profile, CurrentWorkspaceSettingPB workspaceSetting) { Navigator.push( context, PageRoutes.fade(() => HomeScreen(profile, workspaceSetting), RouteDurations.slow.inMilliseconds * .001), @@ -49,7 +49,7 @@ class SplashRoute { pushHomeScreen(context, userProfile, workspaceId); } - void pushHomeScreen(BuildContext context, UserProfile userProfile, CurrentWorkspaceSetting workspaceSetting) { + void pushHomeScreen(BuildContext context, UserProfile userProfile, CurrentWorkspaceSettingPB workspaceSetting) { Navigator.push( context, PageRoutes.fade(() => HomeScreen(userProfile, workspaceSetting), RouteDurations.slow.inMilliseconds * .001), diff --git a/frontend/app_flowy/lib/user/presentation/skip_log_in_screen.dart b/frontend/app_flowy/lib/user/presentation/skip_log_in_screen.dart index c8fb9ba06b..a6feeae3ff 100644 --- a/frontend/app_flowy/lib/user/presentation/skip_log_in_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/skip_log_in_screen.dart @@ -117,7 +117,7 @@ class _SkipLogInScreenState extends State { void _openCurrentWorkspace( BuildContext context, UserProfile user, - dartz.Either workspacesOrError, + dartz.Either workspacesOrError, ) { workspacesOrError.fold( (workspaceSetting) { diff --git a/frontend/app_flowy/lib/user/presentation/welcome_screen.dart b/frontend/app_flowy/lib/user/presentation/welcome_screen.dart index 60ec3bf8a2..45a3ce9bcc 100644 --- a/frontend/app_flowy/lib/user/presentation/welcome_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/welcome_screen.dart @@ -65,7 +65,7 @@ class WelcomeScreen extends StatelessWidget { ); } - Widget _renderList(List workspaces) { + Widget _renderList(List workspaces) { return Expanded( child: StyledListView( itemBuilder: (BuildContext context, int index) { @@ -80,7 +80,7 @@ class WelcomeScreen extends StatelessWidget { ); } - void _handleOnPress(BuildContext context, Workspace workspace) { + void _handleOnPress(BuildContext context, WorkspacePB workspace) { context.read().add(WelcomeEvent.openWorkspace(workspace)); Navigator.of(context).pop(workspace.id); @@ -88,8 +88,8 @@ class WelcomeScreen extends StatelessWidget { } class WorkspaceItem extends StatelessWidget { - final Workspace workspace; - final void Function(Workspace workspace) onPressed; + final WorkspacePB workspace; + final void Function(WorkspacePB workspace) onPressed; const WorkspaceItem({Key? key, required this.workspace, required this.onPressed}) : super(key: key); @override diff --git a/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart b/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart index 18f93abd6f..e8d2335168 100644 --- a/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/app/app_bloc.dart @@ -18,7 +18,7 @@ import 'package:dartz/dartz.dart'; part 'app_bloc.freezed.dart'; class AppBloc extends Bloc { - final App app; + final AppPB app; final AppService appService; final AppListener appListener; @@ -103,7 +103,7 @@ class AppBloc extends Bloc { return super.close(); } - Future _didReceiveViewUpdated(List views, Emitter emit) async { + Future _didReceiveViewUpdated(List views, Emitter emit) async { final latestCreatedView = state.latestCreatedView; AppState newState = state.copyWith(views: views); if (latestCreatedView != null) { @@ -139,20 +139,20 @@ class AppEvent with _$AppEvent { ) = CreateView; const factory AppEvent.delete() = Delete; const factory AppEvent.rename(String newName) = Rename; - const factory AppEvent.didReceiveViewUpdated(List views) = ReceiveViews; - const factory AppEvent.appDidUpdate(App app) = AppDidUpdate; + const factory AppEvent.didReceiveViewUpdated(List views) = ReceiveViews; + const factory AppEvent.appDidUpdate(AppPB app) = AppDidUpdate; } @freezed class AppState with _$AppState { const factory AppState({ - required App app, - required List views, - View? latestCreatedView, + required AppPB app, + required List views, + ViewPB? latestCreatedView, required Either successOrFailure, }) = _AppState; - factory AppState.initial(App app) => AppState( + factory AppState.initial(AppPB app) => AppState( app: app, views: [], successOrFailure: left(unit), @@ -161,8 +161,8 @@ class AppState with _$AppState { class AppViewDataContext extends ChangeNotifier { final String appId; - final ValueNotifier> _viewsNotifier = ValueNotifier([]); - final ValueNotifier _selectedViewNotifier = ValueNotifier(null); + final ValueNotifier> _viewsNotifier = ValueNotifier([]); + final ValueNotifier _selectedViewNotifier = ValueNotifier(null); VoidCallback? _menuSharedStateListener; ExpandableController expandController = ExpandableController(initialExpanded: false); @@ -173,7 +173,7 @@ class AppViewDataContext extends ChangeNotifier { }); } - VoidCallback addSelectedViewChangeListener(void Function(View?) callback) { + VoidCallback addSelectedViewChangeListener(void Function(ViewPB?) callback) { listener() { callback(_selectedViewNotifier.value); } @@ -186,7 +186,7 @@ class AppViewDataContext extends ChangeNotifier { _selectedViewNotifier.removeListener(listener); } - void _setLatestView(View? view) { + void _setLatestView(ViewPB? view) { view?.freeze(); if (_selectedViewNotifier.value != view) { @@ -196,9 +196,9 @@ class AppViewDataContext extends ChangeNotifier { } } - View? get selectedView => _selectedViewNotifier.value; + ViewPB? get selectedView => _selectedViewNotifier.value; - set views(List views) { + set views(List views) { if (_viewsNotifier.value != views) { _viewsNotifier.value = views; _expandIfNeed(); @@ -206,9 +206,9 @@ class AppViewDataContext extends ChangeNotifier { } } - UnmodifiableListView get views => UnmodifiableListView(_viewsNotifier.value); + UnmodifiableListView get views => UnmodifiableListView(_viewsNotifier.value); - VoidCallback addViewsChangeListener(void Function(UnmodifiableListView) callback) { + VoidCallback addViewsChangeListener(void Function(UnmodifiableListView) callback) { listener() { callback(views); } diff --git a/frontend/app_flowy/lib/workspace/application/app/app_listener.dart b/frontend/app_flowy/lib/workspace/application/app/app_listener.dart index 6a30b270af..6edf1a4df2 100644 --- a/frontend/app_flowy/lib/workspace/application/app/app_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/app/app_listener.dart @@ -10,8 +10,8 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart'; import 'package:flowy_sdk/rust_stream.dart'; -typedef AppDidUpdateCallback = void Function(App app); -typedef ViewsDidChangeCallback = void Function(Either, FlowyError> viewsOrFailed); +typedef AppDidUpdateCallback = void Function(AppPB app); +typedef ViewsDidChangeCallback = void Function(Either, FlowyError> viewsOrFailed); class AppListener { StreamSubscription? _subscription; @@ -37,7 +37,7 @@ class AppListener { if (_viewsChanged != null) { result.fold( (payload) { - final repeatedView = RepeatedView.fromBuffer(payload); + final repeatedView = RepeatedViewPB.fromBuffer(payload); _viewsChanged!(left(repeatedView.items)); }, (error) => _viewsChanged!(right(error)), @@ -48,7 +48,7 @@ class AppListener { if (_updated != null) { result.fold( (payload) { - final app = App.fromBuffer(payload); + final app = AppPB.fromBuffer(payload); _updated!(app); }, (error) => Log.error(error), diff --git a/frontend/app_flowy/lib/workspace/application/app/app_service.dart b/frontend/app_flowy/lib/workspace/application/app/app_service.dart index 51513a4032..cc75751e49 100644 --- a/frontend/app_flowy/lib/workspace/application/app/app_service.dart +++ b/frontend/app_flowy/lib/workspace/application/app/app_service.dart @@ -14,20 +14,20 @@ class AppService { required this.appId, }); - Future> getAppDesc({required String appId}) { - final payload = AppId.create()..value = appId; + Future> getAppDesc({required String appId}) { + final payload = AppIdPB.create()..value = appId; return FolderEventReadApp(payload).send(); } - Future> createView({ + Future> createView({ required String appId, required String name, required String desc, required PluginDataType dataType, required PluginType pluginType, }) { - final payload = CreateViewPayload.create() + final payload = CreateViewPayloadPB.create() ..belongToId = appId ..name = name ..desc = desc @@ -37,8 +37,8 @@ class AppService { return FolderEventCreateView(payload).send(); } - Future, FlowyError>> getViews({required String appId}) { - final payload = AppId.create()..value = appId; + Future, FlowyError>> getViews({required String appId}) { + final payload = AppIdPB.create()..value = appId; return FolderEventReadApp(payload).send().then((result) { return result.fold( @@ -49,12 +49,12 @@ class AppService { } Future> delete({required String appId}) { - final request = AppId.create()..value = appId; + final request = AppIdPB.create()..value = appId; return FolderEventDeleteApp(request).send(); } Future> updateApp({required String appId, String? name}) { - UpdateAppPayload payload = UpdateAppPayload.create()..appId = appId; + UpdateAppPayloadPB payload = UpdateAppPayloadPB.create()..appId = appId; if (name != null) { payload.name = name; @@ -67,7 +67,7 @@ class AppService { required int fromIndex, required int toIndex, }) { - final payload = MoveFolderItemPayload.create() + final payload = MoveFolderItemPayloadPB.create() ..itemId = viewId ..from = fromIndex ..to = toIndex diff --git a/frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart b/frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart index 1c77fa1cbd..8be4c40d85 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/doc_bloc.dart @@ -17,7 +17,7 @@ part 'doc_bloc.freezed.dart'; typedef FlutterQuillDocument = Document; class DocumentBloc extends Bloc { - final View view; + final ViewPB view; final DocumentService service; final ViewListener listener; diff --git a/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart b/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart index 7cf6d4412a..659a99e371 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/doc_service.dart @@ -9,7 +9,7 @@ class DocumentService { Future> openDocument({ required String docId, }) async { - await FolderEventSetLatestView(ViewId(value: docId)).send(); + await FolderEventSetLatestView(ViewIdPB(value: docId)).send(); final payload = TextBlockIdPB(value: docId); return TextBlockEventGetBlockData(payload).send(); @@ -23,7 +23,7 @@ class DocumentService { } Future> closeDocument({required String docId}) { - final request = ViewId(value: docId); + final request = ViewIdPB(value: docId); return FolderEventCloseView(request).send(); } } diff --git a/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart b/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart index a940846f5a..ba3c7676c6 100644 --- a/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/doc/share_bloc.dart @@ -13,7 +13,7 @@ part 'share_bloc.freezed.dart'; class DocShareBloc extends Bloc { ShareService service; - View view; + ViewPB view; DocShareBloc({required this.view, required this.service}) : super(const DocShareState.initial()) { on((event, emit) async { await event.map( 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 2129632338..19c4049224 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -30,7 +30,7 @@ class GridBloc extends Bloc { return rows; } - GridBloc({required View view}) + GridBloc({required ViewPB view}) : gridId = view.id, _blocks = LinkedHashMap.identity(), _gridService = GridService(gridId: view.id), diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index e270e32bac..1f8b4336fc 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -20,7 +20,7 @@ class GridService { }); Future> loadGrid() async { - await FolderEventSetLatestView(ViewId(value: gridId)).send(); + await FolderEventSetLatestView(ViewIdPB(value: gridId)).send(); final payload = GridIdPB(value: gridId); return GridEventGetGrid(payload).send(); @@ -40,7 +40,7 @@ class GridService { } Future> closeGrid() { - final request = ViewId(value: gridId); + final request = ViewIdPB(value: gridId); return FolderEventCloseView(request).send(); } } diff --git a/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart b/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart index 4b840634f5..21f29d2658 100644 --- a/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart @@ -3,7 +3,7 @@ import 'package:app_flowy/workspace/application/edit_pannel/edit_context.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart' show CurrentWorkspaceSetting; +import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart' show CurrentWorkspaceSettingPB; import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -13,7 +13,7 @@ part 'home_bloc.freezed.dart'; class HomeBloc extends Bloc { final UserWorkspaceListener _listener; - HomeBloc(UserProfile user, CurrentWorkspaceSetting workspaceSetting) + HomeBloc(UserProfile user, CurrentWorkspaceSettingPB workspaceSetting) : _listener = UserWorkspaceListener(userProfile: user), super(HomeState.initial(workspaceSetting)) { on((event, emit) async { @@ -76,7 +76,7 @@ class HomeEvent with _$HomeEvent { const factory HomeEvent.forceCollapse(bool forceCollapse) = _ForceCollapse; const factory HomeEvent.setEditPannel(EditPannelContext editContext) = _ShowEditPannel; const factory HomeEvent.dismissEditPannel() = _DismissEditPannel; - const factory HomeEvent.didReceiveWorkspaceSetting(CurrentWorkspaceSetting setting) = _DidReceiveWorkspaceSetting; + const factory HomeEvent.didReceiveWorkspaceSetting(CurrentWorkspaceSettingPB setting) = _DidReceiveWorkspaceSetting; const factory HomeEvent.unauthorized(String msg) = _Unauthorized; const factory HomeEvent.collapseMenu() = _CollapseMenu; } @@ -87,12 +87,12 @@ class HomeState with _$HomeState { required bool isLoading, required bool forceCollapse, required Option pannelContext, - required CurrentWorkspaceSetting workspaceSetting, + required CurrentWorkspaceSettingPB workspaceSetting, required bool unauthorized, required bool isMenuCollapsed, }) = _HomeState; - factory HomeState.initial(CurrentWorkspaceSetting workspaceSetting) => HomeState( + factory HomeState.initial(CurrentWorkspaceSettingPB workspaceSetting) => HomeState( isLoading: false, forceCollapse: false, pannelContext: none(), diff --git a/frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart b/frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart index b3885d7b6b..21d51f5a93 100644 --- a/frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart @@ -41,7 +41,7 @@ class MenuBloc extends Bloc { if (state.apps.length > value.fromIndex) { final app = state.apps[value.fromIndex]; _workspaceService.moveApp(appId: app.id, fromIndex: value.fromIndex, toIndex: value.toIndex); - final apps = List.from(state.apps); + final apps = List.from(state.apps); apps.insert(value.toIndex, apps.removeAt(value.fromIndex)); emit(state.copyWith(apps: apps)); } @@ -79,7 +79,7 @@ class MenuBloc extends Bloc { )); } - void _handleAppsOrFail(Either, FlowyError> appsOrFail) { + void _handleAppsOrFail(Either, FlowyError> appsOrFail) { appsOrFail.fold( (apps) => add(MenuEvent.didReceiveApps(left(apps))), (error) => add(MenuEvent.didReceiveApps(right(error))), @@ -93,13 +93,13 @@ class MenuEvent with _$MenuEvent { const factory MenuEvent.openPage(Plugin plugin) = _OpenPage; const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp; const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp; - const factory MenuEvent.didReceiveApps(Either, FlowyError> appsOrFail) = _ReceiveApps; + const factory MenuEvent.didReceiveApps(Either, FlowyError> appsOrFail) = _ReceiveApps; } @freezed class MenuState with _$MenuState { const factory MenuState({ - required List apps, + required List apps, required Either successOrFailure, required Plugin plugin, }) = _MenuState; diff --git a/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart b/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart index 7433c758b0..ce222e4eac 100644 --- a/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart @@ -65,7 +65,7 @@ class MenuUserBloc extends Bloc { ); } - void _workspaceListUpdated(Either, FlowyError> workspacesOrFailed) { + void _workspaceListUpdated(Either, FlowyError> workspacesOrFailed) { // Do nothing by now } } @@ -82,7 +82,7 @@ class MenuUserEvent with _$MenuUserEvent { class MenuUserState with _$MenuUserState { const factory MenuUserState({ required UserProfile userProfile, - required Option> workspaces, + required Option> workspaces, required Either successOrFailure, }) = _MenuUserState; diff --git a/frontend/app_flowy/lib/workspace/application/menu/menu_view_section_bloc.dart b/frontend/app_flowy/lib/workspace/application/menu/menu_view_section_bloc.dart index 6d9f4ce9ef..e70dfd179a 100644 --- a/frontend/app_flowy/lib/workspace/application/menu/menu_view_section_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/menu/menu_view_section_bloc.dart @@ -62,7 +62,7 @@ class ViewSectionBloc extends Bloc { Future _moveView(_MoveView value, Emitter emit) async { if (value.fromIndex < state.views.length) { final viewId = state.views[value.fromIndex].id; - final views = List.from(state.views); + final views = List.from(state.views); views.insert(value.toIndex, views.removeAt(value.fromIndex)); emit(state.copyWith(views: views)); @@ -92,16 +92,16 @@ class ViewSectionBloc extends Bloc { @freezed class ViewSectionEvent with _$ViewSectionEvent { const factory ViewSectionEvent.initial() = _Initial; - const factory ViewSectionEvent.setSelectedView(View? view) = _SetSelectedView; + const factory ViewSectionEvent.setSelectedView(ViewPB? view) = _SetSelectedView; const factory ViewSectionEvent.moveView(int fromIndex, int toIndex) = _MoveView; - const factory ViewSectionEvent.didReceiveViewUpdated(List views) = _DidReceiveViewUpdated; + const factory ViewSectionEvent.didReceiveViewUpdated(List views) = _DidReceiveViewUpdated; } @freezed class ViewSectionState with _$ViewSectionState { const factory ViewSectionState({ - required List views, - View? selectedView, + required List views, + ViewPB? selectedView, }) = _ViewSectionState; factory ViewSectionState.initial(AppViewDataContext appViewData) => ViewSectionState( diff --git a/frontend/app_flowy/lib/workspace/application/trash/trash_bloc.dart b/frontend/app_flowy/lib/workspace/application/trash/trash_bloc.dart index 8c83cd4d2f..a7bcf0588c 100644 --- a/frontend/app_flowy/lib/workspace/application/trash/trash_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/trash/trash_bloc.dart @@ -45,7 +45,7 @@ class TrashBloc extends Bloc { )); } - void _listenTrashUpdated(Either, FlowyError> trashOrFailed) { + void _listenTrashUpdated(Either, FlowyError> trashOrFailed) { trashOrFailed.fold( (trash) { add(TrashEvent.didReceiveTrash(trash)); @@ -66,9 +66,9 @@ class TrashBloc extends Bloc { @freezed class TrashEvent with _$TrashEvent { const factory TrashEvent.initial() = Initial; - const factory TrashEvent.didReceiveTrash(List trash) = ReceiveTrash; + const factory TrashEvent.didReceiveTrash(List trash) = ReceiveTrash; const factory TrashEvent.putback(String trashId) = Putback; - const factory TrashEvent.delete(Trash trash) = Delete; + const factory TrashEvent.delete(TrashPB trash) = Delete; const factory TrashEvent.restoreAll() = RestoreAll; const factory TrashEvent.deleteAll() = DeleteAll; } @@ -76,7 +76,7 @@ class TrashEvent with _$TrashEvent { @freezed class TrashState with _$TrashState { const factory TrashState({ - required List objects, + required List objects, required Either successOrFailure, }) = _TrashState; diff --git a/frontend/app_flowy/lib/workspace/application/trash/trash_listener.dart b/frontend/app_flowy/lib/workspace/application/trash/trash_listener.dart index 51244e23bb..0b4e142058 100644 --- a/frontend/app_flowy/lib/workspace/application/trash/trash_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/trash/trash_listener.dart @@ -8,7 +8,7 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/trash.pb.dart'; import 'package:flowy_sdk/rust_stream.dart'; -typedef TrashUpdatedCallback = void Function(Either, FlowyError> trashOrFailed); +typedef TrashUpdatedCallback = void Function(Either, FlowyError> trashOrFailed); class TrashListener { StreamSubscription? _subscription; @@ -27,7 +27,7 @@ class TrashListener { if (_trashUpdated != null) { result.fold( (payload) { - final repeatedTrash = RepeatedTrash.fromBuffer(payload); + final repeatedTrash = RepeatedTrashPB.fromBuffer(payload); _trashUpdated!(left(repeatedTrash.items)); }, (error) => _trashUpdated!(right(error)), diff --git a/frontend/app_flowy/lib/workspace/application/trash/trash_service.dart b/frontend/app_flowy/lib/workspace/application/trash/trash_service.dart index a2b6d47147..e782120a74 100644 --- a/frontend/app_flowy/lib/workspace/application/trash/trash_service.dart +++ b/frontend/app_flowy/lib/workspace/application/trash/trash_service.dart @@ -5,24 +5,24 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/trash.pb.dart'; class TrashService { - Future> readTrash() { + Future> readTrash() { return FolderEventReadTrash().send(); } Future> putback(String trashId) { - final id = TrashId.create()..id = trashId; + final id = TrashIdPB.create()..id = trashId; return FolderEventPutbackTrash(id).send(); } Future> deleteViews(List> trashList) { final items = trashList.map((trash) { - return TrashId.create() + return TrashIdPB.create() ..id = trash.value1 ..ty = trash.value2; }); - final ids = RepeatedTrashId(items: items); + final ids = RepeatedTrashIdPB(items: items); return FolderEventDeleteTrash(ids).send(); } diff --git a/frontend/app_flowy/lib/workspace/application/view/view_bloc.dart b/frontend/app_flowy/lib/workspace/application/view/view_bloc.dart index f87e863d45..bf3cfee6e3 100644 --- a/frontend/app_flowy/lib/workspace/application/view/view_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/view/view_bloc.dart @@ -11,7 +11,7 @@ part 'view_bloc.freezed.dart'; class ViewBloc extends Bloc { final ViewService service; final ViewListener listener; - final View view; + final ViewPB view; ViewBloc({ required this.view, @@ -81,18 +81,18 @@ class ViewEvent with _$ViewEvent { const factory ViewEvent.rename(String newName) = Rename; const factory ViewEvent.delete() = Delete; const factory ViewEvent.duplicate() = Duplicate; - const factory ViewEvent.viewDidUpdate(Either result) = ViewDidUpdate; + const factory ViewEvent.viewDidUpdate(Either result) = ViewDidUpdate; } @freezed class ViewState with _$ViewState { const factory ViewState({ - required View view, + required ViewPB view, required bool isEditing, required Either successOrFailure, }) = _ViewState; - factory ViewState.init(View view) => ViewState( + factory ViewState.init(ViewPB view) => ViewState( view: view, isEditing: false, successOrFailure: left(unit), diff --git a/frontend/app_flowy/lib/workspace/application/view/view_ext.dart b/frontend/app_flowy/lib/workspace/application/view/view_ext.dart index 3987226a20..a54d5ecf40 100644 --- a/frontend/app_flowy/lib/workspace/application/view/view_ext.dart +++ b/frontend/app_flowy/lib/workspace/application/view/view_ext.dart @@ -32,7 +32,7 @@ extension FlowyPluginExtension on FlowyPlugin { } } -extension ViewExtension on View { +extension ViewExtension on ViewPB { Widget renderThumbnail({Color? iconColor}) { String thumbnail = "file_icon"; diff --git a/frontend/app_flowy/lib/workspace/application/view/view_listener.dart b/frontend/app_flowy/lib/workspace/application/view/view_listener.dart index 4acb5e021f..2b080ec194 100644 --- a/frontend/app_flowy/lib/workspace/application/view/view_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/view/view_listener.dart @@ -9,9 +9,9 @@ import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart'; import 'package:flowy_sdk/rust_stream.dart'; import 'package:flowy_infra/notifier.dart'; -typedef DeleteViewNotifyValue = Either; -typedef UpdateViewNotifiedValue = Either; -typedef RestoreViewNotifiedValue = Either; +typedef DeleteViewNotifyValue = Either; +typedef UpdateViewNotifiedValue = Either; +typedef RestoreViewNotifiedValue = Either; class ViewListener { StreamSubscription? _subscription; @@ -19,7 +19,7 @@ class ViewListener { final PublishNotifier _deletedNotifier = PublishNotifier(); final PublishNotifier _restoredNotifier = PublishNotifier(); FolderNotificationParser? _parser; - View view; + ViewPB view; ViewListener({ required this.view, @@ -62,19 +62,19 @@ class ViewListener { switch (ty) { case FolderNotification.ViewUpdated: result.fold( - (payload) => _updatedViewNotifier.value = left(View.fromBuffer(payload)), + (payload) => _updatedViewNotifier.value = left(ViewPB.fromBuffer(payload)), (error) => _updatedViewNotifier.value = right(error), ); break; case FolderNotification.ViewDeleted: result.fold( - (payload) => _deletedNotifier.value = left(View.fromBuffer(payload)), + (payload) => _deletedNotifier.value = left(ViewPB.fromBuffer(payload)), (error) => _deletedNotifier.value = right(error), ); break; case FolderNotification.ViewRestored: result.fold( - (payload) => _restoredNotifier.value = left(View.fromBuffer(payload)), + (payload) => _restoredNotifier.value = left(ViewPB.fromBuffer(payload)), (error) => _restoredNotifier.value = right(error), ); break; diff --git a/frontend/app_flowy/lib/workspace/application/view/view_service.dart b/frontend/app_flowy/lib/workspace/application/view/view_service.dart index c8edd37782..b73cf25cad 100644 --- a/frontend/app_flowy/lib/workspace/application/view/view_service.dart +++ b/frontend/app_flowy/lib/workspace/application/view/view_service.dart @@ -5,13 +5,13 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; class ViewService { - Future> readView({required String viewId}) { - final request = ViewId(value: viewId); + Future> readView({required String viewId}) { + final request = ViewIdPB(value: viewId); return FolderEventReadView(request).send(); } - Future> updateView({required String viewId, String? name, String? desc}) { - final request = UpdateViewPayload.create()..viewId = viewId; + Future> updateView({required String viewId, String? name, String? desc}) { + final request = UpdateViewPayloadPB.create()..viewId = viewId; if (name != null) { request.name = name; @@ -25,12 +25,12 @@ class ViewService { } Future> delete({required String viewId}) { - final request = RepeatedViewId.create()..items.add(viewId); + final request = RepeatedViewIdPB.create()..items.add(viewId); return FolderEventDeleteView(request).send(); } Future> duplicate({required String viewId}) { - final request = ViewId(value: viewId); + final request = ViewIdPB(value: viewId); return FolderEventDuplicateView(request).send(); } } diff --git a/frontend/app_flowy/lib/workspace/application/workspace/welcome_bloc.dart b/frontend/app_flowy/lib/workspace/application/workspace/welcome_bloc.dart index dd3edb27c1..49c3ba19be 100644 --- a/frontend/app_flowy/lib/workspace/application/workspace/welcome_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/workspace/welcome_bloc.dart @@ -52,7 +52,7 @@ class WelcomeBloc extends Bloc { )); } - Future _openWorkspace(Workspace workspace, Emitter emit) async { + Future _openWorkspace(WorkspacePB workspace, Emitter emit) async { final result = await userService.openWorkspace(workspace.id); emit(result.fold( (workspaces) => state.copyWith(successOrFailure: left(unit)), @@ -82,8 +82,8 @@ class WelcomeEvent with _$WelcomeEvent { const factory WelcomeEvent.initial() = Initial; // const factory WelcomeEvent.fetchWorkspaces() = FetchWorkspace; const factory WelcomeEvent.createWorkspace(String name, String desc) = CreateWorkspace; - const factory WelcomeEvent.openWorkspace(Workspace workspace) = OpenWorkspace; - const factory WelcomeEvent.workspacesReveived(Either, FlowyError> workspacesOrFail) = + const factory WelcomeEvent.openWorkspace(WorkspacePB workspace) = OpenWorkspace; + const factory WelcomeEvent.workspacesReveived(Either, FlowyError> workspacesOrFail) = WorkspacesReceived; } @@ -91,7 +91,7 @@ class WelcomeEvent with _$WelcomeEvent { class WelcomeState with _$WelcomeState { const factory WelcomeState({ required bool isLoading, - required List workspaces, + required List workspaces, required Either successOrFailure, }) = _WelcomeState; diff --git a/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart b/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart index 1ee8de94fd..dab4d7cbcf 100644 --- a/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart @@ -9,8 +9,8 @@ import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/dart_notification.pb.dart'; -typedef AppListNotifyValue = Either, FlowyError>; -typedef WorkspaceNotifyValue = Either; +typedef AppListNotifyValue = Either, FlowyError>; +typedef WorkspaceNotifyValue = Either; class WorkspaceListener { PublishNotifier? _appsChangedNotifier = PublishNotifier(); @@ -47,13 +47,13 @@ class WorkspaceListener { switch (ty) { case FolderNotification.WorkspaceUpdated: result.fold( - (payload) => _workspaceUpdatedNotifier?.value = left(Workspace.fromBuffer(payload)), + (payload) => _workspaceUpdatedNotifier?.value = left(WorkspacePB.fromBuffer(payload)), (error) => _workspaceUpdatedNotifier?.value = right(error), ); break; case FolderNotification.WorkspaceAppsChanged: result.fold( - (payload) => _appsChangedNotifier?.value = left(RepeatedApp.fromBuffer(payload).items), + (payload) => _appsChangedNotifier?.value = left(RepeatedAppPB.fromBuffer(payload).items), (error) => _appsChangedNotifier?.value = right(error), ); break; diff --git a/frontend/app_flowy/lib/workspace/application/workspace/workspace_service.dart b/frontend/app_flowy/lib/workspace/application/workspace/workspace_service.dart index 678794b594..4f68d4776a 100644 --- a/frontend/app_flowy/lib/workspace/application/workspace/workspace_service.dart +++ b/frontend/app_flowy/lib/workspace/application/workspace/workspace_service.dart @@ -5,7 +5,7 @@ import 'package:easy_localization/easy_localization.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/app.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart' show MoveFolderItemPayload, MoveFolderItemType; +import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart' show MoveFolderItemPayloadPB, MoveFolderItemType; import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; @@ -15,16 +15,16 @@ class WorkspaceService { WorkspaceService({ required this.workspaceId, }); - Future> createApp({required String name, required String desc}) { - final payload = CreateAppPayload.create() + Future> createApp({required String name, required String desc}) { + final payload = CreateAppPayloadPB.create() ..name = name ..workspaceId = workspaceId ..desc = desc; return FolderEventCreateApp(payload).send(); } - Future> getWorkspace() { - final payload = WorkspaceId.create()..value = workspaceId; + Future> getWorkspace() { + final payload = WorkspaceIdPB.create()..value = workspaceId; return FolderEventReadWorkspaces(payload).send().then((result) { return result.fold( (workspaces) { @@ -41,8 +41,8 @@ class WorkspaceService { }); } - Future, FlowyError>> getApps() { - final payload = WorkspaceId.create()..value = workspaceId; + Future, FlowyError>> getApps() { + final payload = WorkspaceIdPB.create()..value = workspaceId; return FolderEventReadWorkspaceApps(payload).send().then((result) { return result.fold( (apps) => left(apps.items), @@ -56,7 +56,7 @@ class WorkspaceService { required int fromIndex, required int toIndex, }) { - final payload = MoveFolderItemPayload.create() + final payload = MoveFolderItemPayloadPB.create() ..itemId = appId ..from = fromIndex ..to = toIndex diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart index f205daabac..a9aa15a77a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart @@ -19,7 +19,7 @@ import 'menu/menu.dart'; class HomeScreen extends StatefulWidget { final UserProfile user; - final CurrentWorkspaceSetting workspaceSetting; + final CurrentWorkspaceSettingPB workspaceSetting; const HomeScreen(this.user, this.workspaceSetting, {Key? key}) : super(key: key); @override @@ -27,7 +27,7 @@ class HomeScreen extends StatefulWidget { } class _HomeScreenState extends State { - View? initialView; + ViewPB? initialView; @override void initState() { diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart index 2d26aabc0b..dbeb2248cc 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/header.dart @@ -19,7 +19,7 @@ import 'add_button.dart'; import 'right_click_action.dart'; class MenuAppHeader extends StatelessWidget { - final App app; + final AppPB app; const MenuAppHeader( this.app, { Key? key, @@ -85,7 +85,7 @@ class MenuAppHeader extends StatelessWidget { anchorDirection: AnchorDirection.bottomWithCenterAligned, ); }, - child: BlocSelector( + child: BlocSelector( selector: (state) => state.app, builder: (context, app) => FlowyText.medium( app.name, diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart index 462ce1ba8a..e636c87d9a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart @@ -10,7 +10,7 @@ import 'package:provider/provider.dart'; import 'section/section.dart'; class MenuApp extends StatefulWidget { - final App app; + final AppPB app; const MenuApp(this.app, {Key? key}) : super(key: key); @override diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart index f5de13892f..97ae1dae52 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart @@ -21,8 +21,8 @@ import 'disclosure_action.dart'; // ignore: must_be_immutable class ViewSectionItem extends StatelessWidget { final bool isSelected; - final View view; - final void Function(View) onSelected; + final ViewPB view; + final void Function(ViewPB) onSelected; ViewSectionItem({ Key? key, diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart index 01debf6196..529441df82 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart @@ -33,7 +33,7 @@ import 'menu_user.dart'; class HomeMenu extends StatelessWidget { final PublishNotifier _collapsedNotifier; final UserProfile user; - final CurrentWorkspaceSetting workspaceSetting; + final CurrentWorkspaceSettingPB workspaceSetting; const HomeMenu({ Key? key, @@ -155,19 +155,19 @@ class HomeMenu extends StatelessWidget { } class MenuSharedState { - final ValueNotifier _latestOpenView = ValueNotifier(null); + final ValueNotifier _latestOpenView = ValueNotifier(null); - MenuSharedState({View? view}) { + MenuSharedState({ViewPB? view}) { _latestOpenView.value = view; } - View? get latestOpenView => _latestOpenView.value; + ViewPB? get latestOpenView => _latestOpenView.value; - set latestOpenView(View? view) { + set latestOpenView(ViewPB? view) { _latestOpenView.value = view; } - VoidCallback addLatestViewListener(void Function(View?) callback) { + VoidCallback addLatestViewListener(void Function(ViewPB?) callback) { listener() { callback(_latestOpenView.value); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/board/board.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/board/board.dart index b8692168c6..ab58176e50 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/board/board.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/board/board.dart @@ -9,7 +9,7 @@ import 'src/board_page.dart'; class BoardPluginBuilder implements PluginBuilder { @override Plugin build(dynamic data) { - if (data is View) { + if (data is ViewPB) { return BoardPlugin(pluginType: pluginType, view: data); } else { throw FlowyPluginException.invalidData; @@ -32,11 +32,11 @@ class BoardPluginConfig implements PluginConfig { } class BoardPlugin extends Plugin { - final View _view; + final ViewPB _view; final PluginType _pluginType; BoardPlugin({ - required View view, + required ViewPB view, required PluginType pluginType, }) : _pluginType = pluginType, _view = view; @@ -52,8 +52,8 @@ class BoardPlugin extends Plugin { } class GridPluginDisplay extends PluginDisplay { - final View _view; - GridPluginDisplay({required View view, Key? key}) : _view = view; + final ViewPB _view; + GridPluginDisplay({required ViewPB view, Key? key}) : _view = view; @override Widget get leftBarItem => ViewLeftBarItem(view: _view); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/board/src/board_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/board/src/board_page.dart index 1cdfea5480..612e7c6770 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/board/src/board_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/board/src/board_page.dart @@ -4,9 +4,9 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flutter/material.dart'; class BoardPage extends StatelessWidget { - final View _view; + final ViewPB _view; - const BoardPage({required View view, Key? key}) + const BoardPage({required ViewPB view, Key? key}) : _view = view, super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart index f5376f52fc..c09843873d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart @@ -36,7 +36,7 @@ export './src/widget/toolbar/toolbar_icon_button.dart'; class DocumentPluginBuilder extends PluginBuilder { @override Plugin build(dynamic data) { - if (data is View) { + if (data is ViewPB) { return DocumentPlugin(pluginType: pluginType, view: data); } else { throw FlowyPluginException.invalidData; @@ -54,11 +54,11 @@ class DocumentPluginBuilder extends PluginBuilder { } class DocumentPlugin implements Plugin { - late View _view; + late ViewPB _view; ViewListener? _listener; late PluginType _pluginType; - DocumentPlugin({required PluginType pluginType, required View view, Key? key}) : _view = view { + DocumentPlugin({required PluginType pluginType, required ViewPB view, Key? key}) : _view = view { _pluginType = pluginType; _listener = getIt(param1: view); _listener?.start(onViewUpdated: (result) { @@ -90,9 +90,9 @@ class DocumentPlugin implements Plugin { class DocumentPluginDisplay extends PluginDisplay with NavigationItem { final PublishNotifier _displayNotifier = PublishNotifier(); - final View _view; + final ViewPB _view; - DocumentPluginDisplay({required View view, Key? key}) : _view = view; + DocumentPluginDisplay({required ViewPB view, Key? key}) : _view = view; @override Widget buildWidget() => DocumentPage(view: _view, key: ValueKey(_view.id)); @@ -111,7 +111,7 @@ class DocumentPluginDisplay extends PluginDisplay with NavigationItem { } class DocumentShareButton extends StatelessWidget { - final View view; + final ViewPB view; DocumentShareButton({Key? key, required this.view}) : super(key: ValueKey(view.hashCode)); @override diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart index a02289a555..3598c5a5ac 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart @@ -14,7 +14,7 @@ import 'styles.dart'; import 'widget/banner.dart'; class DocumentPage extends StatefulWidget { - final View view; + final ViewPB view; DocumentPage({Key? key, required this.view}) : super(key: ValueKey(view.id)); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart index da634d8833..776dd833ea 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart @@ -11,7 +11,7 @@ import 'src/grid_page.dart'; class GridPluginBuilder implements PluginBuilder { @override Plugin build(dynamic data) { - if (data is View) { + if (data is ViewPB) { return GridPlugin(pluginType: pluginType, view: data); } else { throw FlowyPluginException.invalidData; @@ -34,11 +34,11 @@ class GridPluginConfig implements PluginConfig { } class GridPlugin extends Plugin { - final View _view; + final ViewPB _view; final PluginType _pluginType; GridPlugin({ - required View view, + required ViewPB view, required PluginType pluginType, }) : _pluginType = pluginType, _view = view; @@ -54,8 +54,8 @@ class GridPlugin extends Plugin { } class GridPluginDisplay extends PluginDisplay { - final View _view; - GridPluginDisplay({required View view, Key? key}) : _view = view; + final ViewPB _view; + GridPluginDisplay({required ViewPB view, Key? key}) : _view = view; @override Widget get leftBarItem => ViewLeftBarItem(view: _view); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index 2ec27f3f3c..82b13867a4 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -19,7 +19,7 @@ import 'widgets/shortcuts.dart'; import 'widgets/toolbar/grid_toolbar.dart'; class GridPage extends StatefulWidget { - final View view; + final ViewPB view; GridPage({Key? key, required this.view}) : super(key: ValueKey(view.id)); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/src/trash_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/src/trash_cell.dart index 92b1f61cd0..4d6604e4af 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/src/trash_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/src/trash_cell.dart @@ -14,7 +14,7 @@ import 'sizes.dart'; class TrashCell extends StatelessWidget { final VoidCallback onRestore; final VoidCallback onDelete; - final Trash object; + final TrashPB object; const TrashCell({required this.object, required this.onRestore, required this.onDelete, Key? key}) : super(key: key); @override diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/trash.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/trash.dart index 324b676fc3..e098eddf96 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/trash/trash.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/trash/trash.dart @@ -31,7 +31,7 @@ class TrashPluginBuilder extends PluginBuilder { } @override - String get menuName => "Trash"; + String get menuName => "TrashPB"; @override PluginType get pluginType => DefaultPlugin.trash.type(); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart index bd9f1441e8..0d06ec56ce 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class ViewLeftBarItem extends StatefulWidget { - final View view; + final ViewPB view; ViewLeftBarItem({required this.view, Key? key}) : super(key: ValueKey(view.hashCode)); @@ -20,7 +20,7 @@ class _ViewLeftBarItemState extends State { final _focusNode = FocusNode(); late ViewService _viewService; late ViewListener _viewListener; - late View view; + late ViewPB view; @override void initState() { diff --git a/frontend/rust-lib/flowy-folder/src/entities/app.rs b/frontend/rust-lib/flowy-folder/src/entities/app.rs index 1c705d5b0e..3a5dc3099e 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/app.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/app.rs @@ -3,7 +3,7 @@ use crate::{ app::{AppColorStyle, AppIdentify, AppName}, workspace::WorkspaceIdentify, }, - entities::view::RepeatedView, + entities::view::RepeatedViewPB, errors::ErrorCode, impl_def_and_def_mut, }; @@ -12,7 +12,7 @@ use flowy_folder_data_model::revision::AppRevision; use std::convert::TryInto; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct App { +pub struct AppPB { #[pb(index = 1)] pub id: String, @@ -26,7 +26,7 @@ pub struct App { pub desc: String, #[pb(index = 5)] - pub belongings: RepeatedView, + pub belongings: RepeatedViewPB, #[pb(index = 6)] pub version: i64, @@ -38,9 +38,9 @@ pub struct App { pub create_time: i64, } -impl std::convert::From for App { +impl std::convert::From for AppPB { fn from(app_serde: AppRevision) -> Self { - App { + AppPB { id: app_serde.id, workspace_id: app_serde.workspace_id, name: app_serde.name, @@ -53,21 +53,21 @@ impl std::convert::From for App { } } #[derive(Eq, PartialEq, Debug, Default, ProtoBuf, Clone)] -pub struct RepeatedApp { +pub struct RepeatedAppPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl_def_and_def_mut!(RepeatedApp, App); +impl_def_and_def_mut!(RepeatedAppPB, AppPB); -impl std::convert::From> for RepeatedApp { +impl std::convert::From> for RepeatedAppPB { fn from(values: Vec) -> Self { - let items = values.into_iter().map(|value| value.into()).collect::>(); - RepeatedApp { items } + let items = values.into_iter().map(|value| value.into()).collect::>(); + RepeatedAppPB { items } } } #[derive(ProtoBuf, Default)] -pub struct CreateAppPayload { +pub struct CreateAppPayloadPB { #[pb(index = 1)] pub workspace_id: String, @@ -78,31 +78,24 @@ pub struct CreateAppPayload { pub desc: String, #[pb(index = 4)] - pub color_style: ColorStyle, + pub color_style: ColorStylePB, } #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct ColorStyle { +pub struct ColorStylePB { #[pb(index = 1)] pub theme_color: String, } -#[derive(ProtoBuf, Default, Debug)] +#[derive(Debug)] pub struct CreateAppParams { - #[pb(index = 1)] pub workspace_id: String, - - #[pb(index = 2)] pub name: String, - - #[pb(index = 3)] pub desc: String, - - #[pb(index = 4)] - pub color_style: ColorStyle, + pub color_style: ColorStylePB, } -impl TryInto for CreateAppPayload { +impl TryInto for CreateAppPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -119,21 +112,21 @@ impl TryInto for CreateAppPayload { } } -impl std::convert::From for ColorStyle { +impl std::convert::From for ColorStylePB { fn from(data: AppColorStyle) -> Self { - ColorStyle { + ColorStylePB { theme_color: data.theme_color, } } } #[derive(ProtoBuf, Default, Clone, Debug)] -pub struct AppId { +pub struct AppIdPB { #[pb(index = 1)] pub value: String, } -impl AppId { +impl AppIdPB { pub fn new(app_id: &str) -> Self { Self { value: app_id.to_string(), @@ -142,7 +135,7 @@ impl AppId { } #[derive(ProtoBuf, Default)] -pub struct UpdateAppPayload { +pub struct UpdateAppPayloadPB { #[pb(index = 1)] pub app_id: String, @@ -153,27 +146,22 @@ pub struct UpdateAppPayload { pub desc: Option, #[pb(index = 4, one_of)] - pub color_style: Option, + pub color_style: Option, #[pb(index = 5, one_of)] pub is_trash: Option, } -#[derive(ProtoBuf, Default, Clone, Debug)] +#[derive(Debug, Clone)] pub struct UpdateAppParams { - #[pb(index = 1)] pub app_id: String, - #[pb(index = 2, one_of)] pub name: Option, - #[pb(index = 3, one_of)] pub desc: Option, - #[pb(index = 4, one_of)] - pub color_style: Option, + pub color_style: Option, - #[pb(index = 5, one_of)] pub is_trash: Option, } @@ -181,7 +169,10 @@ impl UpdateAppParams { pub fn new(app_id: &str) -> Self { Self { app_id: app_id.to_string(), - ..Default::default() + name: None, + desc: None, + color_style: None, + is_trash: None, } } @@ -201,7 +192,7 @@ impl UpdateAppParams { } } -impl TryInto for UpdateAppPayload { +impl TryInto for UpdateAppPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-folder/src/entities/trash.rs b/frontend/rust-lib/flowy-folder/src/entities/trash.rs index c332dded18..15358ba3e5 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/trash.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/trash.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::Formatter; #[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone)] -pub struct Trash { +pub struct TrashPB { #[pb(index = 1)] pub id: String, @@ -22,9 +22,9 @@ pub struct Trash { pub ty: TrashType, } -impl std::convert::From for Trash { +impl std::convert::From for TrashPB { fn from(trash_rev: TrashRevision) -> Self { - Trash { + TrashPB { id: trash_rev.id, name: trash_rev.name, modified_time: trash_rev.modified_time, @@ -34,8 +34,8 @@ impl std::convert::From for Trash { } } -impl std::convert::From for TrashRevision { - fn from(trash: Trash) -> Self { +impl std::convert::From for TrashRevision { + fn from(trash: TrashPB) -> Self { TrashRevision { id: trash.id, name: trash.name, @@ -46,16 +46,16 @@ impl std::convert::From for TrashRevision { } } #[derive(PartialEq, Debug, Default, ProtoBuf, Clone)] -pub struct RepeatedTrash { +pub struct RepeatedTrashPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl_def_and_def_mut!(RepeatedTrash, Trash); -impl std::convert::From> for RepeatedTrash { +impl_def_and_def_mut!(RepeatedTrashPB, TrashPB); +impl std::convert::From> for RepeatedTrashPB { fn from(trash_revs: Vec) -> Self { - let items: Vec = trash_revs.into_iter().map(|trash_rev| trash_rev.into()).collect(); - RepeatedTrash { items } + let items: Vec = trash_revs.into_iter().map(|trash_rev| trash_rev.into()).collect(); + RepeatedTrashPB { items } } } @@ -106,15 +106,15 @@ impl std::default::Default for TrashType { } #[derive(PartialEq, ProtoBuf, Default, Debug, Clone)] -pub struct RepeatedTrashId { +pub struct RepeatedTrashIdPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, #[pb(index = 2)] pub delete_all: bool, } -impl std::fmt::Display for RepeatedTrashId { +impl std::fmt::Display for RepeatedTrashIdPB { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&format!( "{:?}", @@ -123,35 +123,35 @@ impl std::fmt::Display for RepeatedTrashId { } } -impl RepeatedTrashId { - pub fn all() -> RepeatedTrashId { - RepeatedTrashId { +impl RepeatedTrashIdPB { + pub fn all() -> RepeatedTrashIdPB { + RepeatedTrashIdPB { items: vec![], delete_all: true, } } } -impl std::convert::From> for RepeatedTrashId { - fn from(items: Vec) -> Self { - RepeatedTrashId { +impl std::convert::From> for RepeatedTrashIdPB { + fn from(items: Vec) -> Self { + RepeatedTrashIdPB { items, delete_all: false, } } } -impl std::convert::From> for RepeatedTrashId { +impl std::convert::From> for RepeatedTrashIdPB { fn from(trash: Vec) -> Self { let items = trash .into_iter() - .map(|t| TrashId { + .map(|t| TrashIdPB { id: t.id, ty: t.ty.into(), }) .collect::>(); - RepeatedTrashId { + RepeatedTrashIdPB { items, delete_all: false, } @@ -159,7 +159,7 @@ impl std::convert::From> for RepeatedTrashId { } #[derive(PartialEq, ProtoBuf, Default, Debug, Clone)] -pub struct TrashId { +pub struct TrashIdPB { #[pb(index = 1)] pub id: String, @@ -167,15 +167,15 @@ pub struct TrashId { pub ty: TrashType, } -impl std::fmt::Display for TrashId { +impl std::fmt::Display for TrashIdPB { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&format!("{:?}:{}", self.ty, self.id)) } } -impl std::convert::From<&TrashRevision> for TrashId { +impl std::convert::From<&TrashRevision> for TrashIdPB { fn from(trash: &TrashRevision) -> Self { - TrashId { + TrashIdPB { id: trash.id.clone(), ty: trash.ty.clone().into(), } diff --git a/frontend/rust-lib/flowy-folder/src/entities/view.rs b/frontend/rust-lib/flowy-folder/src/entities/view.rs index ca54ec8cff..8f3a26c8fd 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/view.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/view.rs @@ -11,7 +11,7 @@ use flowy_folder_data_model::revision::{gen_view_id, ViewDataTypeRevision, ViewR use std::convert::TryInto; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct View { +pub struct ViewPB { #[pb(index = 1)] pub id: String, @@ -34,9 +34,9 @@ pub struct View { pub plugin_type: i32, } -impl std::convert::From for View { +impl std::convert::From for ViewPB { fn from(rev: ViewRevision) -> Self { - View { + ViewPB { id: rev.id, belong_to_id: rev.belong_to_id, name: rev.name, @@ -79,27 +79,27 @@ impl std::convert::From for ViewDataTypeRevision { } #[derive(Eq, PartialEq, Debug, Default, ProtoBuf, Clone)] -pub struct RepeatedView { +pub struct RepeatedViewPB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl_def_and_def_mut!(RepeatedView, View); +impl_def_and_def_mut!(RepeatedViewPB, ViewPB); -impl std::convert::From> for RepeatedView { +impl std::convert::From> for RepeatedViewPB { fn from(values: Vec) -> Self { - let items = values.into_iter().map(|value| value.into()).collect::>(); - RepeatedView { items } + let items = values.into_iter().map(|value| value.into()).collect::>(); + RepeatedViewPB { items } } } #[derive(Default, ProtoBuf)] -pub struct RepeatedViewId { +pub struct RepeatedViewIdPB { #[pb(index = 1)] pub items: Vec, } #[derive(Default, ProtoBuf)] -pub struct CreateViewPayload { +pub struct CreateViewPayloadPB { #[pb(index = 1)] pub belong_to_id: String, @@ -122,34 +122,19 @@ pub struct CreateViewPayload { pub data: Vec, } -#[derive(Default, ProtoBuf, Debug, Clone)] +#[derive(Debug, Clone)] pub struct CreateViewParams { - #[pb(index = 1)] pub belong_to_id: String, - - #[pb(index = 2)] pub name: String, - - #[pb(index = 3)] pub desc: String, - - #[pb(index = 4)] pub thumbnail: String, - - #[pb(index = 5)] pub data_type: ViewDataType, - - #[pb(index = 6)] pub view_id: String, - - #[pb(index = 7)] pub data: Vec, - - #[pb(index = 8)] pub plugin_type: i32, } -impl TryInto for CreateViewPayload { +impl TryInto for CreateViewPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -175,20 +160,20 @@ impl TryInto for CreateViewPayload { } #[derive(Default, ProtoBuf, Clone, Debug)] -pub struct ViewId { +pub struct ViewIdPB { #[pb(index = 1)] pub value: String, } -impl std::convert::From<&str> for ViewId { +impl std::convert::From<&str> for ViewIdPB { fn from(value: &str) -> Self { - ViewId { + ViewIdPB { value: value.to_string(), } } } -impl std::ops::Deref for ViewId { +impl std::ops::Deref for ViewIdPB { type Target = str; fn deref(&self) -> &Self::Target { @@ -197,7 +182,7 @@ impl std::ops::Deref for ViewId { } #[derive(Default, ProtoBuf)] -pub struct UpdateViewPayload { +pub struct UpdateViewPayloadPB { #[pb(index = 1)] pub view_id: String, @@ -211,22 +196,15 @@ pub struct UpdateViewPayload { pub thumbnail: Option, } -#[derive(Default, ProtoBuf, Clone, Debug)] +#[derive(Clone, Debug)] pub struct UpdateViewParams { - #[pb(index = 1)] pub view_id: String, - - #[pb(index = 2, one_of)] pub name: Option, - - #[pb(index = 3, one_of)] pub desc: Option, - - #[pb(index = 4, one_of)] pub thumbnail: Option, } -impl TryInto for UpdateViewPayload { +impl TryInto for UpdateViewPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -269,7 +247,7 @@ impl std::default::Default for MoveFolderItemType { } #[derive(Default, ProtoBuf)] -pub struct MoveFolderItemPayload { +pub struct MoveFolderItemPayloadPB { #[pb(index = 1)] pub item_id: String, @@ -290,7 +268,7 @@ pub struct MoveFolderItemParams { pub ty: MoveFolderItemType, } -impl TryInto for MoveFolderItemPayload { +impl TryInto for MoveFolderItemPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-folder/src/entities/view_info.rs b/frontend/rust-lib/flowy-folder/src/entities/view_info.rs index a772396e9f..92ec785821 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/view_info.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/view_info.rs @@ -1,8 +1,8 @@ -use crate::entities::{RepeatedView, ViewDataType}; +use crate::entities::{RepeatedViewPB, ViewDataType}; use flowy_derive::ProtoBuf; #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] -pub struct ViewInfo { +pub struct ViewInfoPB { #[pb(index = 1)] pub id: String, @@ -19,7 +19,7 @@ pub struct ViewInfo { pub data_type: ViewDataType, #[pb(index = 6)] - pub belongings: RepeatedView, + pub belongings: RepeatedViewPB, #[pb(index = 7)] pub ext_data: String, diff --git a/frontend/rust-lib/flowy-folder/src/entities/workspace.rs b/frontend/rust-lib/flowy-folder/src/entities/workspace.rs index a9f61b50c8..20c9750940 100644 --- a/frontend/rust-lib/flowy-folder/src/entities/workspace.rs +++ b/frontend/rust-lib/flowy-folder/src/entities/workspace.rs @@ -1,6 +1,6 @@ use crate::{ entities::parser::workspace::{WorkspaceDesc, WorkspaceIdentify, WorkspaceName}, - entities::{app::RepeatedApp, view::View}, + entities::{app::RepeatedAppPB, view::ViewPB}, errors::*, impl_def_and_def_mut, }; @@ -9,7 +9,7 @@ use flowy_folder_data_model::revision::WorkspaceRevision; use std::convert::TryInto; #[derive(Eq, PartialEq, ProtoBuf, Default, Debug, Clone)] -pub struct Workspace { +pub struct WorkspacePB { #[pb(index = 1)] pub id: String, @@ -20,7 +20,7 @@ pub struct Workspace { pub desc: String, #[pb(index = 4)] - pub apps: RepeatedApp, + pub apps: RepeatedAppPB, #[pb(index = 5)] pub modified_time: i64, @@ -29,9 +29,9 @@ pub struct Workspace { pub create_time: i64, } -impl std::convert::From for Workspace { +impl std::convert::From for WorkspacePB { fn from(workspace_serde: WorkspaceRevision) -> Self { - Workspace { + WorkspacePB { id: workspace_serde.id, name: workspace_serde.name, desc: workspace_serde.desc, @@ -42,15 +42,15 @@ impl std::convert::From for Workspace { } } #[derive(PartialEq, Debug, Default, ProtoBuf)] -pub struct RepeatedWorkspace { +pub struct RepeatedWorkspacePB { #[pb(index = 1)] - pub items: Vec, + pub items: Vec, } -impl_def_and_def_mut!(RepeatedWorkspace, Workspace); +impl_def_and_def_mut!(RepeatedWorkspacePB, WorkspacePB); #[derive(ProtoBuf, Default)] -pub struct CreateWorkspacePayload { +pub struct CreateWorkspacePayloadPB { #[pb(index = 1)] pub name: String, @@ -58,16 +58,13 @@ pub struct CreateWorkspacePayload { pub desc: String, } -#[derive(Clone, ProtoBuf, Default, Debug)] +#[derive(Clone, Debug)] pub struct CreateWorkspaceParams { - #[pb(index = 1)] pub name: String, - - #[pb(index = 2)] pub desc: String, } -impl TryInto for CreateWorkspacePayload { +impl TryInto for CreateWorkspacePayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -83,28 +80,28 @@ impl TryInto for CreateWorkspacePayload { // Read all workspaces if the workspace_id is None #[derive(Clone, ProtoBuf, Default, Debug)] -pub struct WorkspaceId { +pub struct WorkspaceIdPB { #[pb(index = 1, one_of)] pub value: Option, } -impl WorkspaceId { +impl WorkspaceIdPB { pub fn new(workspace_id: Option) -> Self { Self { value: workspace_id } } } #[derive(Default, ProtoBuf, Clone)] -pub struct CurrentWorkspaceSetting { +pub struct CurrentWorkspaceSettingPB { #[pb(index = 1)] - pub workspace: Workspace, + pub workspace: WorkspacePB, #[pb(index = 2, one_of)] - pub latest_view: Option, + pub latest_view: Option, } #[derive(ProtoBuf, Default)] -pub struct UpdateWorkspaceRequest { +pub struct UpdateWorkspacePayloadPB { #[pb(index = 1)] pub id: String, @@ -115,19 +112,14 @@ pub struct UpdateWorkspaceRequest { pub desc: Option, } -#[derive(Clone, ProtoBuf, Default, Debug)] +#[derive(Clone, Debug)] pub struct UpdateWorkspaceParams { - #[pb(index = 1)] pub id: String, - - #[pb(index = 2, one_of)] pub name: Option, - - #[pb(index = 3, one_of)] pub desc: Option, } -impl TryInto for UpdateWorkspaceRequest { +impl TryInto for UpdateWorkspacePayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-folder/src/event_map.rs b/frontend/rust-lib/flowy-folder/src/event_map.rs index abb168b5e3..71e436b848 100644 --- a/frontend/rust-lib/flowy-folder/src/event_map.rs +++ b/frontend/rust-lib/flowy-folder/src/event_map.rs @@ -1,9 +1,9 @@ use crate::{ entities::{ - app::{AppId, CreateAppParams, UpdateAppParams}, - trash::RepeatedTrashId, - view::{CreateViewParams, RepeatedViewId, UpdateViewParams, ViewId}, - workspace::{CreateWorkspaceParams, UpdateWorkspaceParams, WorkspaceId}, + app::{AppIdPB, CreateAppParams, UpdateAppParams}, + trash::RepeatedTrashIdPB, + view::{CreateViewParams, RepeatedViewIdPB, UpdateViewParams, ViewIdPB}, + workspace::{CreateWorkspaceParams, UpdateWorkspaceParams, WorkspaceIdPB}, }, errors::FlowyError, manager::FolderManager, @@ -84,73 +84,73 @@ pub fn create(folder: Arc) -> Module { #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] #[event_err = "FlowyError"] pub enum FolderEvent { - #[event(input = "CreateWorkspacePayload", output = "Workspace")] + #[event(input = "CreateWorkspacePayloadPB", output = "WorkspacePB")] CreateWorkspace = 0, - #[event(output = "CurrentWorkspaceSetting")] + #[event(output = "CurrentWorkspaceSettingPB")] ReadCurWorkspace = 1, - #[event(input = "WorkspaceId", output = "RepeatedWorkspace")] + #[event(input = "WorkspaceIdPB", output = "RepeatedWorkspacePB")] ReadWorkspaces = 2, - #[event(input = "WorkspaceId")] + #[event(input = "WorkspaceIdPB")] DeleteWorkspace = 3, - #[event(input = "WorkspaceId", output = "Workspace")] + #[event(input = "WorkspaceIdPB", output = "WorkspacePB")] OpenWorkspace = 4, - #[event(input = "WorkspaceId", output = "RepeatedApp")] + #[event(input = "WorkspaceIdPB", output = "RepeatedAppPB")] ReadWorkspaceApps = 5, - #[event(input = "CreateAppPayload", output = "App")] + #[event(input = "CreateAppPayloadPB", output = "AppPB")] CreateApp = 101, - #[event(input = "AppId")] + #[event(input = "AppIdPB")] DeleteApp = 102, - #[event(input = "AppId", output = "App")] + #[event(input = "AppIdPB", output = "AppPB")] ReadApp = 103, - #[event(input = "UpdateAppPayload")] + #[event(input = "UpdateAppPayloadPB")] UpdateApp = 104, - #[event(input = "CreateViewPayload", output = "View")] + #[event(input = "CreateViewPayloadPB", output = "ViewPB")] CreateView = 201, - #[event(input = "ViewId", output = "View")] + #[event(input = "ViewIdPB", output = "ViewPB")] ReadView = 202, - #[event(input = "UpdateViewPayload", output = "View")] + #[event(input = "UpdateViewPayloadPB", output = "ViewPB")] UpdateView = 203, - #[event(input = "RepeatedViewId")] + #[event(input = "RepeatedViewIdPB")] DeleteView = 204, - #[event(input = "ViewId")] + #[event(input = "ViewIdPB")] DuplicateView = 205, - #[event(input = "ViewId")] + #[event(input = "ViewIdPB")] CloseView = 206, - #[event(input = "ViewId", output = "ViewInfo")] + #[event(input = "ViewIdPB", output = "ViewInfoPB")] ReadViewInfo = 207, #[event()] CopyLink = 220, - #[event(input = "ViewId")] + #[event(input = "ViewIdPB")] SetLatestView = 221, - #[event(input = "MoveFolderItemPayload")] + #[event(input = "MoveFolderItemPayloadPB")] MoveFolderItem = 230, - #[event(output = "RepeatedTrash")] + #[event(output = "RepeatedTrashPB")] ReadTrash = 300, - #[event(input = "TrashId")] + #[event(input = "TrashIdPB")] PutbackTrash = 301, - #[event(input = "RepeatedTrashId")] + #[event(input = "RepeatedTrashIdPB")] DeleteTrash = 302, #[event()] @@ -170,34 +170,34 @@ pub trait FolderCouldServiceV1: Send + Sync { params: CreateWorkspaceParams, ) -> FutureResult; - fn read_workspace(&self, token: &str, params: WorkspaceId) -> FutureResult, FlowyError>; + fn read_workspace(&self, token: &str, params: WorkspaceIdPB) -> FutureResult, FlowyError>; fn update_workspace(&self, token: &str, params: UpdateWorkspaceParams) -> FutureResult<(), FlowyError>; - fn delete_workspace(&self, token: &str, params: WorkspaceId) -> FutureResult<(), FlowyError>; + fn delete_workspace(&self, token: &str, params: WorkspaceIdPB) -> FutureResult<(), FlowyError>; // View fn create_view(&self, token: &str, params: CreateViewParams) -> FutureResult; - fn read_view(&self, token: &str, params: ViewId) -> FutureResult, FlowyError>; + fn read_view(&self, token: &str, params: ViewIdPB) -> FutureResult, FlowyError>; - fn delete_view(&self, token: &str, params: RepeatedViewId) -> FutureResult<(), FlowyError>; + fn delete_view(&self, token: &str, params: RepeatedViewIdPB) -> FutureResult<(), FlowyError>; fn update_view(&self, token: &str, params: UpdateViewParams) -> FutureResult<(), FlowyError>; // App fn create_app(&self, token: &str, params: CreateAppParams) -> FutureResult; - fn read_app(&self, token: &str, params: AppId) -> FutureResult, FlowyError>; + fn read_app(&self, token: &str, params: AppIdPB) -> FutureResult, FlowyError>; fn update_app(&self, token: &str, params: UpdateAppParams) -> FutureResult<(), FlowyError>; - fn delete_app(&self, token: &str, params: AppId) -> FutureResult<(), FlowyError>; + fn delete_app(&self, token: &str, params: AppIdPB) -> FutureResult<(), FlowyError>; // Trash - fn create_trash(&self, token: &str, params: RepeatedTrashId) -> FutureResult<(), FlowyError>; + fn create_trash(&self, token: &str, params: RepeatedTrashIdPB) -> FutureResult<(), FlowyError>; - fn delete_trash(&self, token: &str, params: RepeatedTrashId) -> FutureResult<(), FlowyError>; + fn delete_trash(&self, token: &str, params: RepeatedTrashIdPB) -> FutureResult<(), FlowyError>; fn read_trash(&self, token: &str) -> FutureResult, FlowyError>; } diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index b6555035d3..826006e98c 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -1,7 +1,7 @@ use crate::entities::view::ViewDataType; use crate::{ dart_notification::{send_dart_notification, FolderNotification}, - entities::workspace::RepeatedWorkspace, + entities::workspace::RepeatedWorkspacePB, errors::FlowyResult, event_map::{FolderCouldServiceV1, WorkspaceDatabase, WorkspaceUser}, services::{ @@ -216,7 +216,7 @@ impl DefaultFolderBuilder { let folder = FolderPad::new(vec![workspace_rev.clone()], vec![])?; let folder_id = FolderId::new(user_id); let _ = persistence.save_folder(user_id, &folder_id, folder).await?; - let repeated_workspace = RepeatedWorkspace { + let repeated_workspace = RepeatedWorkspacePB { items: vec![workspace_rev.into()], }; send_dart_notification(token, FolderNotification::UserCreateWorkspace) diff --git a/frontend/rust-lib/flowy-folder/src/services/app/controller.rs b/frontend/rust-lib/flowy-folder/src/services/app/controller.rs index 481af85ccd..112ad052ce 100644 --- a/frontend/rust-lib/flowy-folder/src/services/app/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/app/controller.rs @@ -1,7 +1,7 @@ use crate::{ dart_notification::*, entities::{ - app::{App, CreateAppParams, *}, + app::{AppPB, CreateAppParams, *}, trash::TrashType, }, errors::*, @@ -44,12 +44,12 @@ impl AppController { } #[tracing::instrument(level = "debug", skip(self, params), fields(name = %params.name) err)] - pub(crate) async fn create_app_from_params(&self, params: CreateAppParams) -> Result { + pub(crate) async fn create_app_from_params(&self, params: CreateAppParams) -> Result { let app = self.create_app_on_server(params).await?; self.create_app_on_local(app).await } - pub(crate) async fn create_app_on_local(&self, app: AppRevision) -> Result { + pub(crate) async fn create_app_on_local(&self, app: AppRevision) -> Result { let _ = self .persistence .begin_transaction(|transaction| { @@ -61,7 +61,7 @@ impl AppController { Ok(app.into()) } - pub(crate) async fn read_app(&self, params: AppId) -> Result { + pub(crate) async fn read_app(&self, params: AppIdPB) -> Result { let app = self .persistence .begin_transaction(|transaction| { @@ -81,7 +81,7 @@ impl AppController { let changeset = AppChangeset::new(params.clone()); let app_id = changeset.id.clone(); - let app: App = self + let app: AppPB = self .persistence .begin_transaction(|transaction| { let _ = transaction.update_app(changeset)?; @@ -150,7 +150,7 @@ impl AppController { } #[tracing::instrument(level = "trace", skip(self), err)] - fn read_app_on_server(&self, params: AppId) -> Result<(), FlowyError> { + fn read_app_on_server(&self, params: AppIdPB) -> Result<(), FlowyError> { let token = self.user.token()?; let server = self.cloud_service.clone(); let persistence = self.persistence.clone(); @@ -162,7 +162,7 @@ impl AppController { .await { Ok(_) => { - let app: App = app_rev.into(); + let app: AppPB = app_rev.into(); send_dart_notification(&app.id, FolderNotification::AppUpdated) .payload(app) .send(); @@ -247,7 +247,7 @@ fn notify_apps_changed<'a>( .into_iter() .map(|app_rev| app_rev.into()) .collect(); - let repeated_app = RepeatedApp { items }; + let repeated_app = RepeatedAppPB { items }; send_dart_notification(workspace_id, FolderNotification::WorkspaceAppsChanged) .payload(repeated_app) .send(); diff --git a/frontend/rust-lib/flowy-folder/src/services/app/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/app/event_handler.rs index 28885c69d7..e2087c167e 100644 --- a/frontend/rust-lib/flowy-folder/src/services/app/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/app/event_handler.rs @@ -1,5 +1,5 @@ use crate::{ - entities::app::{App, AppId, CreateAppParams, CreateAppPayload, UpdateAppParams, UpdateAppPayload}, + entities::app::{AppIdPB, AppPB, CreateAppParams, CreateAppPayloadPB, UpdateAppParams, UpdateAppPayloadPB}, errors::FlowyError, services::{AppController, TrashController, ViewController}, }; @@ -8,9 +8,9 @@ use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::{convert::TryInto, sync::Arc}; pub(crate) async fn create_app_handler( - data: Data, + data: Data, controller: AppData>, -) -> DataResult { +) -> DataResult { let params: CreateAppParams = data.into_inner().try_into()?; let detail = controller.create_app_from_params(params).await?; @@ -18,11 +18,11 @@ pub(crate) async fn create_app_handler( } pub(crate) async fn delete_app_handler( - data: Data, + data: Data, app_controller: AppData>, trash_controller: AppData>, ) -> Result<(), FlowyError> { - let params: AppId = data.into_inner(); + let params: AppIdPB = data.into_inner(); let trash = app_controller .read_local_apps(vec![params.value]) .await? @@ -36,7 +36,7 @@ pub(crate) async fn delete_app_handler( #[tracing::instrument(level = "debug", skip(data, controller))] pub(crate) async fn update_app_handler( - data: Data, + data: Data, controller: AppData>, ) -> Result<(), FlowyError> { let params: UpdateAppParams = data.into_inner().try_into()?; @@ -46,11 +46,11 @@ pub(crate) async fn update_app_handler( #[tracing::instrument(level = "trace", skip(data, app_controller, view_controller))] pub(crate) async fn read_app_handler( - data: Data, + data: Data, app_controller: AppData>, view_controller: AppData>, -) -> DataResult { - let params: AppId = data.into_inner(); +) -> DataResult { + let params: AppIdPB = data.into_inner(); let mut app_rev = app_controller.read_app(params.clone()).await?; app_rev.belongings = view_controller.read_views_belong_to(¶ms.value).await?; diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/app_sql.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/app_sql.rs index 6b5f47c2b7..cf643e7dff 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/app_sql.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/app_sql.rs @@ -1,6 +1,6 @@ use crate::entities::{ app::UpdateAppParams, - trash::{Trash, TrashType}, + trash::{TrashPB, TrashType}, }; use crate::{errors::FlowyError, services::persistence::version_1::workspace_sql::WorkspaceTable}; use flowy_database::{ @@ -107,9 +107,9 @@ impl AppTable { } } -impl std::convert::From for Trash { +impl std::convert::From for TrashPB { fn from(table: AppTable) -> Self { - Trash { + TrashPB { id: table.id, name: table.name, modified_time: table.modified_time, diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs index ec1bbf38bf..6223cd3366 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs @@ -1,6 +1,6 @@ use crate::{ entities::{ - trash::{Trash, TrashType}, + trash::{TrashPB, TrashType}, view::UpdateViewParams, }, errors::FlowyError, @@ -133,9 +133,9 @@ impl std::convert::From for ViewRevision { } } -impl std::convert::From for Trash { +impl std::convert::From for TrashPB { fn from(table: ViewTable) -> Self { - Trash { + TrashPB { id: table.id, name: table.name, modified_time: table.modified_time, diff --git a/frontend/rust-lib/flowy-folder/src/services/trash/controller.rs b/frontend/rust-lib/flowy-folder/src/services/trash/controller.rs index 134e8a0d84..8ac9618917 100644 --- a/frontend/rust-lib/flowy-folder/src/services/trash/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/trash/controller.rs @@ -1,6 +1,6 @@ use crate::{ dart_notification::{send_anonymous_dart_notification, FolderNotification}, - entities::trash::{RepeatedTrash, RepeatedTrashId, Trash, TrashId, TrashType}, + entities::trash::{RepeatedTrashIdPB, RepeatedTrashPB, TrashIdPB, TrashPB, TrashType}, errors::{FlowyError, FlowyResult}, event_map::{FolderCouldServiceV1, WorkspaceUser}, services::persistence::{FolderPersistence, FolderPersistenceTransaction}, @@ -49,12 +49,12 @@ impl TrashController { }) .await?; - let identifier = TrashId { + let identifier = TrashIdPB { id: trash.id, ty: trash.ty.into(), }; - let _ = self.delete_trash_on_server(RepeatedTrashId { + let _ = self.delete_trash_on_server(RepeatedTrashIdPB { items: vec![identifier.clone()], delete_all: false, })?; @@ -67,7 +67,7 @@ impl TrashController { #[tracing::instrument(level = "debug", skip(self) err)] pub async fn restore_all_trash(&self) -> FlowyResult<()> { - let trash_identifier: RepeatedTrashId = self + let trash_identifier: RepeatedTrashIdPB = self .persistence .begin_transaction(|transaction| { let trash = transaction.read_trash(None); @@ -81,14 +81,14 @@ impl TrashController { let _ = self.notify.send(TrashEvent::Putback(trash_identifier, tx)); let _ = rx.recv().await; - notify_trash_changed(RepeatedTrash { items: vec![] }); + notify_trash_changed(RepeatedTrashPB { items: vec![] }); let _ = self.delete_all_trash_on_server().await?; Ok(()) } #[tracing::instrument(level = "debug", skip(self), err)] pub async fn delete_all_trash(&self) -> FlowyResult<()> { - let all_trash_identifiers: RepeatedTrashId = self + let all_trash_identifiers: RepeatedTrashIdPB = self .persistence .begin_transaction(|transaction| transaction.read_trash(None)) .await? @@ -96,13 +96,13 @@ impl TrashController { let _ = self.delete_with_identifiers(all_trash_identifiers).await?; - notify_trash_changed(RepeatedTrash { items: vec![] }); + notify_trash_changed(RepeatedTrashPB { items: vec![] }); let _ = self.delete_all_trash_on_server().await?; Ok(()) } #[tracing::instrument(level = "debug", skip(self), err)] - pub async fn delete(&self, trash_identifiers: RepeatedTrashId) -> FlowyResult<()> { + pub async fn delete(&self, trash_identifiers: RepeatedTrashIdPB) -> FlowyResult<()> { let _ = self.delete_with_identifiers(trash_identifiers.clone()).await?; let trash_revs = self .persistence @@ -116,7 +116,7 @@ impl TrashController { } #[tracing::instrument(level = "debug", skip(self), fields(delete_trash_ids), err)] - pub async fn delete_with_identifiers(&self, trash_identifiers: RepeatedTrashId) -> FlowyResult<()> { + pub async fn delete_with_identifiers(&self, trash_identifiers: RepeatedTrashIdPB) -> FlowyResult<()> { let (tx, mut rx) = mpsc::channel::>(1); tracing::Span::current().record("delete_trash_ids", &format!("{}", trash_identifiers).as_str()); let _ = self.notify.send(TrashEvent::Delete(trash_identifiers.clone(), tx)); @@ -153,7 +153,7 @@ impl TrashController { pub async fn add>(&self, trash: Vec) -> Result<(), FlowyError> { let (tx, mut rx) = mpsc::channel::>(1); let trash_revs: Vec = trash.into_iter().map(|t| t.into()).collect(); - let identifiers = trash_revs.iter().map(|t| t.into()).collect::>(); + let identifiers = trash_revs.iter().map(|t| t.into()).collect::>(); tracing::Span::current().record( "trash_ids", @@ -187,8 +187,8 @@ impl TrashController { self.notify.subscribe() } - pub async fn read_trash(&self) -> Result { - let items: Vec = self + pub async fn read_trash(&self) -> Result { + let items: Vec = self .persistence .begin_transaction(|transaction| transaction.read_trash(None)) .await? @@ -197,7 +197,7 @@ impl TrashController { .collect(); let _ = self.read_trash_on_server()?; - Ok(RepeatedTrash { items }) + Ok(RepeatedTrashPB { items }) } pub fn read_trash_ids<'a>( @@ -215,7 +215,7 @@ impl TrashController { impl TrashController { #[tracing::instrument(level = "trace", skip(self, trash), err)] - fn create_trash_on_server>(&self, trash: T) -> FlowyResult<()> { + fn create_trash_on_server>(&self, trash: T) -> FlowyResult<()> { let token = self.user.token()?; let trash_identifiers = trash.into(); let server = self.cloud_service.clone(); @@ -230,7 +230,7 @@ impl TrashController { } #[tracing::instrument(level = "trace", skip(self, trash), err)] - fn delete_trash_on_server>(&self, trash: T) -> FlowyResult<()> { + fn delete_trash_on_server>(&self, trash: T) -> FlowyResult<()> { let token = self.user.token()?; let trash_identifiers = trash.into(); let server = self.cloud_service.clone(); @@ -277,12 +277,12 @@ impl TrashController { async fn delete_all_trash_on_server(&self) -> FlowyResult<()> { let token = self.user.token()?; let server = self.cloud_service.clone(); - server.delete_trash(&token, RepeatedTrashId::all()).await + server.delete_trash(&token, RepeatedTrashIdPB::all()).await } } #[tracing::instrument(level = "debug", skip(repeated_trash), fields(n_trash))] -fn notify_trash_changed>(repeated_trash: T) { +fn notify_trash_changed>(repeated_trash: T) { let repeated_trash = repeated_trash.into(); tracing::Span::current().record("n_trash", &repeated_trash.len()); send_anonymous_dart_notification(FolderNotification::TrashUpdated) @@ -292,9 +292,9 @@ fn notify_trash_changed>(repeated_trash: T) { #[derive(Clone)] pub enum TrashEvent { - NewTrash(RepeatedTrashId, mpsc::Sender>), - Putback(RepeatedTrashId, mpsc::Sender>), - Delete(RepeatedTrashId, mpsc::Sender>), + NewTrash(RepeatedTrashIdPB, mpsc::Sender>), + Putback(RepeatedTrashIdPB, mpsc::Sender>), + Delete(RepeatedTrashIdPB, mpsc::Sender>), } impl std::fmt::Debug for TrashEvent { diff --git a/frontend/rust-lib/flowy-folder/src/services/trash/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/trash/event_handler.rs index b1853faaf5..0034745253 100644 --- a/frontend/rust-lib/flowy-folder/src/services/trash/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/trash/event_handler.rs @@ -1,5 +1,5 @@ use crate::{ - entities::trash::{RepeatedTrash, RepeatedTrashId, TrashId}, + entities::trash::{RepeatedTrashIdPB, RepeatedTrashPB, TrashIdPB}, errors::FlowyError, services::TrashController, }; @@ -9,14 +9,14 @@ use std::sync::Arc; #[tracing::instrument(level = "debug", skip(controller), err)] pub(crate) async fn read_trash_handler( controller: AppData>, -) -> DataResult { +) -> DataResult { let repeated_trash = controller.read_trash().await?; data_result(repeated_trash) } #[tracing::instrument(level = "debug", skip(identifier, controller), err)] pub(crate) async fn putback_trash_handler( - identifier: Data, + identifier: Data, controller: AppData>, ) -> Result<(), FlowyError> { let _ = controller.putback(&identifier.id).await?; @@ -25,7 +25,7 @@ pub(crate) async fn putback_trash_handler( #[tracing::instrument(level = "debug", skip(identifiers, controller), err)] pub(crate) async fn delete_trash_handler( - identifiers: Data, + identifiers: Data, controller: AppData>, ) -> Result<(), FlowyError> { let _ = controller.delete(identifiers.into_inner()).await?; diff --git a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs index 0df71c320f..df1f668941 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/view/controller.rs @@ -1,11 +1,11 @@ pub use crate::entities::view::ViewDataType; -use crate::entities::ViewInfo; +use crate::entities::ViewInfoPB; use crate::manager::{ViewDataProcessor, ViewDataProcessorMap}; use crate::{ dart_notification::{send_dart_notification, FolderNotification}, entities::{ - trash::{RepeatedTrashId, TrashType}, - view::{CreateViewParams, RepeatedView, UpdateViewParams, View, ViewId}, + trash::{RepeatedTrashIdPB, TrashType}, + view::{CreateViewParams, RepeatedViewPB, UpdateViewParams, ViewIdPB, ViewPB}, }, errors::{FlowyError, FlowyResult}, event_map::{FolderCouldServiceV1, WorkspaceUser}, @@ -106,7 +106,7 @@ impl ViewController { } #[tracing::instrument(level = "debug", skip(self, view_id), fields(view_id = %view_id.value), err)] - pub(crate) async fn read_view(&self, view_id: ViewId) -> Result { + pub(crate) async fn read_view(&self, view_id: ViewIdPB) -> Result { let view_rev = self .persistence .begin_transaction(|transaction| { @@ -123,25 +123,25 @@ impl ViewController { } #[tracing::instrument(level = "debug", skip(self, view_id), fields(view_id = %view_id.value), err)] - pub(crate) async fn read_view_info(&self, view_id: ViewId) -> Result { + pub(crate) async fn read_view_info(&self, view_id: ViewIdPB) -> Result { let view_info = self .persistence .begin_transaction(|transaction| { let view_rev = transaction.read_view(&view_id.value)?; - let items: Vec = view_rev + let items: Vec = view_rev .belongings .into_iter() .map(|view_rev| view_rev.into()) .collect(); - let view_info = ViewInfo { + let view_info = ViewInfoPB { id: view_rev.id, belong_to_id: view_rev.belong_to_id, name: view_rev.name, desc: view_rev.desc, data_type: view_rev.data_type.into(), - belongings: RepeatedView { items }, + belongings: RepeatedViewPB { items }, ext_data: view_rev.ext_data, }; Ok(view_info) @@ -245,7 +245,7 @@ impl ViewController { .begin_transaction(|transaction| { let _ = transaction.update_view(changeset)?; let view_rev = transaction.read_view(&view_id)?; - let view: View = view_rev.clone().into(); + let view: ViewPB = view_rev.clone().into(); send_dart_notification(&view_id, FolderNotification::ViewUpdated) .payload(view) .send(); @@ -297,7 +297,7 @@ impl ViewController { } #[tracing::instrument(level = "debug", skip(self), err)] - fn read_view_on_server(&self, params: ViewId) -> Result<(), FlowyError> { + fn read_view_on_server(&self, params: ViewIdPB) -> Result<(), FlowyError> { let token = self.user.token()?; let server = self.cloud_service.clone(); let persistence = self.persistence.clone(); @@ -310,7 +310,7 @@ impl ViewController { .await { Ok(_) => { - let view: View = view_rev.into(); + let view: ViewPB = view_rev.into(); send_dart_notification(&view.id, FolderNotification::ViewUpdated) .payload(view) .send(); @@ -464,7 +464,7 @@ fn get_data_processor( } fn read_local_views_with_transaction<'a>( - identifiers: RepeatedTrashId, + identifiers: RepeatedTrashIdPB, transaction: &'a (dyn FolderPersistenceTransaction + 'a), ) -> Result, FlowyError> { let mut view_revs = vec![]; @@ -474,7 +474,7 @@ fn read_local_views_with_transaction<'a>( Ok(view_revs) } -fn notify_dart(view: View, notification: FolderNotification) { +fn notify_dart(view: ViewPB, notification: FolderNotification) { send_dart_notification(&view.id, notification).payload(view).send(); } @@ -489,13 +489,13 @@ fn notify_views_changed<'a>( trash_controller: Arc, transaction: &'a (dyn FolderPersistenceTransaction + 'a), ) -> FlowyResult<()> { - let items: Vec = read_belonging_views_on_local(belong_to_id, trash_controller.clone(), transaction)? + let items: Vec = read_belonging_views_on_local(belong_to_id, trash_controller.clone(), transaction)? .into_iter() .map(|view_rev| view_rev.into()) .collect(); tracing::Span::current().record("view_count", &format!("{}", items.len()).as_str()); - let repeated_view = RepeatedView { items }; + let repeated_view = RepeatedViewPB { items }; send_dart_notification(belong_to_id, FolderNotification::AppViewsChanged) .payload(repeated_view) .send(); diff --git a/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs index f970905f30..925ece6ba2 100644 --- a/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/view/event_handler.rs @@ -1,12 +1,13 @@ -use crate::entities::view::{MoveFolderItemParams, MoveFolderItemPayload, MoveFolderItemType}; -use crate::entities::ViewInfo; +use crate::entities::view::{MoveFolderItemParams, MoveFolderItemPayloadPB, MoveFolderItemType}; +use crate::entities::ViewInfoPB; use crate::manager::FolderManager; use crate::services::{notify_workspace_setting_did_change, AppController}; use crate::{ entities::{ - trash::Trash, + trash::TrashPB, view::{ - CreateViewParams, CreateViewPayload, RepeatedViewId, UpdateViewParams, UpdateViewPayload, View, ViewId, + CreateViewParams, CreateViewPayloadPB, RepeatedViewIdPB, UpdateViewParams, UpdateViewPayloadPB, ViewIdPB, + ViewPB, }, }, errors::FlowyError, @@ -17,35 +18,35 @@ use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use std::{convert::TryInto, sync::Arc}; pub(crate) async fn create_view_handler( - data: Data, + data: Data, controller: AppData>, -) -> DataResult { +) -> DataResult { let params: CreateViewParams = data.into_inner().try_into()?; let view_rev = controller.create_view_from_params(params).await?; data_result(view_rev.into()) } pub(crate) async fn read_view_handler( - data: Data, + data: Data, controller: AppData>, -) -> DataResult { - let view_id: ViewId = data.into_inner(); +) -> DataResult { + let view_id: ViewIdPB = data.into_inner(); let view_rev = controller.read_view(view_id.clone()).await?; data_result(view_rev.into()) } pub(crate) async fn read_view_info_handler( - data: Data, + data: Data, controller: AppData>, -) -> DataResult { - let view_id: ViewId = data.into_inner(); +) -> DataResult { + let view_id: ViewIdPB = data.into_inner(); let view_info = controller.read_view_info(view_id.clone()).await?; data_result(view_info) } #[tracing::instrument(level = "debug", skip(data, controller), err)] pub(crate) async fn update_view_handler( - data: Data, + data: Data, controller: AppData>, ) -> Result<(), FlowyError> { let params: UpdateViewParams = data.into_inner().try_into()?; @@ -55,11 +56,11 @@ pub(crate) async fn update_view_handler( } pub(crate) async fn delete_view_handler( - data: Data, + data: Data, view_controller: AppData>, trash_controller: AppData>, ) -> Result<(), FlowyError> { - let params: RepeatedViewId = data.into_inner(); + let params: RepeatedViewIdPB = data.into_inner(); for view_id in ¶ms.items { let _ = view_controller.delete_view(view_id.into()).await; } @@ -72,35 +73,35 @@ pub(crate) async fn delete_view_handler( let trash_rev: TrashRevision = view.into(); trash_rev.into() }) - .collect::>(); + .collect::>(); let _ = trash_controller.add(trash).await?; Ok(()) } pub(crate) async fn set_latest_view_handler( - data: Data, + data: Data, folder: AppData>, controller: AppData>, ) -> Result<(), FlowyError> { - let view_id: ViewId = data.into_inner(); + let view_id: ViewIdPB = data.into_inner(); let _ = controller.set_latest_view(&view_id.value)?; let _ = notify_workspace_setting_did_change(&folder, &view_id).await?; Ok(()) } pub(crate) async fn close_view_handler( - data: Data, + data: Data, controller: AppData>, ) -> Result<(), FlowyError> { - let view_id: ViewId = data.into_inner(); + let view_id: ViewIdPB = data.into_inner(); let _ = controller.close_view(&view_id.value).await?; Ok(()) } #[tracing::instrument(level = "debug", skip_all, err)] pub(crate) async fn move_item_handler( - data: Data, + data: Data, view_controller: AppData>, app_controller: AppData>, ) -> Result<(), FlowyError> { @@ -120,10 +121,10 @@ pub(crate) async fn move_item_handler( #[tracing::instrument(level = "debug", skip(data, controller), err)] pub(crate) async fn duplicate_view_handler( - data: Data, + data: Data, controller: AppData>, ) -> Result<(), FlowyError> { - let view_id: ViewId = data.into_inner(); + let view_id: ViewIdPB = data.into_inner(); let _ = controller.duplicate_view(&view_id.value).await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-folder/src/services/workspace/controller.rs b/frontend/rust-lib/flowy-folder/src/services/workspace/controller.rs index 9863cafdc5..42f3f65fa1 100644 --- a/frontend/rust-lib/flowy-folder/src/services/workspace/controller.rs +++ b/frontend/rust-lib/flowy-folder/src/services/workspace/controller.rs @@ -52,7 +52,7 @@ impl WorkspaceController { .into_iter() .map(|workspace_rev| workspace_rev.into()) .collect(); - let repeated_workspace = RepeatedWorkspace { items: workspaces }; + let repeated_workspace = RepeatedWorkspacePB { items: workspaces }; send_dart_notification(&token, FolderNotification::UserCreateWorkspace) .payload(repeated_workspace) .send(); @@ -99,7 +99,7 @@ impl WorkspaceController { Ok(()) } - pub(crate) async fn open_workspace(&self, params: WorkspaceId) -> Result { + pub(crate) async fn open_workspace(&self, params: WorkspaceIdPB) -> Result { let user_id = self.user.user_id()?; if let Some(workspace_id) = params.value { let workspace = self @@ -131,14 +131,14 @@ impl WorkspaceController { workspace_id: Option, user_id: &str, transaction: &'a (dyn FolderPersistenceTransaction + 'a), - ) -> Result { + ) -> Result { let workspace_id = workspace_id.to_owned(); let workspaces = transaction .read_workspaces(user_id, workspace_id)? .into_iter() .map(|workspace_rev| workspace_rev.into()) .collect(); - Ok(RepeatedWorkspace { items: workspaces }) + Ok(RepeatedWorkspacePB { items: workspaces }) } pub(crate) fn read_local_workspace<'a>( @@ -146,7 +146,7 @@ impl WorkspaceController { workspace_id: String, user_id: &str, transaction: &'a (dyn FolderPersistenceTransaction + 'a), - ) -> Result { + ) -> Result { let mut workspace_revs = transaction.read_workspaces(user_id, Some(workspace_id.clone()))?; if workspace_revs.is_empty() { return Err(FlowyError::record_not_found().context(format!("{} workspace not found", workspace_id))); @@ -155,7 +155,7 @@ impl WorkspaceController { let workspace = workspace_revs .drain(..1) .map(|workspace_rev| workspace_rev.into()) - .collect::>() + .collect::>() .pop() .unwrap(); Ok(workspace) @@ -186,7 +186,7 @@ impl WorkspaceController { #[tracing::instrument(level = "trace", skip(self), err)] fn delete_workspace_on_server(&self, workspace_id: &str) -> Result<(), FlowyError> { - let params = WorkspaceId { + let params = WorkspaceIdPB { value: Some(workspace_id.to_string()), }; let (token, server) = (self.user.token()?, self.cloud_service.clone()); @@ -221,11 +221,11 @@ pub async fn notify_workspace_setting_did_change( )?; let setting = match transaction.read_view(view_id) { - Ok(latest_view) => CurrentWorkspaceSetting { + Ok(latest_view) => CurrentWorkspaceSettingPB { workspace, latest_view: Some(latest_view.into()), }, - Err(_) => CurrentWorkspaceSetting { + Err(_) => CurrentWorkspaceSettingPB { workspace, latest_view: None, }, diff --git a/frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs b/frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs index 02fb37a12b..234fa3b7de 100644 --- a/frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs +++ b/frontend/rust-lib/flowy-folder/src/services/workspace/event_handler.rs @@ -1,7 +1,7 @@ use crate::entities::{ - app::RepeatedApp, - view::View, - workspace::{CurrentWorkspaceSetting, RepeatedWorkspace, WorkspaceId, *}, + app::RepeatedAppPB, + view::ViewPB, + workspace::{CurrentWorkspaceSettingPB, RepeatedWorkspacePB, WorkspaceIdPB, *}, }; use crate::{ dart_notification::{send_dart_notification, FolderNotification}, @@ -14,9 +14,9 @@ use std::{convert::TryInto, sync::Arc}; #[tracing::instrument(level = "debug", skip(data, controller), err)] pub(crate) async fn create_workspace_handler( - data: Data, + data: Data, controller: AppData>, -) -> DataResult { +) -> DataResult { let controller = controller.get_ref().clone(); let params: CreateWorkspaceParams = data.into_inner().try_into()?; let workspace_rev = controller.create_workspace_from_params(params).await?; @@ -26,33 +26,33 @@ pub(crate) async fn create_workspace_handler( #[tracing::instrument(level = "debug", skip(controller), err)] pub(crate) async fn read_workspace_apps_handler( controller: AppData>, -) -> DataResult { +) -> DataResult { let items = controller .read_current_workspace_apps() .await? .into_iter() .map(|app_rev| app_rev.into()) .collect(); - let repeated_app = RepeatedApp { items }; + let repeated_app = RepeatedAppPB { items }; data_result(repeated_app) } #[tracing::instrument(level = "debug", skip(data, controller), err)] pub(crate) async fn open_workspace_handler( - data: Data, + data: Data, controller: AppData>, -) -> DataResult { - let params: WorkspaceId = data.into_inner(); +) -> DataResult { + let params: WorkspaceIdPB = data.into_inner(); let workspaces = controller.open_workspace(params).await?; data_result(workspaces) } #[tracing::instrument(level = "debug", skip(data, folder), err)] pub(crate) async fn read_workspaces_handler( - data: Data, + data: Data, folder: AppData>, -) -> DataResult { - let params: WorkspaceId = data.into_inner(); +) -> DataResult { + let params: WorkspaceIdPB = data.into_inner(); let user_id = folder.user.user_id()?; let workspace_controller = folder.workspace_controller.clone(); @@ -79,10 +79,10 @@ pub(crate) async fn read_workspaces_handler( #[tracing::instrument(level = "debug", skip(folder), err)] pub async fn read_cur_workspace_handler( folder: AppData>, -) -> DataResult { +) -> DataResult { let workspace_id = get_current_workspace()?; let user_id = folder.user.user_id()?; - let params = WorkspaceId { + let params = WorkspaceIdPB { value: Some(workspace_id.clone()), }; @@ -95,13 +95,13 @@ pub async fn read_cur_workspace_handler( }) .await?; - let latest_view: Option = folder + let latest_view: Option = folder .view_controller .latest_visit_view() .await .unwrap_or(None) .map(|view_rev| view_rev.into()); - let setting = CurrentWorkspaceSetting { workspace, latest_view }; + let setting = CurrentWorkspaceSettingPB { workspace, latest_view }; let _ = read_workspaces_on_server(folder, user_id, params); data_result(setting) } @@ -110,7 +110,7 @@ pub async fn read_cur_workspace_handler( fn read_workspaces_on_server( folder_manager: AppData>, user_id: String, - params: WorkspaceId, + params: WorkspaceIdPB, ) -> Result<(), FlowyError> { let (token, server) = (folder_manager.user.token()?, folder_manager.cloud_service.clone()); let persistence = folder_manager.persistence.clone(); @@ -145,7 +145,7 @@ fn read_workspaces_on_server( }) .await?; - let repeated_workspace = RepeatedWorkspace { + let repeated_workspace = RepeatedWorkspacePB { items: workspace_revs .into_iter() .map(|workspace_rev| workspace_rev.into()) diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs b/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs index 86c3dc7478..f17986b484 100644 --- a/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs +++ b/frontend/rust-lib/flowy-folder/tests/workspace/folder_test.rs @@ -1,6 +1,6 @@ use crate::script::{invalid_workspace_name_test_case, FolderScript::*, FolderTest}; use flowy_folder::entities::view::ViewDataType; -use flowy_folder::entities::workspace::CreateWorkspacePayload; +use flowy_folder::entities::workspace::CreateWorkspacePayloadPB; use flowy_revision::disk::RevisionState; use flowy_test::{event_builder::*, FlowySDKTest}; @@ -63,7 +63,7 @@ async fn workspace_create_with_apps() { async fn workspace_create_with_invalid_name() { for (name, code) in invalid_workspace_name_test_case() { let sdk = FlowySDKTest::default(); - let request = CreateWorkspacePayload { + let request = CreateWorkspacePayloadPB { name, desc: "".to_owned(), }; diff --git a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs index cdcd3cfa8e..ed16664d90 100644 --- a/frontend/rust-lib/flowy-folder/tests/workspace/script.rs +++ b/frontend/rust-lib/flowy-folder/tests/workspace/script.rs @@ -1,16 +1,16 @@ -use flowy_folder::entities::view::{RepeatedViewId, ViewId}; -use flowy_folder::entities::workspace::WorkspaceId; +use flowy_folder::entities::view::{RepeatedViewIdPB, ViewIdPB}; +use flowy_folder::entities::workspace::WorkspaceIdPB; use flowy_folder::entities::{ - app::{App, RepeatedApp}, - trash::Trash, - view::{RepeatedView, View, ViewDataType}, - workspace::Workspace, + app::{AppIdPB, CreateAppPayloadPB, UpdateAppPayloadPB}, + trash::{RepeatedTrashPB, TrashIdPB, TrashType}, + view::{CreateViewPayloadPB, UpdateViewPayloadPB}, + workspace::{CreateWorkspacePayloadPB, RepeatedWorkspacePB}, }; use flowy_folder::entities::{ - app::{AppId, CreateAppPayload, UpdateAppPayload}, - trash::{RepeatedTrash, TrashId, TrashType}, - view::{CreateViewPayload, UpdateViewPayload}, - workspace::{CreateWorkspacePayload, RepeatedWorkspace}, + app::{AppPB, RepeatedAppPB}, + trash::TrashPB, + view::{RepeatedViewPB, ViewDataType, ViewPB}, + workspace::WorkspacePB, }; use flowy_folder::event_map::FolderEvent::*; use flowy_folder::{errors::ErrorCode, services::folder_editor::FolderEditor}; @@ -30,7 +30,7 @@ pub enum FolderScript { desc: String, }, // AssertWorkspaceRevisionJson(String), - AssertWorkspace(Workspace), + AssertWorkspace(WorkspacePB), ReadWorkspace(Option), // App @@ -39,7 +39,7 @@ pub enum FolderScript { desc: String, }, // AssertAppRevisionJson(String), - AssertApp(App), + AssertApp(AppPB), ReadApp(String), UpdateApp { name: Option, @@ -53,7 +53,7 @@ pub enum FolderScript { desc: String, data_type: ViewDataType, }, - AssertView(View), + AssertView(ViewPB), ReadView(String), UpdateView { name: Option, @@ -79,11 +79,11 @@ pub enum FolderScript { pub struct FolderTest { pub sdk: FlowySDKTest, - pub all_workspace: Vec, - pub workspace: Workspace, - pub app: App, - pub view: View, - pub trash: Vec, + pub all_workspace: Vec, + pub workspace: WorkspacePB, + pub app: AppPB, + pub view: ViewPB, + pub trash: Vec, // pub folder_editor: } @@ -101,11 +101,11 @@ impl FolderTest { ViewDataType::TextBlock, ) .await; - app.belongings = RepeatedView { + app.belongings = RepeatedViewPB { items: vec![view.clone()], }; - workspace.apps = RepeatedApp { + workspace.apps = RepeatedAppPB { items: vec![app.clone()], }; Self { @@ -247,8 +247,8 @@ pub fn invalid_workspace_name_test_case() -> Vec<(String, ErrorCode)> { ] } -pub async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> Workspace { - let request = CreateWorkspacePayload { +pub async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> WorkspacePB { + let request = CreateWorkspacePayloadPB { name: name.to_owned(), desc: desc.to_owned(), }; @@ -258,18 +258,18 @@ pub async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> Wor .payload(request) .async_send() .await - .parse::(); + .parse::(); workspace } -pub async fn read_workspace(sdk: &FlowySDKTest, workspace_id: Option) -> Vec { - let request = WorkspaceId { value: workspace_id }; +pub async fn read_workspace(sdk: &FlowySDKTest, workspace_id: Option) -> Vec { + let request = WorkspaceIdPB { value: workspace_id }; let mut repeated_workspace = FolderEventBuilder::new(sdk.clone()) .event(ReadWorkspaces) .payload(request.clone()) .async_send() .await - .parse::(); + .parse::(); let workspaces; if let Some(workspace_id) = &request.value { @@ -277,7 +277,7 @@ pub async fn read_workspace(sdk: &FlowySDKTest, workspace_id: Option) -> .into_inner() .into_iter() .filter(|workspace| &workspace.id == workspace_id) - .collect::>(); + .collect::>(); debug_assert_eq!(workspaces.len(), 1); } else { workspaces = repeated_workspace.items; @@ -286,8 +286,8 @@ pub async fn read_workspace(sdk: &FlowySDKTest, workspace_id: Option) -> workspaces } -pub async fn create_app(sdk: &FlowySDKTest, workspace_id: &str, name: &str, desc: &str) -> App { - let create_app_request = CreateAppPayload { +pub async fn create_app(sdk: &FlowySDKTest, workspace_id: &str, name: &str, desc: &str) -> AppPB { + let create_app_request = CreateAppPayloadPB { workspace_id: workspace_id.to_owned(), name: name.to_string(), desc: desc.to_string(), @@ -299,12 +299,12 @@ pub async fn create_app(sdk: &FlowySDKTest, workspace_id: &str, name: &str, desc .payload(create_app_request) .async_send() .await - .parse::(); + .parse::(); app } -pub async fn read_app(sdk: &FlowySDKTest, app_id: &str) -> App { - let request = AppId { +pub async fn read_app(sdk: &FlowySDKTest, app_id: &str) -> AppPB { + let request = AppIdPB { value: app_id.to_owned(), }; @@ -313,13 +313,13 @@ pub async fn read_app(sdk: &FlowySDKTest, app_id: &str) -> App { .payload(request) .async_send() .await - .parse::(); + .parse::(); app } pub async fn update_app(sdk: &FlowySDKTest, app_id: &str, name: Option, desc: Option) { - let request = UpdateAppPayload { + let request = UpdateAppPayloadPB { app_id: app_id.to_string(), name, desc, @@ -335,7 +335,7 @@ pub async fn update_app(sdk: &FlowySDKTest, app_id: &str, name: Option, } pub async fn delete_app(sdk: &FlowySDKTest, app_id: &str) { - let request = AppId { + let request = AppIdPB { value: app_id.to_string(), }; @@ -346,8 +346,8 @@ pub async fn delete_app(sdk: &FlowySDKTest, app_id: &str) { .await; } -pub async fn create_view(sdk: &FlowySDKTest, app_id: &str, name: &str, desc: &str, data_type: ViewDataType) -> View { - let request = CreateViewPayload { +pub async fn create_view(sdk: &FlowySDKTest, app_id: &str, name: &str, desc: &str, data_type: ViewDataType) -> ViewPB { + let request = CreateViewPayloadPB { belong_to_id: app_id.to_string(), name: name.to_string(), desc: desc.to_string(), @@ -361,22 +361,22 @@ pub async fn create_view(sdk: &FlowySDKTest, app_id: &str, name: &str, desc: &st .payload(request) .async_send() .await - .parse::(); + .parse::(); view } -pub async fn read_view(sdk: &FlowySDKTest, view_id: &str) -> View { - let view_id: ViewId = view_id.into(); +pub async fn read_view(sdk: &FlowySDKTest, view_id: &str) -> ViewPB { + let view_id: ViewIdPB = view_id.into(); FolderEventBuilder::new(sdk.clone()) .event(ReadView) .payload(view_id) .async_send() .await - .parse::() + .parse::() } pub async fn update_view(sdk: &FlowySDKTest, view_id: &str, name: Option, desc: Option) { - let request = UpdateViewPayload { + let request = UpdateViewPayloadPB { view_id: view_id.to_string(), name, desc, @@ -390,7 +390,7 @@ pub async fn update_view(sdk: &FlowySDKTest, view_id: &str, name: Option } pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec) { - let request = RepeatedViewId { items: view_ids }; + let request = RepeatedViewIdPB { items: view_ids }; FolderEventBuilder::new(sdk.clone()) .event(DeleteView) .payload(request) @@ -400,7 +400,7 @@ pub async fn delete_view(sdk: &FlowySDKTest, view_ids: Vec) { #[allow(dead_code)] pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> DocumentPB { - let view_id: ViewId = view_id.into(); + let view_id: ViewIdPB = view_id.into(); FolderEventBuilder::new(sdk.clone()) .event(SetLatestView) .payload(view_id) @@ -409,16 +409,16 @@ pub async fn set_latest_view(sdk: &FlowySDKTest, view_id: &str) -> DocumentPB { .parse::() } -pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrash { +pub async fn read_trash(sdk: &FlowySDKTest) -> RepeatedTrashPB { FolderEventBuilder::new(sdk.clone()) .event(ReadTrash) .async_send() .await - .parse::() + .parse::() } pub async fn restore_app_from_trash(sdk: &FlowySDKTest, app_id: &str) { - let id = TrashId { + let id = TrashIdPB { id: app_id.to_owned(), ty: TrashType::TrashApp, }; @@ -430,7 +430,7 @@ pub async fn restore_app_from_trash(sdk: &FlowySDKTest, app_id: &str) { } pub async fn restore_view_from_trash(sdk: &FlowySDKTest, view_id: &str) { - let id = TrashId { + let id = TrashIdPB { id: view_id.to_owned(), ty: TrashType::TrashView, }; diff --git a/frontend/rust-lib/flowy-net/src/http_server/folder.rs b/frontend/rust-lib/flowy-net/src/http_server/folder.rs index 788f7fa462..e600d617a9 100644 --- a/frontend/rust-lib/flowy-net/src/http_server/folder.rs +++ b/frontend/rust-lib/flowy-net/src/http_server/folder.rs @@ -1,15 +1,14 @@ use crate::{ - configuration::{ClientServerConfiguration, HEADER_TOKEN}, + configuration::ClientServerConfiguration, request::{HttpRequestBuilder, ResponseMiddleware}, }; use flowy_error::FlowyError; use flowy_folder::entities::{ - trash::RepeatedTrashId, - view::{CreateViewParams, RepeatedViewId, UpdateViewParams, ViewId}, - workspace::{CreateWorkspaceParams, UpdateWorkspaceParams, WorkspaceId}, - {AppId, CreateAppParams, UpdateAppParams}, + trash::RepeatedTrashIdPB, + view::{CreateViewParams, RepeatedViewIdPB, UpdateViewParams, ViewIdPB}, + workspace::{CreateWorkspaceParams, UpdateWorkspaceParams, WorkspaceIdPB}, + {AppIdPB, CreateAppParams, UpdateAppParams}, }; - use flowy_folder::event_map::FolderCouldServiceV1; use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision}; use http_flowy::errors::ServerError; @@ -45,7 +44,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { }) } - fn read_workspace(&self, token: &str, params: WorkspaceId) -> FutureResult, FlowyError> { + fn read_workspace(&self, token: &str, params: WorkspaceIdPB) -> FutureResult, FlowyError> { let token = token.to_owned(); let url = self.config.workspace_url(); FutureResult::new(async move { @@ -63,7 +62,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { }) } - fn delete_workspace(&self, token: &str, params: WorkspaceId) -> FutureResult<(), FlowyError> { + fn delete_workspace(&self, token: &str, params: WorkspaceIdPB) -> FutureResult<(), FlowyError> { let token = token.to_owned(); let url = self.config.workspace_url(); FutureResult::new(async move { @@ -81,7 +80,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { }) } - fn read_view(&self, token: &str, params: ViewId) -> FutureResult, FlowyError> { + fn read_view(&self, token: &str, params: ViewIdPB) -> FutureResult, FlowyError> { let token = token.to_owned(); let url = self.config.view_url(); FutureResult::new(async move { @@ -90,7 +89,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { }) } - fn delete_view(&self, token: &str, params: RepeatedViewId) -> FutureResult<(), FlowyError> { + fn delete_view(&self, token: &str, params: RepeatedViewIdPB) -> FutureResult<(), FlowyError> { let token = token.to_owned(); let url = self.config.view_url(); FutureResult::new(async move { @@ -117,7 +116,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { }) } - fn read_app(&self, token: &str, params: AppId) -> FutureResult, FlowyError> { + fn read_app(&self, token: &str, params: AppIdPB) -> FutureResult, FlowyError> { let token = token.to_owned(); let url = self.config.app_url(); FutureResult::new(async move { @@ -135,7 +134,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { }) } - fn delete_app(&self, token: &str, params: AppId) -> FutureResult<(), FlowyError> { + fn delete_app(&self, token: &str, params: AppIdPB) -> FutureResult<(), FlowyError> { let token = token.to_owned(); let url = self.config.app_url(); FutureResult::new(async move { @@ -144,7 +143,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { }) } - fn create_trash(&self, token: &str, params: RepeatedTrashId) -> FutureResult<(), FlowyError> { + fn create_trash(&self, token: &str, params: RepeatedTrashIdPB) -> FutureResult<(), FlowyError> { let token = token.to_owned(); let url = self.config.trash_url(); FutureResult::new(async move { @@ -153,7 +152,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { }) } - fn delete_trash(&self, token: &str, params: RepeatedTrashId) -> FutureResult<(), FlowyError> { + fn delete_trash(&self, token: &str, params: RepeatedTrashIdPB) -> FutureResult<(), FlowyError> { let token = token.to_owned(); let url = self.config.trash_url(); FutureResult::new(async move { @@ -172,6 +171,7 @@ impl FolderCouldServiceV1 for FolderHttpCloudService { } } +#[allow(dead_code)] fn request_builder() -> HttpRequestBuilder { HttpRequestBuilder::new().middleware(MIDDLEWARE.clone()) } @@ -193,7 +193,7 @@ pub async fn create_workspace_request( pub async fn read_workspaces_request( _token: &str, - _params: WorkspaceId, + _params: WorkspaceIdPB, _url: &str, ) -> Result, ServerError> { // let repeated_workspace = request_builder() @@ -208,26 +208,26 @@ pub async fn read_workspaces_request( } pub async fn update_workspace_request( - token: &str, - params: UpdateWorkspaceParams, - url: &str, + _token: &str, + _params: UpdateWorkspaceParams, + _url: &str, ) -> Result<(), ServerError> { - let _ = request_builder() - .patch(&url.to_owned()) - .header(HEADER_TOKEN, token) - .protobuf(params)? - .send() - .await?; + // let _ = request_builder() + // .patch(&url.to_owned()) + // .header(HEADER_TOKEN, token) + // .protobuf(params)? + // .send() + // .await?; Ok(()) } -pub async fn delete_workspace_request(token: &str, params: WorkspaceId, url: &str) -> Result<(), ServerError> { - let _ = request_builder() - .delete(url) - .header(HEADER_TOKEN, token) - .protobuf(params)? - .send() - .await?; +pub async fn delete_workspace_request(_token: &str, _params: WorkspaceIdPB, _url: &str) -> Result<(), ServerError> { + // let _ = request_builder() + // .delete(url) + // .header(HEADER_TOKEN, token) + // .protobuf(params)? + // .send() + // .await?; Ok(()) } @@ -247,7 +247,7 @@ pub async fn create_app_request( unimplemented!() } -pub async fn read_app_request(_token: &str, _params: AppId, _url: &str) -> Result, ServerError> { +pub async fn read_app_request(_token: &str, _params: AppIdPB, _url: &str) -> Result, ServerError> { // let app = request_builder() // .get(&url.to_owned()) // .header(HEADER_TOKEN, token) @@ -259,23 +259,23 @@ pub async fn read_app_request(_token: &str, _params: AppId, _url: &str) -> Resul unimplemented!() } -pub async fn update_app_request(token: &str, params: UpdateAppParams, url: &str) -> Result<(), ServerError> { - let _ = request_builder() - .patch(&url.to_owned()) - .header(HEADER_TOKEN, token) - .protobuf(params)? - .send() - .await?; +pub async fn update_app_request(_token: &str, _params: UpdateAppParams, _url: &str) -> Result<(), ServerError> { + // let _ = request_builder() + // .patch(&url.to_owned()) + // .header(HEADER_TOKEN, token) + // .protobuf(params)? + // .send() + // .await?; Ok(()) } -pub async fn delete_app_request(token: &str, params: AppId, url: &str) -> Result<(), ServerError> { - let _ = request_builder() - .delete(&url.to_owned()) - .header(HEADER_TOKEN, token) - .protobuf(params)? - .send() - .await?; +pub async fn delete_app_request(_token: &str, _params: AppIdPB, _url: &str) -> Result<(), ServerError> { + // let _ = request_builder() + // .delete(&url.to_owned()) + // .header(HEADER_TOKEN, token) + // .protobuf(params)? + // .send() + // .await?; Ok(()) } @@ -295,7 +295,11 @@ pub async fn create_view_request( unimplemented!() } -pub async fn read_view_request(_token: &str, _params: ViewId, _url: &str) -> Result, ServerError> { +pub async fn read_view_request( + _token: &str, + _params: ViewIdPB, + _url: &str, +) -> Result, ServerError> { // let view = request_builder() // .get(&url.to_owned()) // .header(HEADER_TOKEN, token) @@ -307,43 +311,43 @@ pub async fn read_view_request(_token: &str, _params: ViewId, _url: &str) -> Res unimplemented!() } -pub async fn update_view_request(token: &str, params: UpdateViewParams, url: &str) -> Result<(), ServerError> { - let _ = request_builder() - .patch(&url.to_owned()) - .header(HEADER_TOKEN, token) - .protobuf(params)? - .send() - .await?; +pub async fn update_view_request(_token: &str, _params: UpdateViewParams, _url: &str) -> Result<(), ServerError> { + // let _ = request_builder() + // .patch(&url.to_owned()) + // .header(HEADER_TOKEN, token) + // .protobuf(params)? + // .send() + // .await?; Ok(()) } -pub async fn delete_view_request(token: &str, params: RepeatedViewId, url: &str) -> Result<(), ServerError> { - let _ = request_builder() - .delete(&url.to_owned()) - .header(HEADER_TOKEN, token) - .protobuf(params)? - .send() - .await?; +pub async fn delete_view_request(_token: &str, _params: RepeatedViewIdPB, _url: &str) -> Result<(), ServerError> { + // let _ = request_builder() + // .delete(&url.to_owned()) + // .header(HEADER_TOKEN, token) + // .protobuf(params)? + // .send() + // .await?; Ok(()) } -pub async fn create_trash_request(token: &str, params: RepeatedTrashId, url: &str) -> Result<(), ServerError> { - let _ = request_builder() - .post(&url.to_owned()) - .header(HEADER_TOKEN, token) - .protobuf(params)? - .send() - .await?; +pub async fn create_trash_request(_token: &str, _params: RepeatedTrashIdPB, _url: &str) -> Result<(), ServerError> { + // let _ = request_builder() + // .post(&url.to_owned()) + // .header(HEADER_TOKEN, token) + // .protobuf(params)? + // .send() + // .await?; Ok(()) } -pub async fn delete_trash_request(token: &str, params: RepeatedTrashId, url: &str) -> Result<(), ServerError> { - let _ = request_builder() - .delete(&url.to_owned()) - .header(HEADER_TOKEN, token) - .protobuf(params)? - .send() - .await?; +pub async fn delete_trash_request(_token: &str, _params: RepeatedTrashIdPB, _url: &str) -> Result<(), ServerError> { + // let _ = request_builder() + // .delete(&url.to_owned()) + // .header(HEADER_TOKEN, token) + // .protobuf(params)? + // .send() + // .await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-net/src/local_server/server.rs b/frontend/rust-lib/flowy-net/src/local_server/server.rs index 7625a8ee84..e6ee90df69 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/server.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/server.rs @@ -253,10 +253,10 @@ impl RevisionUser for LocalRevisionUser { } use flowy_folder::entities::{ - app::{AppId, CreateAppParams, UpdateAppParams}, - trash::RepeatedTrashId, - view::{CreateViewParams, RepeatedViewId, UpdateViewParams, ViewId}, - workspace::{CreateWorkspaceParams, UpdateWorkspaceParams, WorkspaceId}, + app::{AppIdPB, CreateAppParams, UpdateAppParams}, + trash::RepeatedTrashIdPB, + view::{CreateViewParams, RepeatedViewIdPB, UpdateViewParams, ViewIdPB}, + workspace::{CreateWorkspaceParams, UpdateWorkspaceParams, WorkspaceIdPB}, }; use flowy_folder_data_model::revision::{ gen_app_id, gen_workspace_id, AppRevision, TrashRevision, ViewRevision, WorkspaceRevision, @@ -289,7 +289,7 @@ impl FolderCouldServiceV1 for LocalServer { FutureResult::new(async { Ok(workspace) }) } - fn read_workspace(&self, _token: &str, _params: WorkspaceId) -> FutureResult, FlowyError> { + fn read_workspace(&self, _token: &str, _params: WorkspaceIdPB) -> FutureResult, FlowyError> { FutureResult::new(async { Ok(vec![]) }) } @@ -297,7 +297,7 @@ impl FolderCouldServiceV1 for LocalServer { FutureResult::new(async { Ok(()) }) } - fn delete_workspace(&self, _token: &str, _params: WorkspaceId) -> FutureResult<(), FlowyError> { + fn delete_workspace(&self, _token: &str, _params: WorkspaceIdPB) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) } @@ -320,11 +320,11 @@ impl FolderCouldServiceV1 for LocalServer { FutureResult::new(async { Ok(view) }) } - fn read_view(&self, _token: &str, _params: ViewId) -> FutureResult, FlowyError> { + fn read_view(&self, _token: &str, _params: ViewIdPB) -> FutureResult, FlowyError> { FutureResult::new(async { Ok(None) }) } - fn delete_view(&self, _token: &str, _params: RepeatedViewId) -> FutureResult<(), FlowyError> { + fn delete_view(&self, _token: &str, _params: RepeatedViewIdPB) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) } @@ -347,7 +347,7 @@ impl FolderCouldServiceV1 for LocalServer { FutureResult::new(async { Ok(app) }) } - fn read_app(&self, _token: &str, _params: AppId) -> FutureResult, FlowyError> { + fn read_app(&self, _token: &str, _params: AppIdPB) -> FutureResult, FlowyError> { FutureResult::new(async { Ok(None) }) } @@ -355,15 +355,15 @@ impl FolderCouldServiceV1 for LocalServer { FutureResult::new(async { Ok(()) }) } - fn delete_app(&self, _token: &str, _params: AppId) -> FutureResult<(), FlowyError> { + fn delete_app(&self, _token: &str, _params: AppIdPB) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) } - fn create_trash(&self, _token: &str, _params: RepeatedTrashId) -> FutureResult<(), FlowyError> { + fn create_trash(&self, _token: &str, _params: RepeatedTrashIdPB) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) } - fn delete_trash(&self, _token: &str, _params: RepeatedTrashId) -> FutureResult<(), FlowyError> { + fn delete_trash(&self, _token: &str, _params: RepeatedTrashIdPB) -> FutureResult<(), FlowyError> { FutureResult::new(async { Ok(()) }) } diff --git a/frontend/rust-lib/flowy-test/src/helper.rs b/frontend/rust-lib/flowy-test/src/helper.rs index efc4282386..dda5e31370 100644 --- a/frontend/rust-lib/flowy-test/src/helper.rs +++ b/frontend/rust-lib/flowy-test/src/helper.rs @@ -1,10 +1,10 @@ use crate::prelude::*; -use flowy_folder::entities::WorkspaceId; +use flowy_folder::entities::WorkspaceIdPB; use flowy_folder::{ entities::{ app::*, view::*, - workspace::{CreateWorkspacePayload, Workspace}, + workspace::{CreateWorkspacePayloadPB, WorkspacePB}, }, event_map::FolderEvent::{CreateWorkspace, OpenWorkspace, *}, }; @@ -18,9 +18,9 @@ use std::{fs, path::PathBuf, sync::Arc}; pub struct ViewTest { pub sdk: FlowySDKTest, - pub workspace: Workspace, - pub app: App, - pub view: View, + pub workspace: WorkspacePB, + pub app: AppPB, + pub view: ViewPB, } impl ViewTest { @@ -47,8 +47,8 @@ impl ViewTest { } } -async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> Workspace { - let request = CreateWorkspacePayload { +async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> WorkspacePB { + let request = CreateWorkspacePayloadPB { name: name.to_owned(), desc: desc.to_owned(), }; @@ -58,12 +58,12 @@ async fn create_workspace(sdk: &FlowySDKTest, name: &str, desc: &str) -> Workspa .payload(request) .async_send() .await - .parse::(); + .parse::(); workspace } async fn open_workspace(sdk: &FlowySDKTest, workspace_id: &str) { - let payload = WorkspaceId { + let payload = WorkspaceIdPB { value: Some(workspace_id.to_owned()), }; let _ = FolderEventBuilder::new(sdk.clone()) @@ -73,8 +73,8 @@ async fn open_workspace(sdk: &FlowySDKTest, workspace_id: &str) { .await; } -async fn create_app(sdk: &FlowySDKTest, name: &str, desc: &str, workspace_id: &str) -> App { - let create_app_request = CreateAppPayload { +async fn create_app(sdk: &FlowySDKTest, name: &str, desc: &str, workspace_id: &str) -> AppPB { + let create_app_request = CreateAppPayloadPB { workspace_id: workspace_id.to_owned(), name: name.to_string(), desc: desc.to_string(), @@ -86,12 +86,12 @@ async fn create_app(sdk: &FlowySDKTest, name: &str, desc: &str, workspace_id: &s .payload(create_app_request) .async_send() .await - .parse::(); + .parse::(); app } -async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataType, data: Vec) -> View { - let request = CreateViewPayload { +async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataType, data: Vec) -> ViewPB { + let request = CreateViewPayloadPB { belong_to_id: app_id.to_string(), name: "View A".to_string(), desc: "".to_string(), @@ -106,7 +106,7 @@ async fn create_view(sdk: &FlowySDKTest, app_id: &str, data_type: ViewDataType, .payload(request) .async_send() .await - .parse::(); + .parse::(); view } From 8e18d3a93784caecc63b037e8fbdc37ee50ae376 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 19 Jul 2022 14:40:56 +0800 Subject: [PATCH 042/112] chore: reanme flowy-user crate --- .../app_flowy/lib/startup/deps_resolver.dart | 10 +++++----- .../lib/user/application/auth_service.dart | 10 +++++----- .../lib/user/application/sign_in_bloc.dart | 4 ++-- .../lib/user/application/sign_up_bloc.dart | 4 ++-- .../lib/user/application/user_listener.dart | 12 +++++------ .../lib/user/application/user_service.dart | 4 ++-- .../application/user_settings_service.dart | 6 +++--- .../app_flowy/lib/user/domain/auth_state.dart | 4 ++-- .../lib/user/presentation/router.dart | 10 +++++----- .../lib/user/presentation/sign_in_screen.dart | 4 ++-- .../lib/user/presentation/sign_up_screen.dart | 4 ++-- .../user/presentation/skip_log_in_screen.dart | 2 +- .../lib/user/presentation/welcome_screen.dart | 2 +- .../lib/workspace/application/appearance.dart | 2 +- .../workspace/application/home/home_bloc.dart | 2 +- .../application/menu/menu_user_bloc.dart | 12 +++++------ .../workspace/workspace_listener.dart | 4 ++-- .../presentation/home/home_screen.dart | 4 ++-- .../presentation/home/menu/menu.dart | 4 ++-- .../presentation/home/menu/menu_user.dart | 4 ++-- frontend/app_flowy/test/util/test_env.dart | 2 +- .../app_flowy/test/workspace_bloc_test.dart | 2 +- .../flowy-net/src/http_server/user.rs | 6 +++--- .../flowy-net/src/local_server/server.rs | 6 +++--- .../rust-lib/flowy-test/src/event_builder.rs | 6 +++--- frontend/rust-lib/flowy-test/src/helper.rs | 18 ++++++++--------- frontend/rust-lib/flowy-test/src/lib.rs | 4 ++-- .../rust-lib/flowy-user/src/entities/auth.rs | 8 ++++---- .../flowy-user/src/entities/user_profile.rs | 14 +++++++------ .../flowy-user/src/entities/user_setting.rs | 18 ++++++++--------- frontend/rust-lib/flowy-user/src/event_map.rs | 18 ++++++++--------- .../flowy-user/src/handlers/auth_handler.rs | 8 ++++---- .../flowy-user/src/handlers/user_handler.rs | 16 +++++++-------- .../flowy-user/src/services/database.rs | 6 +++--- .../flowy-user/src/services/notifier.rs | 6 +++--- .../flowy-user/src/services/user_session.rs | 14 ++++++------- .../flowy-user/tests/event/auth_test.rs | 14 ++++++------- .../tests/event/user_profile_test.rs | 20 +++++++++---------- 38 files changed, 148 insertions(+), 146 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 6f1d7e64a4..1864a2aa62 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -51,14 +51,14 @@ void _resolveHomeDeps(GetIt getIt) { getIt.registerSingleton(MenuSharedState()); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (user, _) => UserListener(userProfile: user), ); // getIt.registerLazySingleton(() => HomeStackManager()); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (user, _) => WelcomeBloc( userService: UserService(userId: user.id), userWorkspaceListener: UserWorkspaceListener(userProfile: user), @@ -73,7 +73,7 @@ void _resolveHomeDeps(GetIt getIt) { void _resolveFolderDeps(GetIt getIt) { //workspace - getIt.registerFactoryParam( + getIt.registerFactoryParam( (user, workspaceId) => WorkspaceListener(user: user, workspaceId: workspaceId)); // ViewPB @@ -90,14 +90,14 @@ void _resolveFolderDeps(GetIt getIt) { ); //Menu - getIt.registerFactoryParam( + getIt.registerFactoryParam( (user, workspaceId) => MenuBloc( workspaceId: workspaceId, listener: getIt(param1: user, param2: workspaceId), ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (user, _) => MenuUserBloc(user), ); diff --git a/frontend/app_flowy/lib/user/application/auth_service.dart b/frontend/app_flowy/lib/user/application/auth_service.dart index 28f7dc5d0e..c2ce625ccf 100644 --- a/frontend/app_flowy/lib/user/application/auth_service.dart +++ b/frontend/app_flowy/lib/user/application/auth_service.dart @@ -1,21 +1,21 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show SignInPayload, SignUpPayload, UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show SignInPayloadPB, SignUpPayloadPB, UserProfilePB; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; class AuthService { - Future> signIn({required String? email, required String? password}) { + Future> signIn({required String? email, required String? password}) { // - final request = SignInPayload.create() + final request = SignInPayloadPB.create() ..email = email ?? '' ..password = password ?? ''; return UserEventSignIn(request).send(); } - Future> signUp( + Future> signUp( {required String? name, required String? password, required String? email}) { - final request = SignUpPayload.create() + final request = SignUpPayloadPB.create() ..email = email ?? '' ..name = name ?? '' ..password = password ?? ''; diff --git a/frontend/app_flowy/lib/user/application/sign_in_bloc.dart b/frontend/app_flowy/lib/user/application/sign_in_bloc.dart index 45b6ee1eb5..1b5838d9c4 100644 --- a/frontend/app_flowy/lib/user/application/sign_in_bloc.dart +++ b/frontend/app_flowy/lib/user/application/sign_in_bloc.dart @@ -2,7 +2,7 @@ import 'package:app_flowy/user/application/auth_service.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -69,7 +69,7 @@ class SignInState with _$SignInState { required bool isSubmitting, required Option passwordError, required Option emailError, - required Option> successOrFail, + required Option> successOrFail, }) = _SignInState; factory SignInState.initial() => SignInState( diff --git a/frontend/app_flowy/lib/user/application/sign_up_bloc.dart b/frontend/app_flowy/lib/user/application/sign_up_bloc.dart index b94a02bf09..0c103fd4d7 100644 --- a/frontend/app_flowy/lib/user/application/sign_up_bloc.dart +++ b/frontend/app_flowy/lib/user/application/sign_up_bloc.dart @@ -2,7 +2,7 @@ import 'package:app_flowy/user/application/auth_service.dart'; import 'package:dartz/dartz.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_sdk/protobuf/flowy-error-code/code.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -120,7 +120,7 @@ class SignUpState with _$SignUpState { required Option passwordError, required Option repeatPasswordError, required Option emailError, - required Option> successOrFail, + required Option> successOrFail, }) = _SignUpState; factory SignUpState.initial() => SignUpState( diff --git a/frontend/app_flowy/lib/user/application/user_listener.dart b/frontend/app_flowy/lib/user/application/user_listener.dart index ec3cd5ac1d..5483926e71 100644 --- a/frontend/app_flowy/lib/user/application/user_listener.dart +++ b/frontend/app_flowy/lib/user/application/user_listener.dart @@ -13,7 +13,7 @@ import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/dart_notification.pb.dart' as user; import 'package:flowy_sdk/rust_stream.dart'; -typedef UserProfileNotifyValue = Either; +typedef UserProfileNotifyValue = Either; typedef AuthNotifyValue = Either; class UserListener { @@ -22,9 +22,9 @@ class UserListener { PublishNotifier? _profileNotifier = PublishNotifier(); UserNotificationParser? _userParser; - final UserProfile _userProfile; + final UserProfilePB _userProfile; UserListener({ - required UserProfile userProfile, + required UserProfilePB userProfile, }) : _userProfile = userProfile; void start({ @@ -65,7 +65,7 @@ class UserListener { break; case user.UserNotification.UserProfileUpdated: result.fold( - (payload) => _profileNotifier?.value = left(UserProfile.fromBuffer(payload)), + (payload) => _profileNotifier?.value = left(UserProfilePB.fromBuffer(payload)), (error) => _profileNotifier?.value = right(error), ); break; @@ -84,10 +84,10 @@ class UserWorkspaceListener { PublishNotifier? _settingChangedNotifier = PublishNotifier(); FolderNotificationListener? _listener; - final UserProfile _userProfile; + final UserProfilePB _userProfile; UserWorkspaceListener({ - required UserProfile userProfile, + required UserProfilePB userProfile, }) : _userProfile = userProfile; void start({ diff --git a/frontend/app_flowy/lib/user/application/user_service.dart b/frontend/app_flowy/lib/user/application/user_service.dart index 8685205567..48bea6aa41 100644 --- a/frontend/app_flowy/lib/user/application/user_service.dart +++ b/frontend/app_flowy/lib/user/application/user_service.dart @@ -11,7 +11,7 @@ class UserService { UserService({ required this.userId, }); - Future> getUserProfile({required String userId}) { + Future> getUserProfile({required String userId}) { return UserEventGetUserProfile().send(); } @@ -20,7 +20,7 @@ class UserService { String? password, String? email, }) { - var payload = UpdateUserProfilePayload.create()..id = userId; + var payload = UpdateUserProfilePayloadPB.create()..id = userId; if (name != null) { payload.name = name; diff --git a/frontend/app_flowy/lib/user/application/user_settings_service.dart b/frontend/app_flowy/lib/user/application/user_settings_service.dart index eb93ab150d..28309d202c 100644 --- a/frontend/app_flowy/lib/user/application/user_settings_service.dart +++ b/frontend/app_flowy/lib/user/application/user_settings_service.dart @@ -5,11 +5,11 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/user_setting.pb.dart'; class UserSettingsService { - Future getAppearanceSettings() async { + Future getAppearanceSettings() async { final result = await UserEventGetAppearanceSetting().send(); return result.fold( - (AppearanceSettings setting) { + (AppearanceSettingsPB setting) { return setting; }, (error) { @@ -18,7 +18,7 @@ class UserSettingsService { ); } - Future> setAppearanceSettings(AppearanceSettings settings) { + Future> setAppearanceSettings(AppearanceSettingsPB settings) { return UserEventSetAppearanceSetting(settings).send(); } } diff --git a/frontend/app_flowy/lib/user/domain/auth_state.dart b/frontend/app_flowy/lib/user/domain/auth_state.dart index e2d3a33b09..ae0c259573 100644 --- a/frontend/app_flowy/lib/user/domain/auth_state.dart +++ b/frontend/app_flowy/lib/user/domain/auth_state.dart @@ -1,11 +1,11 @@ -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'auth_state.freezed.dart'; @freezed class AuthState with _$AuthState { - const factory AuthState.authenticated(UserProfile userProfile) = Authenticated; + const factory AuthState.authenticated(UserProfilePB userProfile) = Authenticated; const factory AuthState.unauthenticated(FlowyError error) = Unauthenticated; const factory AuthState.initial() = _Initial; } diff --git a/frontend/app_flowy/lib/user/presentation/router.dart b/frontend/app_flowy/lib/user/presentation/router.dart index 5f863a8d99..2928154ebe 100644 --- a/frontend/app_flowy/lib/user/presentation/router.dart +++ b/frontend/app_flowy/lib/user/presentation/router.dart @@ -7,7 +7,7 @@ import 'package:app_flowy/user/presentation/welcome_screen.dart'; import 'package:app_flowy/workspace/presentation/home/home_screen.dart'; import 'package:flowy_infra/time/duration.dart'; import 'package:flowy_infra_ui/widget/route/animation.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flowy_sdk/protobuf/flowy-folder/protobuf.dart'; import 'package:flutter/material.dart'; @@ -16,7 +16,7 @@ class AuthRouter { // TODO: implement showForgetPasswordScreen } - void pushWelcomeScreen(BuildContext context, UserProfile userProfile) { + void pushWelcomeScreen(BuildContext context, UserProfilePB userProfile) { getIt().pushWelcomeScreen(context, userProfile); } @@ -28,7 +28,7 @@ class AuthRouter { ); } - void pushHomeScreen(BuildContext context, UserProfile profile, CurrentWorkspaceSettingPB workspaceSetting) { + void pushHomeScreen(BuildContext context, UserProfilePB profile, CurrentWorkspaceSettingPB workspaceSetting) { Navigator.push( context, PageRoutes.fade(() => HomeScreen(profile, workspaceSetting), RouteDurations.slow.inMilliseconds * .001), @@ -37,7 +37,7 @@ class AuthRouter { } class SplashRoute { - Future pushWelcomeScreen(BuildContext context, UserProfile userProfile) async { + Future pushWelcomeScreen(BuildContext context, UserProfilePB userProfile) async { final screen = WelcomeScreen(userProfile: userProfile); final workspaceId = await Navigator.of(context).push( PageRoutes.fade( @@ -49,7 +49,7 @@ class SplashRoute { pushHomeScreen(context, userProfile, workspaceId); } - void pushHomeScreen(BuildContext context, UserProfile userProfile, CurrentWorkspaceSettingPB workspaceSetting) { + void pushHomeScreen(BuildContext context, UserProfilePB userProfile, CurrentWorkspaceSettingPB workspaceSetting) { Navigator.push( context, PageRoutes.fade(() => HomeScreen(userProfile, workspaceSetting), RouteDurations.slow.inMilliseconds * .001), diff --git a/frontend/app_flowy/lib/user/presentation/sign_in_screen.dart b/frontend/app_flowy/lib/user/presentation/sign_in_screen.dart index baa8ef0ccb..ee3600e782 100644 --- a/frontend/app_flowy/lib/user/presentation/sign_in_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/sign_in_screen.dart @@ -10,7 +10,7 @@ import 'package:flowy_infra_ui/widget/rounded_input_field.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/style_widget/snap_bar.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:dartz/dartz.dart'; @@ -39,7 +39,7 @@ class SignInScreen extends StatelessWidget { ); } - void _handleSuccessOrFail(Either result, BuildContext context) { + void _handleSuccessOrFail(Either result, BuildContext context) { result.fold( (user) => router.pushWelcomeScreen(context, user), (error) => showSnapBar(context, error.msg), diff --git a/frontend/app_flowy/lib/user/presentation/sign_up_screen.dart b/frontend/app_flowy/lib/user/presentation/sign_up_screen.dart index 6a0b8f1d85..d0cb7f8b90 100644 --- a/frontend/app_flowy/lib/user/presentation/sign_up_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/sign_up_screen.dart @@ -8,7 +8,7 @@ import 'package:flowy_infra_ui/widget/rounded_button.dart'; import 'package:flowy_infra_ui/widget/rounded_input_field.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flowy_infra_ui/style_widget/snap_bar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -36,7 +36,7 @@ class SignUpScreen extends StatelessWidget { ); } - void _handleSuccessOrFail(BuildContext context, Either result) { + void _handleSuccessOrFail(BuildContext context, Either result) { result.fold( (user) => router.pushWelcomeScreen(context, user), (error) => showSnapBar(context, error.msg), diff --git a/frontend/app_flowy/lib/user/presentation/skip_log_in_screen.dart b/frontend/app_flowy/lib/user/presentation/skip_log_in_screen.dart index a6feeae3ff..6e3ae5ea52 100644 --- a/frontend/app_flowy/lib/user/presentation/skip_log_in_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/skip_log_in_screen.dart @@ -116,7 +116,7 @@ class _SkipLogInScreenState extends State { void _openCurrentWorkspace( BuildContext context, - UserProfile user, + UserProfilePB user, dartz.Either workspacesOrError, ) { workspacesOrError.fold( diff --git a/frontend/app_flowy/lib/user/presentation/welcome_screen.dart b/frontend/app_flowy/lib/user/presentation/welcome_screen.dart index 45a3ce9bcc..31b06d8bd1 100644 --- a/frontend/app_flowy/lib/user/presentation/welcome_screen.dart +++ b/frontend/app_flowy/lib/user/presentation/welcome_screen.dart @@ -12,7 +12,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; class WelcomeScreen extends StatelessWidget { - final UserProfile userProfile; + final UserProfilePB userProfile; const WelcomeScreen({ Key? key, required this.userProfile, diff --git a/frontend/app_flowy/lib/workspace/application/appearance.dart b/frontend/app_flowy/lib/workspace/application/appearance.dart index f3ff7801ce..0e47fa2be6 100644 --- a/frontend/app_flowy/lib/workspace/application/appearance.dart +++ b/frontend/app_flowy/lib/workspace/application/appearance.dart @@ -9,7 +9,7 @@ import 'package:flutter/material.dart'; import 'package:easy_localization/easy_localization.dart'; class AppearanceSettingModel extends ChangeNotifier with EquatableMixin { - AppearanceSettings setting; + AppearanceSettingsPB setting; AppTheme _theme; Locale _locale; Timer? _saveOperation; diff --git a/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart b/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart index 21f29d2658..a4ddef0945 100644 --- a/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart @@ -13,7 +13,7 @@ part 'home_bloc.freezed.dart'; class HomeBloc extends Bloc { final UserWorkspaceListener _listener; - HomeBloc(UserProfile user, CurrentWorkspaceSettingPB workspaceSetting) + HomeBloc(UserProfilePB user, CurrentWorkspaceSettingPB workspaceSetting) : _listener = UserWorkspaceListener(userProfile: user), super(HomeState.initial(workspaceSetting)) { on((event, emit) async { diff --git a/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart b/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart index ce222e4eac..0f30bb9d45 100644 --- a/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart @@ -14,7 +14,7 @@ class MenuUserBloc extends Bloc { final UserService _userService; final UserListener _userListener; final UserWorkspaceListener _userWorkspaceListener; - final UserProfile userProfile; + final UserProfilePB userProfile; MenuUserBloc(this.userProfile) : _userListener = UserListener(userProfile: userProfile), @@ -31,7 +31,7 @@ class MenuUserBloc extends Bloc { fetchWorkspaces: () async { // }, - didReceiveUserProfile: (UserProfile newUserProfile) { + didReceiveUserProfile: (UserProfilePB newUserProfile) { emit(state.copyWith(userProfile: newUserProfile)); }, updateUserName: (String name) { @@ -58,7 +58,7 @@ class MenuUserBloc extends Bloc { result.fold((l) => null, (error) => Log.error(error)); } - void _profileUpdated(Either userProfileOrFailed) { + void _profileUpdated(Either userProfileOrFailed) { userProfileOrFailed.fold( (newUserProfile) => add(MenuUserEvent.didReceiveUserProfile(newUserProfile)), (err) => Log.error(err), @@ -75,18 +75,18 @@ class MenuUserEvent with _$MenuUserEvent { const factory MenuUserEvent.initial() = _Initial; const factory MenuUserEvent.fetchWorkspaces() = _FetchWorkspaces; const factory MenuUserEvent.updateUserName(String name) = _UpdateUserName; - const factory MenuUserEvent.didReceiveUserProfile(UserProfile newUserProfile) = _DidReceiveUserProfile; + const factory MenuUserEvent.didReceiveUserProfile(UserProfilePB newUserProfile) = _DidReceiveUserProfile; } @freezed class MenuUserState with _$MenuUserState { const factory MenuUserState({ - required UserProfile userProfile, + required UserProfilePB userProfile, required Option> workspaces, required Either successOrFailure, }) = _MenuUserState; - factory MenuUserState.initial(UserProfile userProfile) => MenuUserState( + factory MenuUserState.initial(UserProfilePB userProfile) => MenuUserState( userProfile: userProfile, workspaces: none(), successOrFailure: left(unit), diff --git a/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart b/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart index dab4d7cbcf..2d7a100e8b 100644 --- a/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/workspace/workspace_listener.dart @@ -3,7 +3,7 @@ import 'dart:typed_data'; import 'package:app_flowy/core/folder_notification.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_infra/notifier.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flowy_sdk/protobuf/flowy-folder/app.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; @@ -17,7 +17,7 @@ class WorkspaceListener { PublishNotifier? _workspaceUpdatedNotifier = PublishNotifier(); FolderNotificationListener? _listener; - final UserProfile user; + final UserProfilePB user; final String workspaceId; WorkspaceListener({ diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart index a9aa15a77a..f3a9f6773a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart @@ -5,7 +5,7 @@ import 'package:app_flowy/workspace/presentation/widgets/float_bubble/question_b import 'package:app_flowy/startup/startup.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_infra_ui/style_widget/container.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flowy_sdk/protobuf/flowy-folder/protobuf.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -18,7 +18,7 @@ import 'home_stack.dart'; import 'menu/menu.dart'; class HomeScreen extends StatefulWidget { - final UserProfile user; + final UserProfilePB user; final CurrentWorkspaceSettingPB workspaceSetting; const HomeScreen(this.user, this.workspaceSetting, {Key? key}) : super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart index 529441df82..ef5e20bb6b 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart @@ -10,7 +10,7 @@ import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/workspace.pb.dart'; import 'package:flutter/material.dart'; @@ -32,7 +32,7 @@ import 'menu_user.dart'; class HomeMenu extends StatelessWidget { final PublishNotifier _collapsedNotifier; - final UserProfile user; + final UserProfilePB user; final CurrentWorkspaceSettingPB workspaceSetting; const HomeMenu({ diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart index 6b75c9ef3f..6c9ffdece2 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu_user.dart @@ -6,14 +6,14 @@ import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:easy_localization/easy_localization.dart'; class MenuUser extends StatelessWidget { - final UserProfile user; + final UserProfilePB user; MenuUser(this.user, {Key? key}) : super(key: ValueKey(user.id)); @override diff --git a/frontend/app_flowy/test/util/test_env.dart b/frontend/app_flowy/test/util/test_env.dart index 40006295a4..1743e4b920 100644 --- a/frontend/app_flowy/test/util/test_env.dart +++ b/frontend/app_flowy/test/util/test_env.dart @@ -14,7 +14,7 @@ class FlowyTest { return FlowyTest(); } - Future signIn() async { + Future signIn() async { final authService = getIt(); const password = "AppFlowy123@"; final uid = uuid(); diff --git a/frontend/app_flowy/test/workspace_bloc_test.dart b/frontend/app_flowy/test/workspace_bloc_test.dart index 680726b401..d0b898cc42 100644 --- a/frontend/app_flowy/test/workspace_bloc_test.dart +++ b/frontend/app_flowy/test/workspace_bloc_test.dart @@ -7,7 +7,7 @@ import 'package:bloc_test/bloc_test.dart'; import 'util/test_env.dart'; void main() { - UserProfile? userInfo; + UserProfilePB? userInfo; setUpAll(() async { final flowyTest = await FlowyTest.setup(); userInfo = await flowyTest.signIn(); diff --git a/frontend/rust-lib/flowy-net/src/http_server/user.rs b/frontend/rust-lib/flowy-net/src/http_server/user.rs index faf5621161..7768c91bb6 100644 --- a/frontend/rust-lib/flowy-net/src/http_server/user.rs +++ b/frontend/rust-lib/flowy-net/src/http_server/user.rs @@ -1,7 +1,7 @@ use crate::{configuration::*, request::HttpRequestBuilder}; use flowy_error::FlowyError; use flowy_user::entities::{ - SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfile, + SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfilePB, }; use flowy_user::event_map::UserCloudService; use http_flowy::errors::ServerError; @@ -51,7 +51,7 @@ impl UserCloudService for UserHttpCloudService { }) } - fn get_user(&self, token: &str) -> FutureResult { + fn get_user(&self, token: &str) -> FutureResult { let token = token.to_owned(); let url = self.config.user_profile_url(); FutureResult::new(async move { @@ -92,7 +92,7 @@ pub async fn user_sign_out_request(token: &str, url: &str) -> Result<(), ServerE Ok(()) } -pub async fn get_user_profile_request(token: &str, url: &str) -> Result { +pub async fn get_user_profile_request(token: &str, url: &str) -> Result { let user_profile = request_builder() .get(&url.to_owned()) .header(HEADER_TOKEN, token) diff --git a/frontend/rust-lib/flowy-net/src/local_server/server.rs b/frontend/rust-lib/flowy-net/src/local_server/server.rs index e6ee90df69..338697f432 100644 --- a/frontend/rust-lib/flowy-net/src/local_server/server.rs +++ b/frontend/rust-lib/flowy-net/src/local_server/server.rs @@ -263,7 +263,7 @@ use flowy_folder_data_model::revision::{ }; use flowy_text_block::BlockCloudService; use flowy_user::entities::{ - SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfile, + SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfilePB, }; use flowy_user::event_map::UserCloudService; use lib_infra::{future::FutureResult, util::timestamp}; @@ -405,8 +405,8 @@ impl UserCloudService for LocalServer { FutureResult::new(async { Ok(()) }) } - fn get_user(&self, _token: &str) -> FutureResult { - FutureResult::new(async { Ok(UserProfile::default()) }) + fn get_user(&self, _token: &str) -> FutureResult { + FutureResult::new(async { Ok(UserProfilePB::default()) }) } fn ws_addr(&self) -> String { diff --git a/frontend/rust-lib/flowy-test/src/event_builder.rs b/frontend/rust-lib/flowy-test/src/event_builder.rs index ed6f3c3bc8..d9841d6b4a 100644 --- a/frontend/rust-lib/flowy-test/src/event_builder.rs +++ b/frontend/rust-lib/flowy-test/src/event_builder.rs @@ -1,5 +1,5 @@ use crate::FlowySDKTest; -use flowy_user::{entities::UserProfile, errors::FlowyError}; +use flowy_user::{entities::UserProfilePB, errors::FlowyError}; use lib_dispatch::prelude::{EventDispatcher, EventResponse, FromBytes, ModuleRequest, StatusCode, ToBytes, *}; use std::{ convert::TryFrom, @@ -14,7 +14,7 @@ impl FolderEventBuilder { pub fn new(sdk: FlowySDKTest) -> Self { EventBuilder::test(TestContext::new(sdk)) } - pub fn user_profile(&self) -> &Option { + pub fn user_profile(&self) -> &Option { &self.user_profile } } @@ -24,7 +24,7 @@ pub type UserModuleEventBuilder = FolderEventBuilder; #[derive(Clone)] pub struct EventBuilder { context: TestContext, - user_profile: Option, + user_profile: Option, err_phantom: PhantomData, } diff --git a/frontend/rust-lib/flowy-test/src/helper.rs b/frontend/rust-lib/flowy-test/src/helper.rs index dda5e31370..1265bd695c 100644 --- a/frontend/rust-lib/flowy-test/src/helper.rs +++ b/frontend/rust-lib/flowy-test/src/helper.rs @@ -9,7 +9,7 @@ use flowy_folder::{ event_map::FolderEvent::{CreateWorkspace, OpenWorkspace, *}, }; use flowy_user::{ - entities::{SignInPayload, SignUpPayload, UserProfile}, + entities::{SignInPayloadPB, SignUpPayloadPB, UserProfilePB}, errors::FlowyError, event_map::UserEvent::{InitUser, SignIn, SignOut, SignUp}, }; @@ -138,13 +138,13 @@ pub fn login_password() -> String { } pub struct SignUpContext { - pub user_profile: UserProfile, + pub user_profile: UserProfilePB, pub password: String, } pub fn sign_up(dispatch: Arc) -> SignUpContext { let password = login_password(); - let payload = SignUpPayload { + let payload = SignUpPayloadPB { email: random_email(), name: "app flowy".to_string(), password: password.clone(), @@ -154,7 +154,7 @@ pub fn sign_up(dispatch: Arc) -> SignUpContext { let request = ModuleRequest::new(SignUp).payload(payload); let user_profile = EventDispatcher::sync_send(dispatch, request) - .parse::() + .parse::() .unwrap() .unwrap(); @@ -164,7 +164,7 @@ pub fn sign_up(dispatch: Arc) -> SignUpContext { pub async fn async_sign_up(dispatch: Arc) -> SignUpContext { let password = login_password(); let email = random_email(); - let payload = SignUpPayload { + let payload = SignUpPayloadPB { email, name: "app flowy".to_string(), password: password.clone(), @@ -175,7 +175,7 @@ pub async fn async_sign_up(dispatch: Arc) -> SignUpContext { let request = ModuleRequest::new(SignUp).payload(payload); let user_profile = EventDispatcher::async_send(dispatch.clone(), request) .await - .parse::() + .parse::() .unwrap() .unwrap(); @@ -189,8 +189,8 @@ pub async fn init_user_setting(dispatch: Arc) { } #[allow(dead_code)] -fn sign_in(dispatch: Arc) -> UserProfile { - let payload = SignInPayload { +fn sign_in(dispatch: Arc) -> UserProfilePB { + let payload = SignInPayloadPB { email: login_email(), password: login_password(), name: "rust".to_owned(), @@ -200,7 +200,7 @@ fn sign_in(dispatch: Arc) -> UserProfile { let request = ModuleRequest::new(SignIn).payload(payload); EventDispatcher::sync_send(dispatch, request) - .parse::() + .parse::() .unwrap() .unwrap() } diff --git a/frontend/rust-lib/flowy-test/src/lib.rs b/frontend/rust-lib/flowy-test/src/lib.rs index 70159edf19..8f6aacb44d 100644 --- a/frontend/rust-lib/flowy-test/src/lib.rs +++ b/frontend/rust-lib/flowy-test/src/lib.rs @@ -4,7 +4,7 @@ pub mod helper; use crate::helper::*; use flowy_net::{get_client_server_configuration, ClientServerConfiguration}; use flowy_sdk::{FlowySDK, FlowySDKConfig}; -use flowy_user::entities::UserProfile; +use flowy_user::entities::UserProfilePB; use nanoid::nanoid; pub mod prelude { @@ -47,7 +47,7 @@ impl FlowySDKTest { context } - pub async fn init_user(&self) -> UserProfile { + pub async fn init_user(&self) -> UserProfilePB { let context = async_sign_up(self.inner.dispatcher()).await; init_user_setting(self.inner.dispatcher()).await; context.user_profile diff --git a/frontend/rust-lib/flowy-user/src/entities/auth.rs b/frontend/rust-lib/flowy-user/src/entities/auth.rs index 14224ae231..f7625b37d7 100644 --- a/frontend/rust-lib/flowy-user/src/entities/auth.rs +++ b/frontend/rust-lib/flowy-user/src/entities/auth.rs @@ -4,7 +4,7 @@ use flowy_derive::ProtoBuf; use std::convert::TryInto; #[derive(ProtoBuf, Default)] -pub struct SignInPayload { +pub struct SignInPayloadPB { #[pb(index = 1)] pub email: String, @@ -42,7 +42,7 @@ pub struct SignInResponse { pub token: String, } -impl TryInto for SignInPayload { +impl TryInto for SignInPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { @@ -58,7 +58,7 @@ impl TryInto for SignInPayload { } #[derive(ProtoBuf, Default)] -pub struct SignUpPayload { +pub struct SignUpPayloadPB { #[pb(index = 1)] pub email: String, @@ -68,7 +68,7 @@ pub struct SignUpPayload { #[pb(index = 3)] pub password: String, } -impl TryInto for SignUpPayload { +impl TryInto for SignUpPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs index 82553e8050..276894ffc8 100644 --- a/frontend/rust-lib/flowy-user/src/entities/user_profile.rs +++ b/frontend/rust-lib/flowy-user/src/entities/user_profile.rs @@ -7,13 +7,13 @@ use crate::{ }; #[derive(Default, ProtoBuf)] -pub struct UserToken { +pub struct UserTokenPB { #[pb(index = 1)] pub token: String, } #[derive(ProtoBuf, Default, Debug, PartialEq, Eq, Clone)] -pub struct UserProfile { +pub struct UserProfilePB { #[pb(index = 1)] pub id: String, @@ -28,7 +28,7 @@ pub struct UserProfile { } #[derive(ProtoBuf, Default)] -pub struct UpdateUserProfilePayload { +pub struct UpdateUserProfilePayloadPB { #[pb(index = 1)] pub id: String, @@ -42,7 +42,7 @@ pub struct UpdateUserProfilePayload { pub password: Option, } -impl UpdateUserProfilePayload { +impl UpdateUserProfilePayloadPB { pub fn new(id: &str) -> Self { Self { id: id.to_owned(), @@ -85,7 +85,9 @@ impl UpdateUserProfileParams { pub fn new(user_id: &str) -> Self { Self { id: user_id.to_owned(), - ..Default::default() + name: None, + email: None, + password: None, } } @@ -105,7 +107,7 @@ impl UpdateUserProfileParams { } } -impl TryInto for UpdateUserProfilePayload { +impl TryInto for UpdateUserProfilePayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { diff --git a/frontend/rust-lib/flowy-user/src/entities/user_setting.rs b/frontend/rust-lib/flowy-user/src/entities/user_setting.rs index 8f7beadb4a..23c74b6d5f 100644 --- a/frontend/rust-lib/flowy-user/src/entities/user_setting.rs +++ b/frontend/rust-lib/flowy-user/src/entities/user_setting.rs @@ -2,22 +2,22 @@ use flowy_derive::ProtoBuf; use serde::{Deserialize, Serialize}; #[derive(ProtoBuf, Default, Debug, Clone)] -pub struct UserPreferences { +pub struct UserPreferencesPB { #[pb(index = 1)] user_id: String, #[pb(index = 2)] - appearance_setting: AppearanceSettings, + appearance_setting: AppearanceSettingsPB, } #[derive(ProtoBuf, Serialize, Deserialize, Debug, Clone)] -pub struct AppearanceSettings { +pub struct AppearanceSettingsPB { #[pb(index = 1)] pub theme: String, #[pb(index = 2)] #[serde(default)] - pub locale: LocaleSettings, + pub locale: LocaleSettingsPB, #[pb(index = 3)] #[serde(default = "DEFAULT_RESET_VALUE")] @@ -27,7 +27,7 @@ pub struct AppearanceSettings { const DEFAULT_RESET_VALUE: fn() -> bool = || APPEARANCE_RESET_AS_DEFAULT; #[derive(ProtoBuf, Serialize, Deserialize, Debug, Clone)] -pub struct LocaleSettings { +pub struct LocaleSettingsPB { #[pb(index = 1)] pub language_code: String, @@ -35,7 +35,7 @@ pub struct LocaleSettings { pub country_code: String, } -impl std::default::Default for LocaleSettings { +impl std::default::Default for LocaleSettingsPB { fn default() -> Self { Self { language_code: "en".to_owned(), @@ -47,11 +47,11 @@ impl std::default::Default for LocaleSettings { pub const APPEARANCE_DEFAULT_THEME: &str = "light"; const APPEARANCE_RESET_AS_DEFAULT: bool = true; -impl std::default::Default for AppearanceSettings { +impl std::default::Default for AppearanceSettingsPB { fn default() -> Self { - AppearanceSettings { + AppearanceSettingsPB { theme: APPEARANCE_DEFAULT_THEME.to_owned(), - locale: LocaleSettings::default(), + locale: LocaleSettingsPB::default(), reset_as_default: APPEARANCE_RESET_AS_DEFAULT, } } diff --git a/frontend/rust-lib/flowy-user/src/event_map.rs b/frontend/rust-lib/flowy-user/src/event_map.rs index 348da177d3..ced1ede179 100644 --- a/frontend/rust-lib/flowy-user/src/event_map.rs +++ b/frontend/rust-lib/flowy-user/src/event_map.rs @@ -1,5 +1,5 @@ use crate::entities::{ - SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfile, + SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfilePB, }; use crate::{errors::FlowyError, handlers::*, services::UserSession}; use lib_dispatch::prelude::*; @@ -26,7 +26,7 @@ pub trait UserCloudService: Send + Sync { fn sign_in(&self, params: SignInParams) -> FutureResult; fn sign_out(&self, token: &str) -> FutureResult<(), FlowyError>; fn update_user(&self, token: &str, params: UpdateUserProfileParams) -> FutureResult<(), FlowyError>; - fn get_user(&self, token: &str) -> FutureResult; + fn get_user(&self, token: &str) -> FutureResult; fn ws_addr(&self) -> String; } @@ -39,27 +39,27 @@ pub enum UserEvent { #[event()] InitUser = 0, - #[event(input = "SignInPayload", output = "UserProfile")] + #[event(input = "SignInPayloadPB", output = "UserProfilePB")] SignIn = 1, - #[event(input = "SignUpPayload", output = "UserProfile")] + #[event(input = "SignUpPayloadPB", output = "UserProfilePB")] SignUp = 2, #[event(passthrough)] SignOut = 3, - #[event(input = "UpdateUserProfilePayload")] + #[event(input = "UpdateUserProfilePayloadPB")] UpdateUserProfile = 4, - #[event(output = "UserProfile")] + #[event(output = "UserProfilePB")] GetUserProfile = 5, - #[event(output = "UserProfile")] + #[event(output = "UserProfilePB")] CheckUser = 6, - #[event(input = "AppearanceSettings")] + #[event(input = "AppearanceSettingsPB")] SetAppearanceSetting = 7, - #[event(output = "AppearanceSettings")] + #[event(output = "AppearanceSettingsPB")] GetAppearanceSetting = 8, } diff --git a/frontend/rust-lib/flowy-user/src/handlers/auth_handler.rs b/frontend/rust-lib/flowy-user/src/handlers/auth_handler.rs index 22a17d887c..8ff5bdb7e2 100644 --- a/frontend/rust-lib/flowy-user/src/handlers/auth_handler.rs +++ b/frontend/rust-lib/flowy-user/src/handlers/auth_handler.rs @@ -7,9 +7,9 @@ use std::{convert::TryInto, sync::Arc}; // tracing instrument 👉🏻 https://docs.rs/tracing/0.1.26/tracing/attr.instrument.html #[tracing::instrument(level = "debug", name = "sign_in", skip(data, session), fields(email = %data.email), err)] pub async fn sign_in( - data: Data, + data: Data, session: AppData>, -) -> DataResult { +) -> DataResult { let params: SignInParams = data.into_inner().try_into()?; let user_profile = session.sign_in(params).await?; data_result(user_profile) @@ -26,9 +26,9 @@ pub async fn sign_in( err )] pub async fn sign_up( - data: Data, + data: Data, session: AppData>, -) -> DataResult { +) -> DataResult { let params: SignUpParams = data.into_inner().try_into()?; let user_profile = session.sign_up(params).await?; diff --git a/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs b/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs index 6ee62519e7..8a10dd89e2 100644 --- a/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs +++ b/frontend/rust-lib/flowy-user/src/handlers/user_handler.rs @@ -1,5 +1,5 @@ use crate::entities::{ - AppearanceSettings, UpdateUserProfileParams, UpdateUserProfilePayload, UserProfile, APPEARANCE_DEFAULT_THEME, + AppearanceSettingsPB, UpdateUserProfileParams, UpdateUserProfilePayloadPB, UserProfilePB, APPEARANCE_DEFAULT_THEME, }; use crate::{errors::FlowyError, services::UserSession}; use flowy_database::kv::KV; @@ -13,13 +13,13 @@ pub async fn init_user_handler(session: AppData>) -> Result<(), } #[tracing::instrument(level = "debug", skip(session))] -pub async fn check_user_handler(session: AppData>) -> DataResult { +pub async fn check_user_handler(session: AppData>) -> DataResult { let user_profile = session.check_user().await?; data_result(user_profile) } #[tracing::instrument(level = "debug", skip(session))] -pub async fn get_user_profile_handler(session: AppData>) -> DataResult { +pub async fn get_user_profile_handler(session: AppData>) -> DataResult { let user_profile = session.get_user_profile().await?; data_result(user_profile) } @@ -32,7 +32,7 @@ pub async fn sign_out(session: AppData>) -> Result<(), FlowyErr #[tracing::instrument(level = "debug", skip(data, session))] pub async fn update_user_profile_handler( - data: Data, + data: Data, session: AppData>, ) -> Result<(), FlowyError> { let params: UpdateUserProfileParams = data.into_inner().try_into()?; @@ -43,7 +43,7 @@ pub async fn update_user_profile_handler( const APPEARANCE_SETTING_CACHE_KEY: &str = "appearance_settings"; #[tracing::instrument(level = "debug", skip(data), err)] -pub async fn set_appearance_setting(data: Data) -> Result<(), FlowyError> { +pub async fn set_appearance_setting(data: Data) -> Result<(), FlowyError> { let mut setting = data.into_inner(); if setting.theme.is_empty() { setting.theme = APPEARANCE_DEFAULT_THEME.to_string(); @@ -55,15 +55,15 @@ pub async fn set_appearance_setting(data: Data) -> Result<() } #[tracing::instrument(err)] -pub async fn get_appearance_setting() -> DataResult { +pub async fn get_appearance_setting() -> DataResult { match KV::get_str(APPEARANCE_SETTING_CACHE_KEY) { - None => data_result(AppearanceSettings::default()), + None => data_result(AppearanceSettingsPB::default()), Some(s) => { let setting = match serde_json::from_str(&s) { Ok(setting) => setting, Err(e) => { tracing::error!("Deserialize AppearanceSettings failed: {:?}, fallback to default", e); - AppearanceSettings::default() + AppearanceSettingsPB::default() } }; data_result(setting) diff --git a/frontend/rust-lib/flowy-user/src/services/database.rs b/frontend/rust-lib/flowy-user/src/services/database.rs index eaf5b7f6cb..64ebd705a7 100644 --- a/frontend/rust-lib/flowy-user/src/services/database.rs +++ b/frontend/rust-lib/flowy-user/src/services/database.rs @@ -1,4 +1,4 @@ -use crate::entities::{SignInResponse, SignUpResponse, UpdateUserProfileParams, UserProfile}; +use crate::entities::{SignInResponse, SignUpResponse, UpdateUserProfileParams, UserProfilePB}; use flowy_database::ConnectionPool; use flowy_database::{schema::user_table, DBConnection, Database}; use flowy_error::{ErrorCode, FlowyError}; @@ -113,9 +113,9 @@ impl std::convert::From for UserTable { } } -impl std::convert::From for UserProfile { +impl std::convert::From for UserProfilePB { fn from(table: UserTable) -> Self { - UserProfile { + UserProfilePB { id: table.id, email: table.email, name: table.name, diff --git a/frontend/rust-lib/flowy-user/src/services/notifier.rs b/frontend/rust-lib/flowy-user/src/services/notifier.rs index 9500988d99..4efdc301ac 100644 --- a/frontend/rust-lib/flowy-user/src/services/notifier.rs +++ b/frontend/rust-lib/flowy-user/src/services/notifier.rs @@ -1,4 +1,4 @@ -use crate::entities::UserProfile; +use crate::entities::UserProfilePB; use tokio::sync::{broadcast, mpsc}; #[derive(Clone)] @@ -14,7 +14,7 @@ pub enum UserStatus { token: String, }, SignUp { - profile: UserProfile, + profile: UserProfilePB, ret: mpsc::Sender<()>, }, } @@ -42,7 +42,7 @@ impl UserNotifier { }); } - pub(crate) fn notify_sign_up(&self, ret: mpsc::Sender<()>, user_profile: &UserProfile) { + pub(crate) fn notify_sign_up(&self, ret: mpsc::Sender<()>, user_profile: &UserProfilePB) { let _ = self.user_status_notifier.send(UserStatus::SignUp { profile: user_profile.clone(), ret, diff --git a/frontend/rust-lib/flowy-user/src/services/user_session.rs b/frontend/rust-lib/flowy-user/src/services/user_session.rs index 48e6ef9661..3822a8a0db 100644 --- a/frontend/rust-lib/flowy-user/src/services/user_session.rs +++ b/frontend/rust-lib/flowy-user/src/services/user_session.rs @@ -1,5 +1,5 @@ use crate::entities::{ - SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfile, + SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserProfileParams, UserProfilePB, }; use crate::{ dart_notification::*, @@ -80,7 +80,7 @@ impl UserSession { } #[tracing::instrument(level = "debug", skip(self))] - pub async fn sign_in(&self, params: SignInParams) -> Result { + pub async fn sign_in(&self, params: SignInParams) -> Result { if self.is_user_login(¶ms.email) { self.get_user_profile().await } else { @@ -88,14 +88,14 @@ impl UserSession { let session: Session = resp.clone().into(); let _ = self.set_session(Some(session))?; let user_table = self.save_user(resp.into()).await?; - let user_profile: UserProfile = user_table.into(); + let user_profile: UserProfilePB = user_table.into(); self.notifier.notify_login(&user_profile.token, &user_profile.id); Ok(user_profile) } } #[tracing::instrument(level = "debug", skip(self))] - pub async fn sign_up(&self, params: SignUpParams) -> Result { + pub async fn sign_up(&self, params: SignUpParams) -> Result { if self.is_user_login(¶ms.email) { self.get_user_profile().await } else { @@ -103,7 +103,7 @@ impl UserSession { let session: Session = resp.clone().into(); let _ = self.set_session(Some(session))?; let user_table = self.save_user(resp.into()).await?; - let user_profile: UserProfile = user_table.into(); + let user_profile: UserProfilePB = user_table.into(); let (ret, mut tx) = mpsc::channel(1); self.notifier.notify_sign_up(ret, &user_profile); @@ -143,7 +143,7 @@ impl UserSession { Ok(()) } - pub async fn check_user(&self) -> Result { + pub async fn check_user(&self) -> Result { let (user_id, token) = self.get_session()?.into_part(); let user = dsl::user_table @@ -154,7 +154,7 @@ impl UserSession { Ok(user.into()) } - pub async fn get_user_profile(&self) -> Result { + pub async fn get_user_profile(&self) -> Result { let (user_id, token) = self.get_session()?.into_part(); let user = dsl::user_table .filter(user_table::id.eq(&user_id)) diff --git a/frontend/rust-lib/flowy-user/tests/event/auth_test.rs b/frontend/rust-lib/flowy-user/tests/event/auth_test.rs index 39b22a9af0..288b9d8b08 100644 --- a/frontend/rust-lib/flowy-user/tests/event/auth_test.rs +++ b/frontend/rust-lib/flowy-user/tests/event/auth_test.rs @@ -1,13 +1,13 @@ use crate::helper::*; use flowy_test::{event_builder::UserModuleEventBuilder, FlowySDKTest}; -use flowy_user::entities::{SignInPayload, SignUpPayload, UserProfile}; +use flowy_user::entities::{SignInPayloadPB, SignUpPayloadPB, UserProfilePB}; use flowy_user::{errors::ErrorCode, event_map::UserEvent::*}; #[tokio::test] async fn sign_up_with_invalid_email() { for email in invalid_email_test_case() { let sdk = FlowySDKTest::default(); - let request = SignUpPayload { + let request = SignUpPayloadPB { email: email.to_string(), name: valid_name(), password: login_password(), @@ -29,7 +29,7 @@ async fn sign_up_with_invalid_email() { async fn sign_up_with_invalid_password() { for password in invalid_password_test_case() { let sdk = FlowySDKTest::default(); - let request = SignUpPayload { + let request = SignUpPayloadPB { email: random_email(), name: valid_name(), password, @@ -50,7 +50,7 @@ async fn sign_in_success() { let _ = UserModuleEventBuilder::new(test.clone()).event(SignOut).sync_send(); let sign_up_context = test.sign_up().await; - let request = SignInPayload { + let request = SignInPayloadPB { email: sign_up_context.user_profile.email.clone(), password: sign_up_context.password.clone(), name: "".to_string(), @@ -61,7 +61,7 @@ async fn sign_in_success() { .payload(request) .async_send() .await - .parse::(); + .parse::(); dbg!(&response); } @@ -69,7 +69,7 @@ async fn sign_in_success() { async fn sign_in_with_invalid_email() { for email in invalid_email_test_case() { let sdk = FlowySDKTest::default(); - let request = SignInPayload { + let request = SignInPayloadPB { email: email.to_string(), password: login_password(), name: "".to_string(), @@ -93,7 +93,7 @@ async fn sign_in_with_invalid_password() { for password in invalid_password_test_case() { let sdk = FlowySDKTest::default(); - let request = SignInPayload { + let request = SignInPayloadPB { email: random_email(), password, name: "".to_string(), diff --git a/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs b/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs index b01a533336..fa77b69509 100644 --- a/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs +++ b/frontend/rust-lib/flowy-user/tests/event/user_profile_test.rs @@ -1,6 +1,6 @@ use crate::helper::*; use flowy_test::{event_builder::UserModuleEventBuilder, FlowySDKTest}; -use flowy_user::entities::{UpdateUserProfilePayload, UserProfile}; +use flowy_user::entities::{UpdateUserProfilePayloadPB, UserProfilePB}; use flowy_user::{errors::ErrorCode, event_map::UserEvent::*}; use nanoid::nanoid; @@ -24,7 +24,7 @@ async fn user_profile_get() { let user = UserModuleEventBuilder::new(test.clone()) .event(GetUserProfile) .sync_send() - .parse::(); + .parse::(); assert_eq!(user_profile, user); } @@ -33,7 +33,7 @@ async fn user_update_with_name() { let sdk = FlowySDKTest::default(); let user = sdk.init_user().await; let new_name = "hello_world".to_owned(); - let request = UpdateUserProfilePayload::new(&user.id).name(&new_name); + let request = UpdateUserProfilePayloadPB::new(&user.id).name(&new_name); let _ = UserModuleEventBuilder::new(sdk.clone()) .event(UpdateUserProfile) .payload(request) @@ -43,7 +43,7 @@ async fn user_update_with_name() { .event(GetUserProfile) .assert_error() .sync_send() - .parse::(); + .parse::(); assert_eq!(user_profile.name, new_name,); } @@ -53,7 +53,7 @@ async fn user_update_with_email() { let sdk = FlowySDKTest::default(); let user = sdk.init_user().await; let new_email = format!("{}@gmail.com", nanoid!(6)); - let request = UpdateUserProfilePayload::new(&user.id).email(&new_email); + let request = UpdateUserProfilePayloadPB::new(&user.id).email(&new_email); let _ = UserModuleEventBuilder::new(sdk.clone()) .event(UpdateUserProfile) .payload(request) @@ -62,7 +62,7 @@ async fn user_update_with_email() { .event(GetUserProfile) .assert_error() .sync_send() - .parse::(); + .parse::(); assert_eq!(user_profile.email, new_email,); } @@ -72,7 +72,7 @@ async fn user_update_with_password() { let sdk = FlowySDKTest::default(); let user = sdk.init_user().await; let new_password = "H123world!".to_owned(); - let request = UpdateUserProfilePayload::new(&user.id).password(&new_password); + let request = UpdateUserProfilePayloadPB::new(&user.id).password(&new_password); let _ = UserModuleEventBuilder::new(sdk.clone()) .event(UpdateUserProfile) @@ -86,7 +86,7 @@ async fn user_update_with_invalid_email() { let test = FlowySDKTest::default(); let user = test.init_user().await; for email in invalid_email_test_case() { - let request = UpdateUserProfilePayload::new(&user.id).email(&email); + let request = UpdateUserProfilePayloadPB::new(&user.id).email(&email); assert_eq!( UserModuleEventBuilder::new(test.clone()) .event(UpdateUserProfile) @@ -104,7 +104,7 @@ async fn user_update_with_invalid_password() { let test = FlowySDKTest::default(); let user = test.init_user().await; for password in invalid_password_test_case() { - let request = UpdateUserProfilePayload::new(&user.id).password(&password); + let request = UpdateUserProfilePayloadPB::new(&user.id).password(&password); UserModuleEventBuilder::new(test.clone()) .event(UpdateUserProfile) @@ -118,7 +118,7 @@ async fn user_update_with_invalid_password() { async fn user_update_with_invalid_name() { let test = FlowySDKTest::default(); let user = test.init_user().await; - let request = UpdateUserProfilePayload::new(&user.id).name(""); + let request = UpdateUserProfilePayloadPB::new(&user.id).name(""); UserModuleEventBuilder::new(test.clone()) .event(UpdateUserProfile) .payload(request) From 45011e2dd3cf77eddda683a39b620ec714a741cb Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 19 Jul 2022 20:39:05 +0800 Subject: [PATCH 043/112] chore: add task test --- .../src/services/filter/filter_service.rs | 6 +- .../src/services/grid_editor_task.rs | 14 +- .../flowy-grid/src/services/tasks/queue.rs | 14 +- .../flowy-grid/src/services/tasks/runner.rs | 14 +- .../src/services/tasks/scheduler.rs | 142 +++++++++++++++--- .../flowy-grid/src/services/tasks/store.rs | 15 +- .../flowy-grid/src/services/tasks/task.rs | 53 ++++++- 7 files changed, 210 insertions(+), 48 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs index be02e80ebd..f3b1d72fb8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs +++ b/frontend/rust-lib/flowy-grid/src/services/filter/filter_service.rs @@ -130,11 +130,7 @@ impl GridFilterService { let handler_id = self.grid_pad.read().await.grid_id(); let context = FilterTaskContext { blocks }; - Task { - handler_id, - id: task_id, - content: TaskContent::Filter(context), - } + Task::new(&handler_id, task_id, TaskContent::Filter(context)) } async fn notify(&self, changesets: Vec) { diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs index 1b3a364833..0338730818 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor_task.rs @@ -1,23 +1,23 @@ use crate::manager::GridTaskSchedulerRwLock; use crate::services::grid_editor::GridRevisionEditor; -use crate::services::tasks::{GridTaskHandler, Task, TaskContent, TaskHandlerId, TaskId}; +use crate::services::tasks::{GridTaskHandler, Task, TaskContent, TaskId}; use flowy_error::FlowyError; use futures::future::BoxFuture; use lib_infra::future::BoxResultFuture; pub(crate) trait GridServiceTaskScheduler: Send + Sync + 'static { fn gen_task_id(&self) -> BoxFuture; - fn register_task(&self, task: Task) -> BoxFuture<()>; + fn add_task(&self, task: Task) -> BoxFuture<()>; } impl GridTaskHandler for GridRevisionEditor { - fn handler_id(&self) -> &TaskHandlerId { + fn handler_id(&self) -> &str { &self.grid_id } - fn process_task(&self, task: Task) -> BoxResultFuture<(), FlowyError> { + fn process_content(&self, content: TaskContent) -> BoxResultFuture<(), FlowyError> { Box::pin(async move { - match task.content { + match content { TaskContent::Snapshot => {} TaskContent::Filter(context) => self.filter_service.process(context).await?, } @@ -32,10 +32,10 @@ impl GridServiceTaskScheduler for GridTaskSchedulerRwLock { Box::pin(async move { this.read().await.next_task_id() }) } - fn register_task(&self, task: Task) -> BoxFuture<()> { + fn add_task(&self, task: Task) -> BoxFuture<()> { let this = self.clone(); Box::pin(async move { - this.write().await.register_task(task); + this.write().await.add_task(task); }) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs index 537f789f9b..1ba97afd9a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/queue.rs @@ -20,7 +20,12 @@ impl GridTaskQueue { } pub(crate) fn push(&mut self, task: &Task) { - let task_type = match task.content { + if task.content.is_none() { + tracing::warn!("Ignore task: {} with empty content", task.id); + return; + } + + let task_type = match task.content.as_ref().unwrap() { TaskContent::Snapshot => TaskType::Snapshot, TaskContent::Filter { .. } => TaskType::Filter, }; @@ -28,7 +33,7 @@ impl GridTaskQueue { ty: task_type, id: task.id, }; - match self.index_tasks.entry("1".to_owned()) { + match self.index_tasks.entry(task.handler_id.clone()) { Entry::Occupied(entry) => { let mut list = entry.get().borrow_mut(); assert!(list.peek().map(|old_id| pending_task.id >= old_id.id).unwrap_or(true)); @@ -44,6 +49,11 @@ impl GridTaskQueue { } } + #[allow(dead_code)] + pub(crate) fn clear(&mut self) { + self.queue.clear(); + } + pub(crate) fn mut_head(&mut self, mut f: F) -> Option where F: FnMut(&mut TaskList) -> Option, diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/runner.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/runner.rs index 713fc15c86..121329edfb 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/runner.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/runner.rs @@ -1,4 +1,5 @@ use crate::services::tasks::scheduler::GridTaskScheduler; + use std::sync::Arc; use std::time::Duration; use tokio::sync::{watch, RwLock}; @@ -7,13 +8,13 @@ use tokio::time::interval; pub struct GridTaskRunner { scheduler: Arc>, debounce_duration: Duration, - notifier: Option>, + notifier: Option>, } impl GridTaskRunner { pub fn new( scheduler: Arc>, - notifier: watch::Receiver<()>, + notifier: watch::Receiver, debounce_duration: Duration, ) -> Self { Self { @@ -34,12 +35,13 @@ impl GridTaskRunner { // The runner will be stopped if the corresponding Sender drop. break; } + + if *notifier.borrow() { + break; + } let mut interval = interval(self.debounce_duration); interval.tick().await; - - if let Err(e) = self.scheduler.write().await.process_next_task().await { - tracing::error!("{:?}", e); - } + let _ = self.scheduler.write().await.process_next_task().await; } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs index 14494842ec..73ba298d9b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/scheduler.rs @@ -3,8 +3,8 @@ use crate::services::tasks::runner::GridTaskRunner; use crate::services::tasks::store::GridTaskStore; use crate::services::tasks::task::Task; -use crate::services::tasks::TaskId; -use flowy_error::{FlowyError, FlowyResult}; +use crate::services::tasks::{TaskContent, TaskId, TaskStatus}; +use flowy_error::FlowyError; use lib_infra::future::BoxResultFuture; use std::collections::HashMap; use std::sync::Arc; @@ -12,21 +12,21 @@ use std::time::Duration; use tokio::sync::{watch, RwLock}; pub(crate) trait GridTaskHandler: Send + Sync + 'static { - fn handler_id(&self) -> &TaskHandlerId; + fn handler_id(&self) -> &str; - fn process_task(&self, task: Task) -> BoxResultFuture<(), FlowyError>; + fn process_content(&self, content: TaskContent) -> BoxResultFuture<(), FlowyError>; } pub struct GridTaskScheduler { queue: GridTaskQueue, store: GridTaskStore, - notifier: watch::Sender<()>, + notifier: watch::Sender, handlers: HashMap>, } impl GridTaskScheduler { pub(crate) fn new() -> Arc> { - let (notifier, rx) = watch::channel(()); + let (notifier, rx) = watch::channel(false); let scheduler = Self { queue: GridTaskQueue::new(), @@ -57,25 +57,38 @@ impl GridTaskScheduler { let _ = self.handlers.remove(handler_id.as_ref()); } - pub(crate) async fn process_next_task(&mut self) -> FlowyResult<()> { - let mut get_next_task = || { - let pending_task = self.queue.mut_head(|list| list.pop())?; - let task = self.store.remove_task(&pending_task.id)?; - Some(task) - }; - - if let Some(task) = get_next_task() { - match self.handlers.get(&task.handler_id) { - None => {} - Some(handler) => { - let _ = handler.process_task(task).await; - } - } - } - Ok(()) + #[allow(dead_code)] + pub(crate) fn stop(&mut self) { + let _ = self.notifier.send(true); + self.queue.clear(); + self.store.clear(); } - pub(crate) fn register_task(&mut self, task: Task) { + pub(crate) async fn process_next_task(&mut self) -> Option<()> { + let pending_task = self.queue.mut_head(|list| list.pop())?; + let mut task = self.store.remove_task(&pending_task.id)?; + let handler = self.handlers.get(&task.handler_id)?; + + let ret = task.ret.take()?; + let content = task.content.take()?; + + task.set_status(TaskStatus::Processing); + let _ = match handler.process_content(content).await { + Ok(_) => { + task.set_status(TaskStatus::Done); + let _ = ret.send(task.into()); + } + Err(e) => { + tracing::error!("Process task failed: {:?}", e); + task.set_status(TaskStatus::Failure); + let _ = ret.send(task.into()); + } + }; + self.notify(); + None + } + + pub(crate) fn add_task(&mut self, task: Task) { assert!(!task.is_finished()); self.queue.push(&task); self.store.insert_task(task); @@ -87,6 +100,87 @@ impl GridTaskScheduler { } pub(crate) fn notify(&self) { - let _ = self.notifier.send(()); + let _ = self.notifier.send(false); + } +} + +#[cfg(test)] +mod tests { + use crate::services::grid_editor_task::GridServiceTaskScheduler; + use crate::services::tasks::{GridTaskHandler, GridTaskScheduler, Task, TaskContent, TaskStatus}; + use flowy_error::FlowyError; + use lib_infra::future::BoxResultFuture; + use std::sync::Arc; + use std::time::Duration; + use tokio::time::interval; + + #[tokio::test] + async fn task_scheduler_snapshot_task_test() { + let scheduler = GridTaskScheduler::new(); + scheduler + .write() + .await + .register_handler(Arc::new(MockGridTaskHandler())); + + let task_id = scheduler.gen_task_id().await; + let mut task = Task::new("1", task_id, TaskContent::Snapshot); + let rx = task.rx.take().unwrap(); + scheduler.write().await.add_task(task); + assert_eq!(rx.await.unwrap().status, TaskStatus::Done); + } + + #[tokio::test] + async fn task_scheduler_snapshot_task_cancel_test() { + let scheduler = GridTaskScheduler::new(); + scheduler + .write() + .await + .register_handler(Arc::new(MockGridTaskHandler())); + + let task_id = scheduler.gen_task_id().await; + let mut task = Task::new("1", task_id, TaskContent::Snapshot); + let rx = task.rx.take().unwrap(); + scheduler.write().await.add_task(task); + scheduler.write().await.stop(); + + assert_eq!(rx.await.unwrap().status, TaskStatus::Cancel); + } + + #[tokio::test] + async fn task_scheduler_multi_task_test() { + let scheduler = GridTaskScheduler::new(); + scheduler + .write() + .await + .register_handler(Arc::new(MockGridTaskHandler())); + + let task_id = scheduler.gen_task_id().await; + let mut task_1 = Task::new("1", task_id, TaskContent::Snapshot); + let rx_1 = task_1.rx.take().unwrap(); + + let task_id = scheduler.gen_task_id().await; + let mut task_2 = Task::new("1", task_id, TaskContent::Snapshot); + let rx_2 = task_2.rx.take().unwrap(); + + scheduler.write().await.add_task(task_1); + scheduler.write().await.add_task(task_2); + + assert_eq!(rx_1.await.unwrap().status, TaskStatus::Done); + assert_eq!(rx_2.await.unwrap().status, TaskStatus::Done); + } + struct MockGridTaskHandler(); + impl GridTaskHandler for MockGridTaskHandler { + fn handler_id(&self) -> &str { + "1" + } + + fn process_content(&self, _content: TaskContent) -> BoxResultFuture<(), FlowyError> { + Box::pin(async move { + let mut interval = interval(Duration::from_secs(1)); + interval.tick().await; + interval.tick().await; + Ok(()) + }) + } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/store.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/store.rs index 21aae60bc4..9f14889e4d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/store.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/store.rs @@ -1,6 +1,7 @@ use crate::services::tasks::task::Task; -use crate::services::tasks::TaskId; +use crate::services::tasks::{TaskId, TaskStatus}; use std::collections::HashMap; +use std::mem; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::SeqCst; @@ -25,6 +26,18 @@ impl GridTaskStore { self.tasks.remove(task_id) } + #[allow(dead_code)] + pub(crate) fn clear(&mut self) { + let tasks = mem::take(&mut self.tasks); + tasks.into_values().for_each(|mut task| { + if task.ret.is_some() { + let ret = task.ret.take().unwrap(); + task.set_status(TaskStatus::Cancel); + let _ = ret.send(task.into()); + } + }); + } + pub(crate) fn next_task_id(&self) -> TaskId { let _ = self.task_id_counter.fetch_add(1, SeqCst); self.task_id_counter.load(SeqCst) diff --git a/frontend/rust-lib/flowy-grid/src/services/tasks/task.rs b/frontend/rust-lib/flowy-grid/src/services/tasks/task.rs index 92575dabdc..92950b02aa 100644 --- a/frontend/rust-lib/flowy-grid/src/services/tasks/task.rs +++ b/frontend/rust-lib/flowy-grid/src/services/tasks/task.rs @@ -1,3 +1,5 @@ +#![allow(clippy::all)] +#![allow(dead_code)] use crate::services::row::GridBlockSnapshot; use crate::services::tasks::queue::TaskHandlerId; use std::cmp::Ordering; @@ -60,14 +62,59 @@ pub(crate) enum TaskContent { Filter(FilterTaskContext), } +#[derive(Debug, Eq, PartialEq)] +pub(crate) enum TaskStatus { + Pending, + Processing, + Done, + Failure, + Cancel, +} + pub(crate) struct Task { - pub handler_id: TaskHandlerId, pub id: TaskId, - pub content: TaskContent, + pub handler_id: TaskHandlerId, + pub content: Option, + status: TaskStatus, + pub ret: Option>, + pub rx: Option>, +} + +pub(crate) struct TaskResult { + pub id: TaskId, + pub(crate) status: TaskStatus, +} + +impl std::convert::From for TaskResult { + fn from(task: Task) -> Self { + TaskResult { + id: task.id, + status: task.status, + } + } } impl Task { + pub fn new(handler_id: &str, id: TaskId, content: TaskContent) -> Self { + let (ret, rx) = tokio::sync::oneshot::channel(); + Self { + handler_id: handler_id.to_owned(), + id, + content: Some(content), + ret: Some(ret), + rx: Some(rx), + status: TaskStatus::Pending, + } + } + + pub fn set_status(&mut self, status: TaskStatus) { + self.status = status; + } + pub fn is_finished(&self) -> bool { - todo!() + match self.status { + TaskStatus::Done => true, + _ => false, + } } } From efa89866f3151d0694861c68901add0ac59ee7eb Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Tue, 19 Jul 2022 13:07:25 -0400 Subject: [PATCH 044/112] fix: colors and brew install for mac Also fixed colors for Linux. Now displays messages in yellow so that they stick out more. --- .../scripts/install_dev_env/install_linux.sh | 37 ++++++++++----- .../scripts/install_dev_env/install_macos.sh | 45 ++++++++++++------- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/frontend/scripts/install_dev_env/install_linux.sh b/frontend/scripts/install_dev_env/install_linux.sh index 405c8b85c5..a580c22b19 100755 --- a/frontend/scripts/install_dev_env/install_linux.sh +++ b/frontend/scripts/install_dev_env/install_linux.sh @@ -1,30 +1,43 @@ #!/bin/bash -BLUE="\e[34m" +YELLOW="\e[93m" GREEN="\e[32m" RED="\e[31m" ENDCOLOR="\e[0m" +printMessage() { + printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n" +} + +printSuccess() { + printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n" +} + +printError() { + printf "${RED}AppFlowy : $1${ENDCOLOR}\n" +} + + # Note: This script does not install applications which are installed by the package manager. There are too many package managers out there. # Install Rust -echo -e "${BLUE}AppFlowy : The Rust programming language is required to compile AppFlowy.${ENDCOLOR}" -echo -e "${BLUE}AppFlowy : We can install it now if you don't already have it on your system.${ENDCOLOR}" +printMessage "The Rust programming language is required to compile AppFlowy." +printMessage "We can install it now if you don't already have it on your system." -read -p "$(echo -e $GREEN"AppFlowy : Do you want to install Rust? [y/N]"$ENDCOLOR) " installrust +read -p "$(printSuccess "Do you want to install Rust? [y/N]") " installrust if [ ${installrust^^} == "Y" ]; then - echo -e "${BLUE}AppFlowy : Installing Rust.${ENDCOLOR}" + printMessage "Installing Rust." curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source $HOME/.cargo/env rustup toolchain install stable rustup default stable else - echo -e "${BLUE}AppFlowy : Skipping Rust installation.${ENDCOLOR}" + printMessage "Skipping Rust installation." fi # Enable the flutter stable channel -echo -e "${BLUE}AppFlowy : Checking Flutter installation.${ENDCOLOR}" +printMessage "Setting up Flutter" flutter channel stable # Enable linux desktop @@ -34,24 +47,24 @@ flutter config --enable-linux-desktop flutter doctor # Add the githooks directory to your git configuration -echo -e "${BLUE}AppFlowy : Setting up githooks.${ENDCOLOR}" +printMessage "Setting up githooks." git config core.hooksPath .githooks # Change to the frontend directory cd frontend # Install cargo make -echo -e "${BLUE}AppFlowy : Installing cargo-make.${ENDCOLOR}" +printMessage "Installing cargo-make." cargo install --force cargo-make # Install duckscript -echo -e "${BLUE}AppFlowy : Installing duckscript.${ENDCOLOR}" +printMessage "Installing duckscript." cargo install --force duckscript_cli # Install CommitLint -echo -e "${BLUE}AppFlowy : Installing CommitLint.${ENDCOLOR}" +printMessage "Installing CommitLint." npm install @commitlint/cli @commitlint/config-conventional --save-dev # Check prerequisites -echo -e "${BLUE}AppFlowy : Checking prerequisites.${ENDCOLOR}" +printMessage "Checking prerequisites." cargo make flowy_dev diff --git a/frontend/scripts/install_dev_env/install_macos.sh b/frontend/scripts/install_dev_env/install_macos.sh index 36c8f062f4..edc0c40b26 100755 --- a/frontend/scripts/install_dev_env/install_macos.sh +++ b/frontend/scripts/install_dev_env/install_macos.sh @@ -1,30 +1,43 @@ #!/bin/bash -BLUE="\e[34m" +YELLOW="\e[93m" GREEN="\e[32m" RED="\e[31m" ENDCOLOR="\e[0m" -# Install Rust -echo -e "${BLUE}AppFlowy : The Rust programming language is required to compile AppFlowy.${ENDCOLOR}" -echo -e "${BLUE}AppFlowy : We can install it now if you don't already have it on your system.${ENDCOLOR}" +printMessage() { + printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n" +} -read -p "$(echo -e $GREEN"AppFlowy : Do you want to install Rust? [y/N]"$ENDCOLOR) " installrust +printSuccess() { + printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n" +} + +printError() { + printf "${RED}AppFlowy : $1${ENDCOLOR}\n" +} + + +# Install Rust +printMessage "The Rust programming language is required to compile AppFlowy." +printMessage "We can install it now if you don't already have it on your system." + +read -p "$(printSuccess "Do you want to install Rust? [y/N]") " installrust if [ ${installrust^^} == "Y" ]; then - echo -e "${BLUE}AppFlowy : Installing Rust.${ENDCOLOR}" - brew 'rustup-init' + printMessage "Installing Rust." + brew install rustup-init rustup-init -y --default-toolchain=stable else - echo -e "${BLUE}AppFlowy : Skipping Rust installation.${ENDCOLOR}" + printMessage "Skipping Rust installation." fi # Install sqllite -echo -e "${BLUE}AppFlowy : Installing SqlLite3.${ENDCOLOR}" -brew 'sqlite3' +printMessage "Installing sqlLite3." +brew install sqlite3 # Enable the flutter stable channel -echo -e "${BLUE}AppFlowy : Checking Flutter installation.${ENDCOLOR}" +printMessage "Setting up Flutter" flutter channel stable # Enable linux desktop @@ -34,24 +47,24 @@ flutter config --enable-macos-desktop flutter doctor # Add the githooks directory to your git configuration -echo -e "${BLUE}AppFlowy : Setting up githooks.${ENDCOLOR}" +printMessage "Setting up githooks." git config core.hooksPath .githooks # Change to the frontend directory cd frontend # Install cargo make -echo -e "${BLUE}AppFlowy : Installing cargo-make.${ENDCOLOR}" +printMessage "Installing cargo-make." cargo install --force cargo-make # Install duckscript -echo -e "${BLUE}AppFlowy : Installing duckscript.${ENDCOLOR}" +printMessage "Installing duckscript." cargo install --force duckscript_cli # Install CommitLint -echo -e "${BLUE}AppFlowy : Installing CommitLint.${ENDCOLOR}" +printMessagae "Installing CommitLint." npm install @commitlint/cli @commitlint/config-conventional --save-dev # Check prerequisites -echo -e "${BLUE}AppFlowy : Checking prerequisites.${ENDCOLOR}" +printMessage "Checking prerequisites." cargo make flowy_dev From cb1afacbd6f9f85e45ba9f9dcef3c7f3a4eeb1b6 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 20 Jul 2022 15:30:48 +0800 Subject: [PATCH 045/112] chore: rename some structs --- frontend/rust-lib/flowy-database/src/schema.rs | 11 ----------- .../rust-lib/flowy-revision/src/rev_manager.rs | 15 +-------------- .../flowy-revision/src/snapshot/persistence.rs | 3 +++ .../flowy-revision/src/snapshot/rev_snapshot.rs | 3 +++ 4 files changed, 7 insertions(+), 25 deletions(-) diff --git a/frontend/rust-lib/flowy-database/src/schema.rs b/frontend/rust-lib/flowy-database/src/schema.rs index 70d3ae4b20..e41fd6d865 100644 --- a/frontend/rust-lib/flowy-database/src/schema.rs +++ b/frontend/rust-lib/flowy-database/src/schema.rs @@ -49,16 +49,6 @@ table! { } } -table! { - rev_history (id) { - id -> Integer, - object_id -> Text, - start_rev_id -> BigInt, - end_rev_id -> BigInt, - data -> Binary, - } -} - table! { rev_snapshot (id) { id -> Integer, @@ -135,7 +125,6 @@ allow_tables_to_appear_in_same_query!( grid_meta_rev_table, grid_rev_table, kv_table, - rev_history, rev_snapshot, rev_table, trash_table, diff --git a/frontend/rust-lib/flowy-revision/src/rev_manager.rs b/frontend/rust-lib/flowy-revision/src/rev_manager.rs index f133c20782..bd4d01740d 100644 --- a/frontend/rust-lib/flowy-revision/src/rev_manager.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_manager.rs @@ -1,5 +1,4 @@ use crate::disk::RevisionState; -// use crate::history::{RevisionHistoryConfig, RevisionHistoryDiskCache, RevisionHistoryManager}; use crate::{RevisionPersistence, RevisionSnapshotDiskCache, RevisionSnapshotManager, WSDataProviderDataSource}; use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; @@ -46,7 +45,7 @@ pub struct RevisionManager { user_id: String, rev_id_counter: RevIdCounter, rev_persistence: Arc, - // rev_history: Arc, + #[allow(dead_code)] rev_snapshot: Arc, rev_compactor: Arc, #[cfg(feature = "flowy_unit_test")] @@ -59,25 +58,14 @@ impl RevisionManager { object_id: &str, rev_persistence: RevisionPersistence, rev_compactor: C, - // history_persistence: HP, snapshot_persistence: SP, ) -> Self where - // HP: 'static + RevisionHistoryDiskCache, SP: 'static + RevisionSnapshotDiskCache, C: 'static + RevisionCompactor, { let rev_id_counter = RevIdCounter::new(0); let rev_compactor = Arc::new(rev_compactor); - // let history_persistence = Arc::new(history_persistence); - // let rev_history_config = RevisionHistoryConfig::default(); - // let rev_history = Arc::new(RevisionHistoryManager::new( - // user_id, - // object_id, - // rev_history_config, - // history_persistence, - // rev_compactor.clone(), - // )); let rev_persistence = Arc::new(rev_persistence); @@ -90,7 +78,6 @@ impl RevisionManager { user_id: user_id.to_owned(), rev_id_counter, rev_persistence, - // rev_history, rev_snapshot, rev_compactor, #[cfg(feature = "flowy_unit_test")] diff --git a/frontend/rust-lib/flowy-revision/src/snapshot/persistence.rs b/frontend/rust-lib/flowy-revision/src/snapshot/persistence.rs index e07c541b12..d8d7bae3a6 100644 --- a/frontend/rust-lib/flowy-revision/src/snapshot/persistence.rs +++ b/frontend/rust-lib/flowy-revision/src/snapshot/persistence.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(dead_code)] +#![allow(unused_variables)] use crate::{RevisionSnapshotDiskCache, RevisionSnapshotInfo}; use flowy_database::ConnectionPool; use flowy_error::FlowyResult; diff --git a/frontend/rust-lib/flowy-revision/src/snapshot/rev_snapshot.rs b/frontend/rust-lib/flowy-revision/src/snapshot/rev_snapshot.rs index 71e2e270ec..047d21607e 100644 --- a/frontend/rust-lib/flowy-revision/src/snapshot/rev_snapshot.rs +++ b/frontend/rust-lib/flowy-revision/src/snapshot/rev_snapshot.rs @@ -1,3 +1,6 @@ +#![allow(clippy::all)] +#![allow(dead_code)] +#![allow(unused_variables)] use flowy_error::FlowyResult; use std::sync::Arc; From e0db7bd4f932322cec005673fcc9112800a54085 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 20 Jul 2022 18:27:12 +0800 Subject: [PATCH 046/112] chore: remove feature flag: filter --- .../src/services/persistence/mod.rs | 12 +- frontend/rust-lib/flowy-grid/Cargo.toml | 3 +- frontend/rust-lib/flowy-grid/src/manager.rs | 15 ++- .../flowy-grid/src/services/grid_editor.rs | 4 +- .../src/services/persistence/block_index.rs | 1 + .../src/services/persistence/migration.rs | 113 ++++++++++++++++++ .../src/services/persistence/mod.rs | 1 + .../flowy-revision/src/cache/disk/mod.rs | 10 ++ .../flowy-revision/src/rev_persistence.rs | 11 +- .../flowy-sdk/src/deps_resolve/grid_deps.rs | 17 ++- frontend/rust-lib/flowy-sdk/src/lib.rs | 21 +++- .../src/revision/grid_rev.rs | 5 - .../src/client_grid/grid_revision_pad.rs | 12 +- 13 files changed, 196 insertions(+), 29 deletions(-) create mode 100644 frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs index 54fcc3b522..5676db54da 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs @@ -11,9 +11,9 @@ use flowy_database::ConnectionPool; use flowy_error::{FlowyError, FlowyResult}; use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision}; use flowy_revision::disk::{RevisionRecord, RevisionState}; -use flowy_revision::mk_revision_disk_cache; -use flowy_sync::client_folder::initial_folder_delta; +use flowy_revision::mk_text_block_revision_disk_cache; use flowy_sync::{client_folder::FolderPad, entities::revision::Revision}; +use lib_ot::core::PlainTextDeltaBuilder; use std::sync::Arc; use tokio::sync::RwLock; pub use version_1::{app_sql::*, trash_sql::*, v1_impl::V1Transaction, view_sql::*, workspace_sql::*}; @@ -109,16 +109,16 @@ impl FolderPersistence { pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> { let pool = self.database.db_pool()?; - let delta_data = initial_folder_delta(&folder)?.to_delta_bytes(); - let md5 = folder.md5(); - let revision = Revision::new(folder_id.as_ref(), 0, 0, delta_data, user_id, md5); + let json = folder.to_json()?; + let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_delta_bytes(); + let revision = Revision::initial_revision(user_id, folder_id.as_ref(), delta_data); let record = RevisionRecord { revision, state: RevisionState::Sync, write_to_disk: true, }; - let disk_cache = mk_revision_disk_cache(user_id, pool); + let disk_cache = mk_text_block_revision_disk_cache(user_id, pool); disk_cache.delete_and_insert_records(folder_id.as_ref(), None, vec![record]) } } diff --git a/frontend/rust-lib/flowy-grid/Cargo.toml b/frontend/rust-lib/flowy-grid/Cargo.toml index e09e156772..ba3702038e 100644 --- a/frontend/rust-lib/flowy-grid/Cargo.toml +++ b/frontend/rust-lib/flowy-grid/Cargo.toml @@ -50,7 +50,6 @@ lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file [features] -default = ["filter"] +default = [] dart = ["lib-infra/dart"] -filter = [] flowy_unit_test = ["flowy-revision/flowy_unit_test"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 77f019293f..320f18b560 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -2,6 +2,7 @@ use crate::services::block_revision_editor::GridBlockRevisionCompactor; use crate::services::grid_editor::{GridRevisionCompactor, GridRevisionEditor}; use crate::services::persistence::block_index::BlockIndexCache; use crate::services::persistence::kv::GridKVPersistence; +use crate::services::persistence::migration::GridMigration; use crate::services::persistence::GridDatabase; use crate::services::tasks::GridTaskScheduler; use bytes::Bytes; @@ -31,6 +32,7 @@ pub struct GridManager { #[allow(dead_code)] kv_persistence: Arc, task_scheduler: GridTaskSchedulerRwLock, + migration: GridMigration, } impl GridManager { @@ -41,17 +43,27 @@ impl GridManager { ) -> Self { let grid_editors = Arc::new(DashMap::new()); let kv_persistence = Arc::new(GridKVPersistence::new(database.clone())); - let block_index_cache = Arc::new(BlockIndexCache::new(database)); + let block_index_cache = Arc::new(BlockIndexCache::new(database.clone())); let task_scheduler = GridTaskScheduler::new(); + let migration = GridMigration::new(grid_user.clone(), database); Self { grid_editors, grid_user, kv_persistence, block_index_cache, task_scheduler, + migration, } } + pub async fn initialize_with_new_user(&self, _user_id: &str, _token: &str) -> FlowyResult<()> { + Ok(()) + } + + pub async fn initialize(&self, _user_id: &str, _token: &str) -> FlowyResult<()> { + Ok(()) + } + #[tracing::instrument(level = "debug", skip_all, err)] pub async fn create_grid>(&self, grid_id: T, revisions: RepeatedRevision) -> FlowyResult<()> { let grid_id = grid_id.as_ref(); @@ -74,6 +86,7 @@ impl GridManager { pub async fn open_grid>(&self, grid_id: T) -> FlowyResult> { let grid_id = grid_id.as_ref(); tracing::Span::current().record("grid_id", &grid_id); + let _ = self.migration.migration_grid_if_need(grid_id).await; self.get_or_create_grid_editor(grid_id).await } 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 bcb4a7d288..572665bd0c 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -643,8 +643,8 @@ pub struct GridPadBuilder(); impl RevisionObjectBuilder for GridPadBuilder { type Output = GridRevisionPad; - fn build_object(object_id: &str, revisions: Vec) -> FlowyResult { - let pad = GridRevisionPad::from_revisions(object_id, revisions)?; + fn build_object(_object_id: &str, revisions: Vec) -> FlowyResult { + let pad = GridRevisionPad::from_revisions(revisions)?; Ok(pad) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/block_index.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/block_index.rs index c62dc502ad..798819fb98 100644 --- a/frontend/rust-lib/flowy-grid/src/services/persistence/block_index.rs +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/block_index.rs @@ -7,6 +7,7 @@ use flowy_database::{ use flowy_error::FlowyResult; use std::sync::Arc; +/// Allow getting the block id from row id. pub struct BlockIndexCache { database: Arc, } diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs new file mode 100644 index 0000000000..026ba3bc20 --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs @@ -0,0 +1,113 @@ +use crate::manager::GridUser; + +use crate::services::persistence::GridDatabase; +use flowy_database::kv::KV; +use flowy_error::FlowyResult; +use flowy_grid_data_model::revision::GridRevision; +use flowy_revision::disk::{RevisionRecord, SQLiteGridRevisionPersistence}; +use flowy_revision::{mk_grid_block_revision_disk_cache, RevisionLoader, RevisionPersistence}; +use flowy_sync::client_grid::{make_grid_rev_json_str, GridRevisionPad}; +use flowy_sync::entities::revision::Revision; + +use lib_ot::core::PlainTextDeltaBuilder; +use serde::{Deserialize, Serialize}; +use std::str::FromStr; +use std::sync::Arc; + +pub(crate) struct GridMigration { + user: Arc, + database: Arc, +} + +impl GridMigration { + pub fn new(user: Arc, database: Arc) -> Self { + Self { user, database } + } + + pub async fn migration_grid_if_need(&self, grid_id: &str) -> FlowyResult<()> { + match KV::get_str(grid_id) { + None => { + let _ = self.reset_grid_rev(grid_id).await?; + let _ = self.save_migrate_record(grid_id)?; + } + Some(s) => { + let mut record = MigrationGridRecord::from_str(&s)?; + let empty_json = self.empty_grid_rev_json()?; + if record.len < empty_json.len() { + let _ = self.reset_grid_rev(grid_id).await?; + record.len = empty_json.len(); + KV::set_str(grid_id, record.to_string()); + } + } + } + Ok(()) + } + + async fn reset_grid_rev(&self, grid_id: &str) -> FlowyResult<()> { + let user_id = self.user.user_id()?; + let pool = self.database.db_pool()?; + let grid_rev_pad = self.get_grid_revision_pad(grid_id).await?; + let json = grid_rev_pad.json_str()?; + let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_delta_bytes(); + let revision = Revision::initial_revision(&user_id, grid_id, delta_data); + let record = RevisionRecord::new(revision); + // + let disk_cache = mk_grid_block_revision_disk_cache(&user_id, pool); + let _ = disk_cache.delete_and_insert_records(grid_id, None, vec![record]); + Ok(()) + } + + fn save_migrate_record(&self, grid_id: &str) -> FlowyResult<()> { + let empty_json_str = self.empty_grid_rev_json()?; + let record = MigrationGridRecord { + grid_id: grid_id.to_owned(), + len: empty_json_str.len(), + }; + KV::set_str(grid_id, record.to_string()); + Ok(()) + } + + fn empty_grid_rev_json(&self) -> FlowyResult { + let empty_grid_rev = GridRevision::default(); + let empty_json = make_grid_rev_json_str(&empty_grid_rev)?; + Ok(empty_json) + } + + async fn get_grid_revision_pad(&self, grid_id: &str) -> FlowyResult { + let pool = self.database.db_pool()?; + let user_id = self.user.user_id()?; + let disk_cache = SQLiteGridRevisionPersistence::new(&user_id, pool); + let rev_persistence = Arc::new(RevisionPersistence::new(&user_id, grid_id, disk_cache)); + let (revisions, _) = RevisionLoader { + object_id: grid_id.to_owned(), + user_id, + cloud: None, + rev_persistence, + } + .load() + .await?; + + let pad = GridRevisionPad::from_revisions(revisions)?; + Ok(pad) + } +} + +#[derive(Serialize, Deserialize)] +struct MigrationGridRecord { + grid_id: String, + len: usize, +} + +impl FromStr for MigrationGridRecord { + type Err = serde_json::Error; + + fn from_str(s: &str) -> Result { + serde_json::from_str::(s) + } +} + +impl ToString for MigrationGridRecord { + fn to_string(&self) -> String { + serde_json::to_string(self).unwrap_or_else(|_| "".to_string()) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/mod.rs index d6167cf8e6..7bd196acc7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/persistence/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/mod.rs @@ -4,6 +4,7 @@ use std::sync::Arc; pub mod block_index; pub mod kv; +pub mod migration; pub trait GridDatabase: Send + Sync { fn db_pool(&self) -> Result, FlowyError>; diff --git a/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs b/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs index 814b591f15..991d8f9b9f 100644 --- a/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs +++ b/frontend/rust-lib/flowy-revision/src/cache/disk/mod.rs @@ -53,6 +53,14 @@ pub struct RevisionRecord { } impl RevisionRecord { + pub fn new(revision: Revision) -> Self { + Self { + revision, + state: RevisionState::Sync, + write_to_disk: true, + } + } + pub fn ack(&mut self) { self.state = RevisionState::Ack; } @@ -64,6 +72,8 @@ pub struct RevisionChangeset { pub(crate) state: RevisionState, } +/// Sync: revision is not synced to the server +/// Ack: revision is synced to the server #[derive(Debug, Clone, Eq, PartialEq)] pub enum RevisionState { Sync = 0, diff --git a/frontend/rust-lib/flowy-revision/src/rev_persistence.rs b/frontend/rust-lib/flowy-revision/src/rev_persistence.rs index 98bc89ba24..eb3da339b7 100644 --- a/frontend/rust-lib/flowy-revision/src/rev_persistence.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_persistence.rs @@ -2,7 +2,7 @@ use crate::cache::{ disk::{RevisionChangeset, RevisionDiskCache, SQLiteTextBlockRevisionPersistence}, memory::RevisionMemoryCacheDelegate, }; -use crate::disk::{RevisionRecord, RevisionState}; +use crate::disk::{RevisionRecord, RevisionState, SQLiteGridBlockRevisionPersistence}; use crate::memory::RevisionMemoryCache; use crate::RevisionCompactor; use flowy_database::ConnectionPool; @@ -214,13 +214,20 @@ impl RevisionPersistence { } } -pub fn mk_revision_disk_cache( +pub fn mk_text_block_revision_disk_cache( user_id: &str, pool: Arc, ) -> Arc> { Arc::new(SQLiteTextBlockRevisionPersistence::new(user_id, pool)) } +pub fn mk_grid_block_revision_disk_cache( + user_id: &str, + pool: Arc, +) -> Arc> { + Arc::new(SQLiteGridBlockRevisionPersistence::new(user_id, pool)) +} + impl RevisionMemoryCacheDelegate for Arc> { fn checkpoint_tick(&self, mut records: Vec) -> FlowyResult<()> { records.retain(|record| record.write_to_disk); diff --git a/frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs b/frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs index 88073a3107..f2b862c53a 100644 --- a/frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs +++ b/frontend/rust-lib/flowy-sdk/src/deps_resolve/grid_deps.rs @@ -16,14 +16,23 @@ use std::sync::Arc; pub struct GridDepsResolver(); impl GridDepsResolver { - pub fn resolve(ws_conn: Arc, user_session: Arc) -> Arc { + pub async fn resolve(ws_conn: Arc, user_session: Arc) -> Arc { let user = Arc::new(GridUserImpl(user_session.clone())); let rev_web_socket = Arc::new(GridWebSocket(ws_conn)); - Arc::new(GridManager::new( - user, + let grid_manager = Arc::new(GridManager::new( + user.clone(), rev_web_socket, Arc::new(GridDatabaseImpl(user_session)), - )) + )); + + if let (Ok(user_id), Ok(token)) = (user.user_id(), user.token()) { + match grid_manager.initialize(&user_id, &token).await { + Ok(_) => {} + Err(e) => tracing::error!("Initialize grid manager failed: {}", e), + } + } + + grid_manager } } diff --git a/frontend/rust-lib/flowy-sdk/src/lib.rs b/frontend/rust-lib/flowy-sdk/src/lib.rs index 4a37faefef..00a3785122 100644 --- a/frontend/rust-lib/flowy-sdk/src/lib.rs +++ b/frontend/rust-lib/flowy-sdk/src/lib.rs @@ -112,7 +112,7 @@ impl FlowySDK { &config.server_config, ); - let grid_manager = GridDepsResolver::resolve(ws_conn.clone(), user_session.clone()); + let grid_manager = GridDepsResolver::resolve(ws_conn.clone(), user_session.clone()).await; let folder_manager = FolderDepsResolver::resolve( local_server.clone(), @@ -147,7 +147,7 @@ impl FlowySDK { ) })); - _start_listening(&dispatcher, &ws_conn, &user_session, &folder_manager); + _start_listening(&dispatcher, &ws_conn, &user_session, &folder_manager, &grid_manager); Self { config, @@ -171,10 +171,12 @@ fn _start_listening( ws_conn: &Arc, user_session: &Arc, folder_manager: &Arc, + grid_manager: &Arc, ) { let subscribe_user_status = user_session.notifier.subscribe_user_status(); let subscribe_network_type = ws_conn.subscribe_network_ty(); let folder_manager = folder_manager.clone(); + let grid_manager = grid_manager.clone(); let cloned_folder_manager = folder_manager.clone(); let ws_conn = ws_conn.clone(); let user_session = user_session.clone(); @@ -182,7 +184,13 @@ fn _start_listening( dispatch.spawn(async move { user_session.init(); listen_on_websocket(ws_conn.clone()); - _listen_user_status(ws_conn.clone(), subscribe_user_status, folder_manager.clone()).await; + _listen_user_status( + ws_conn.clone(), + subscribe_user_status, + folder_manager.clone(), + grid_manager.clone(), + ) + .await; }); dispatch.spawn(async move { @@ -209,6 +217,7 @@ async fn _listen_user_status( ws_conn: Arc, mut subscribe: broadcast::Receiver, folder_manager: Arc, + grid_manager: Arc, ) { while let Ok(status) = subscribe.recv().await { let result = || async { @@ -216,6 +225,7 @@ async fn _listen_user_status( UserStatus::Login { token, user_id } => { tracing::trace!("User did login"); let _ = folder_manager.initialize(&user_id, &token).await?; + let _ = grid_manager.initialize(&user_id, &token).await?; let _ = ws_conn.start(token, user_id).await?; } UserStatus::Logout { .. } => { @@ -233,6 +243,11 @@ async fn _listen_user_status( let _ = folder_manager .initialize_with_new_user(&profile.id, &profile.token) .await?; + + let _ = grid_manager + .initialize_with_new_user(&profile.id, &profile.token) + .await?; + let _ = ws_conn.start(profile.token.clone(), profile.id.clone()).await?; let _ = ret.send(()); } 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 671f71563f..2298eb485f 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 @@ -31,13 +31,8 @@ pub struct GridRevision { pub fields: Vec>, pub blocks: Vec>, - #[cfg(feature = "filter")] #[serde(default)] pub setting: GridSettingRevision, - - #[cfg(not(feature = "filter"))] - #[serde(default, skip)] - pub setting: GridSettingRevision, } impl GridRevision { diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index e47305f7fa..eaa6f1823a 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -62,7 +62,7 @@ impl GridRevisionPad { }) } - pub fn from_revisions(_grid_id: &str, revisions: Vec) -> CollaborateResult { + pub fn from_revisions(revisions: Vec) -> CollaborateResult { let grid_delta: GridRevisionDelta = make_delta_from_revisions::(revisions)?; Self::from_delta(grid_delta) } @@ -480,8 +480,8 @@ impl GridRevisionPad { match f(Arc::make_mut(&mut self.grid_rev))? { None => Ok(None), Some(_) => { - let old = json_from_grid(&cloned_grid)?; - let new = json_from_grid(&self.grid_rev)?; + let old = make_grid_rev_json_str(&cloned_grid)?; + let new = self.json_str()?; match cal_diff::(old, new) { None => Ok(None), Some(delta) => { @@ -528,9 +528,13 @@ impl GridRevisionPad { }, ) } + + pub fn json_str(&self) -> CollaborateResult { + make_grid_rev_json_str(&self.grid_rev) + } } -fn json_from_grid(grid: &Arc) -> CollaborateResult { +pub fn make_grid_rev_json_str(grid: &GridRevision) -> CollaborateResult { let json = serde_json::to_string(grid) .map_err(|err| internal_error(format!("Serialize grid to json str failed. {:?}", err)))?; Ok(json) From c97e1ccb953fe1260d6cc9d5078317ebe4bcadcb Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 20 Jul 2022 18:47:05 +0800 Subject: [PATCH 047/112] chore: fix tests --- shared-lib/flowy-grid-data-model/tests/serde_test.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared-lib/flowy-grid-data-model/tests/serde_test.rs b/shared-lib/flowy-grid-data-model/tests/serde_test.rs index b544e10588..1dff913547 100644 --- a/shared-lib/flowy-grid-data-model/tests/serde_test.rs +++ b/shared-lib/flowy-grid-data-model/tests/serde_test.rs @@ -6,5 +6,8 @@ fn grid_default_serde_test() { let grid = GridRevision::new(&grid_id); let json = serde_json::to_string(&grid).unwrap(); - assert_eq!(json, r#"{"grid_id":"1","fields":[],"blocks":[]}"#) + assert_eq!( + json, + r#"{"grid_id":"1","fields":[],"blocks":[],"setting":{"layout":0,"filters":[]}}"# + ) } From 1758d8b74adc9152b61414fe9f25f75db9d92917 Mon Sep 17 00:00:00 2001 From: Nir Givon Date: Wed, 20 Jul 2022 13:58:51 +0300 Subject: [PATCH 048/112] fix: Typo: Month/Month/Day -> Year/Month/Day --- frontend/app_flowy/assets/translations/en.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/app_flowy/assets/translations/en.json b/frontend/app_flowy/assets/translations/en.json index a6f9b4d3ae..8b9971e99a 100644 --- a/frontend/app_flowy/assets/translations/en.json +++ b/frontend/app_flowy/assets/translations/en.json @@ -172,8 +172,8 @@ "includeTime": " Include time", "dateFormatFriendly": "Month Day,Year", "dateFormatISO": "Year-Month-Day", - "dateFormatLocal": "Month/Month/Day", - "dateFormatUS": "Month/Month/Day", + "dateFormatLocal": "Year/Month/Day", + "dateFormatUS": "Year/Month/Day", "timeFormat": " Time format", "invalidTimeFormat": "Invalid format", "timeFormatTwelveHour": "12 hour", @@ -214,4 +214,4 @@ "timeHintTextInTwentyFourHour": "12:00" } } -} +} \ No newline at end of file From da3fd117378053dee1195f7618dd3d8eb8fcece6 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 20 Jul 2022 20:08:42 +0800 Subject: [PATCH 049/112] fix: open the latest view when AppFlowy launch. --- .../lib/workspace/presentation/home/home_screen.dart | 5 ++++- .../app_flowy/lib/workspace/presentation/home/menu/menu.dart | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart index f3a9f6773a..d1d5321848 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart @@ -122,7 +122,10 @@ class _HomeScreenState extends State { ); final latestView = workspaceSetting.hasLatestView() ? workspaceSetting.latestView : null; - getIt().latestOpenView = latestView; + if (getIt().latestOpenView == null) { + /// AppFlowy will open the view that the last time the user opened it. The _buildHomeMenu will get called when AppFlowy's screen resizes. So we only set the latestOpenView when it's null. + getIt().latestOpenView = latestView; + } return FocusTraversalGroup(child: RepaintBoundary(child: homeMenu)); } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart index ef5e20bb6b..3976598b7b 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart @@ -164,7 +164,9 @@ class MenuSharedState { ViewPB? get latestOpenView => _latestOpenView.value; set latestOpenView(ViewPB? view) { - _latestOpenView.value = view; + if (_latestOpenView.value != view) { + _latestOpenView.value = view; + } } VoidCallback addLatestViewListener(void Function(ViewPB?) callback) { From d1fb443aa75c49b624c0669a4b964d9c9248fea9 Mon Sep 17 00:00:00 2001 From: mhead Date: Wed, 20 Jul 2022 19:53:00 +0530 Subject: [PATCH 050/112] feat: resize the left-hand sidebar --- .../workspace/application/home/home_bloc.dart | 81 ++++++++++--------- .../presentation/home/home_layout.dart | 2 + .../presentation/home/home_screen.dart | 23 ++++++ 3 files changed, 70 insertions(+), 36 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart b/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart index a4ddef0945..af637ea1c7 100644 --- a/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/home/home_bloc.dart @@ -16,42 +16,48 @@ class HomeBloc extends Bloc { HomeBloc(UserProfilePB user, CurrentWorkspaceSettingPB workspaceSetting) : _listener = UserWorkspaceListener(userProfile: user), super(HomeState.initial(workspaceSetting)) { - on((event, emit) async { - await event.map( - initial: (_Initial value) { - _listener.start( - onAuthChanged: (result) => _authDidChanged(result), - onSettingUpdated: (result) { - result.fold( - (setting) => add(HomeEvent.didReceiveWorkspaceSetting(setting)), - (r) => Log.error(r), - ); - }, - ); - }, - showLoading: (e) async { - emit(state.copyWith(isLoading: e.isLoading)); - }, - setEditPannel: (e) async { - emit(state.copyWith(pannelContext: some(e.editContext))); - }, - dismissEditPannel: (value) async { - emit(state.copyWith(pannelContext: none())); - }, - forceCollapse: (e) async { - emit(state.copyWith(forceCollapse: e.forceCollapse)); - }, - didReceiveWorkspaceSetting: (_DidReceiveWorkspaceSetting value) { - emit(state.copyWith(workspaceSetting: value.setting)); - }, - unauthorized: (_Unauthorized value) { - emit(state.copyWith(unauthorized: true)); - }, - collapseMenu: (e) { - emit(state.copyWith(isMenuCollapsed: !state.isMenuCollapsed)); - }, - ); - }); + on( + (event, emit) async { + await event.map( + initial: (_Initial value) { + _listener.start( + onAuthChanged: (result) => _authDidChanged(result), + onSettingUpdated: (result) { + result.fold( + (setting) => add(HomeEvent.didReceiveWorkspaceSetting(setting)), + (r) => Log.error(r), + ); + }, + ); + }, + showLoading: (e) async { + emit(state.copyWith(isLoading: e.isLoading)); + }, + setEditPannel: (e) async { + emit(state.copyWith(pannelContext: some(e.editContext))); + }, + dismissEditPannel: (value) async { + emit(state.copyWith(pannelContext: none())); + }, + forceCollapse: (e) async { + emit(state.copyWith(forceCollapse: e.forceCollapse)); + }, + didReceiveWorkspaceSetting: (_DidReceiveWorkspaceSetting value) { + emit(state.copyWith(workspaceSetting: value.setting)); + }, + unauthorized: (_Unauthorized value) { + emit(state.copyWith(unauthorized: true)); + }, + collapseMenu: (e) { + emit(state.copyWith(isMenuCollapsed: !state.isMenuCollapsed)); + }, + editPannelResized: (e) { + final newOffset = (state.resizeOffset + e.offset).clamp(-50, 200).toDouble(); + emit(state.copyWith(resizeOffset: newOffset)); + }, + ); + }, + ); } @override @@ -79,6 +85,7 @@ class HomeEvent with _$HomeEvent { const factory HomeEvent.didReceiveWorkspaceSetting(CurrentWorkspaceSettingPB setting) = _DidReceiveWorkspaceSetting; const factory HomeEvent.unauthorized(String msg) = _Unauthorized; const factory HomeEvent.collapseMenu() = _CollapseMenu; + const factory HomeEvent.editPannelResized(double offset) = _EditPannelResized; } @freezed @@ -90,6 +97,7 @@ class HomeState with _$HomeState { required CurrentWorkspaceSettingPB workspaceSetting, required bool unauthorized, required bool isMenuCollapsed, + required double resizeOffset, }) = _HomeState; factory HomeState.initial(CurrentWorkspaceSettingPB workspaceSetting) => HomeState( @@ -99,5 +107,6 @@ class HomeState with _$HomeState { workspaceSetting: workspaceSetting, unauthorized: false, isMenuCollapsed: false, + resizeOffset: 0, ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_layout.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_layout.dart index 0405279851..e7e02b9767 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_layout.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/home_layout.dart @@ -27,6 +27,8 @@ class HomeLayout { menuWidth = Sizes.sideBarLg; } + menuWidth += homeBlocState.resizeOffset; + if (forceCollapse) { showMenu = false; } else { diff --git a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart index f3a9f6773a..a084feca47 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/home_screen.dart @@ -7,6 +7,7 @@ import 'package:flowy_sdk/log.dart'; import 'package:flowy_infra_ui/style_widget/container.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfilePB; import 'package:flowy_sdk/protobuf/flowy-folder/protobuf.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -87,6 +88,7 @@ class _HomeScreenState extends State { context: context, state: state, ); + final homeMenuResizer = _buildHomeMenuResizer(context: context); final editPannel = _buildEditPannel( homeState: state, layout: layout, @@ -99,6 +101,7 @@ class _HomeScreenState extends State { homeMenu: menu, editPannel: editPannel, bubble: bubble, + homeMenuResizer: homeMenuResizer, ); }, ); @@ -147,12 +150,31 @@ class _HomeScreenState extends State { ); } + Widget _buildHomeMenuResizer({ + required BuildContext context, + }) { + return MouseRegion( + cursor: SystemMouseCursors.resizeLeftRight, + child: GestureDetector( + dragStartBehavior: DragStartBehavior.down, + onPanUpdate: ((details) { + context.read().add(HomeEvent.editPannelResized(details.delta.dx)); + }), + behavior: HitTestBehavior.translucent, + child: SizedBox( + width: 10, + height: MediaQuery.of(context).size.height, + )), + ); + } + Widget _layoutWidgets({ required HomeLayout layout, required Widget homeMenu, required Widget homeStack, required Widget editPannel, required Widget bubble, + required Widget homeMenuResizer, }) { return Stack( children: [ @@ -167,6 +189,7 @@ class _HomeScreenState extends State { .constrained(minWidth: 500) .positioned(left: layout.homePageLOffset, right: layout.homePageROffset, bottom: 0, top: 0, animate: true) .animate(layout.animDuration, Curves.easeOut), + homeMenuResizer.positioned(left: layout.homePageLOffset - 5), bubble .positioned( right: 20, From da80efecd17b320b3c7f6c730b1110ed590e49e7 Mon Sep 17 00:00:00 2001 From: Ian Su Date: Fri, 22 Jul 2022 00:01:39 +0800 Subject: [PATCH 051/112] feat: add SettingDialogBloc --- .../app_flowy/lib/startup/deps_resolver.dart | 6 ++ .../application/settings/prelude.dart | 1 + .../settings/settings_dialog_bloc.dart | 67 +++++++++++++ .../settings/settings_dialog.dart | 98 +++++++++---------- .../settings/widgets/settings_user_view.dart | 1 - 5 files changed, 122 insertions(+), 51 deletions(-) create mode 100644 frontend/app_flowy/lib/workspace/application/settings/prelude.dart create mode 100644 frontend/app_flowy/lib/workspace/application/settings/settings_dialog_bloc.dart diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index ed382f9b83..bafbb46919 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -10,6 +10,7 @@ import 'package:app_flowy/workspace/application/workspace/prelude.dart'; import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dart'; import 'package:app_flowy/workspace/application/view/prelude.dart'; import 'package:app_flowy/workspace/application/menu/prelude.dart'; +import 'package:app_flowy/workspace/application/settings/prelude.dart'; import 'package:app_flowy/user/application/prelude.dart'; import 'package:app_flowy/user/presentation/router.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; @@ -102,6 +103,11 @@ void _resolveFolderDeps(GetIt getIt) { (user, _) => MenuUserBloc(user), ); + //Settings + getIt.registerFactoryParam( + (user, _) => SettingsDialogBloc(user), + ); + //User getIt.registerFactoryParam( (user, _) => SettingsUserViewBloc(user), diff --git a/frontend/app_flowy/lib/workspace/application/settings/prelude.dart b/frontend/app_flowy/lib/workspace/application/settings/prelude.dart new file mode 100644 index 0000000000..3917b54aaf --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/settings/prelude.dart @@ -0,0 +1 @@ +export 'settings_dialog_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/settings/settings_dialog_bloc.dart b/frontend/app_flowy/lib/workspace/application/settings/settings_dialog_bloc.dart new file mode 100644 index 0000000000..1dd73638b2 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/settings/settings_dialog_bloc.dart @@ -0,0 +1,67 @@ +import 'package:app_flowy/user/application/user_listener.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:dartz/dartz.dart'; + +part 'settings_dialog_bloc.freezed.dart'; + +class SettingsDialogBloc extends Bloc { + final UserListener _userListener; + final UserProfile userProfile; + + SettingsDialogBloc(this.userProfile) + : _userListener = UserListener(userProfile: userProfile), + super(SettingsDialogState.initial(userProfile)) { + on((event, emit) async { + await event.when( + initial: () async { + _userListener.start(onProfileUpdated: _profileUpdated); + }, + didReceiveUserProfile: (UserProfile newUserProfile) { + emit(state.copyWith(userProfile: newUserProfile)); + }, + setViewIndex: (int viewIndex) { + emit(state.copyWith(viewIndex: viewIndex)); + }, + ); + }); + } + + @override + Future close() async { + await _userListener.stop(); + super.close(); + } + + void _profileUpdated(Either userProfileOrFailed) { + userProfileOrFailed.fold( + (newUserProfile) => add(SettingsDialogEvent.didReceiveUserProfile(newUserProfile)), + (err) => Log.error(err), + ); + } +} + +@freezed +class SettingsDialogEvent with _$SettingsDialogEvent { + const factory SettingsDialogEvent.initial() = _Initial; + const factory SettingsDialogEvent.didReceiveUserProfile(UserProfile newUserProfile) = _DidReceiveUserProfile; + const factory SettingsDialogEvent.setViewIndex(int index) = _SetViewIndex; +} + +@freezed +class SettingsDialogState with _$SettingsDialogState { + const factory SettingsDialogState({ + required UserProfile userProfile, + required Either successOrFailure, + required int viewIndex, + }) = _SettingsDialogState; + + factory SettingsDialogState.initial(UserProfile userProfile) => SettingsDialogState( + userProfile: userProfile, + successOrFailure: left(unit), + viewIndex: 0, + ); +} diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart b/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart index 72bb0bf7ac..ae4d3f5e52 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart @@ -1,25 +1,21 @@ +import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_appearance_view.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_language_view.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_user_view.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_menu.dart'; +import 'package:app_flowy/workspace/application/settings/settings_dialog_bloc.dart'; import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:provider/provider.dart'; -class SettingsDialog extends StatefulWidget { +class SettingsDialog extends StatelessWidget { final UserProfile user; SettingsDialog(this.user, {Key? key}) : super(key: ValueKey(user.id)); - @override - State createState() => _SettingsDialogState(); -} - -class _SettingsDialogState extends State { - int _selectedViewIndex = 0; - Widget getSettingsView(int index, UserProfile user) { final List settingsViews = [ const SettingsAppearanceView(), @@ -31,47 +27,49 @@ class _SettingsDialogState extends State { @override Widget build(BuildContext context) { - return ChangeNotifierProvider.value( - value: Provider.of(context, listen: true), - child: AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - title: Text( - LocaleKeys.settings_title.tr(), - style: const TextStyle( - fontWeight: FontWeight.bold, - ), - ), - content: ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 600, - minWidth: 600, - maxWidth: 1000, - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox( - width: 200, - child: SettingsMenu( - changeSelectedIndex: (index) { - setState(() { - _selectedViewIndex = index; - }); - }, - currentIndex: _selectedViewIndex, - ), - ), - const VerticalDivider(), - const SizedBox(width: 10), - Expanded( - child: getSettingsView(_selectedViewIndex, widget.user), - ) - ], - ), - ), - ), - ); + return BlocProvider( + create: (context) => getIt(param1: user)..add(const SettingsDialogEvent.initial()), + child: BlocBuilder( + builder: (context, state) => ChangeNotifierProvider.value( + value: Provider.of(context, listen: true), + child: AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + title: Text( + LocaleKeys.settings_title.tr(), + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + content: ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 600, + minWidth: 600, + maxWidth: 1000, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 200, + child: SettingsMenu( + changeSelectedIndex: (index) { + context.read().add(SettingsDialogEvent.setViewIndex(index)); + }, + currentIndex: context.read().state.viewIndex, + ), + ), + const VerticalDivider(), + const SizedBox(width: 10), + Expanded( + child: getSettingsView(context.read().state.viewIndex, + context.read().state.userProfile), + ) + ], + ), + ), + ), + ))); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart index f347dbed7b..6cc56ccf74 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -25,7 +25,6 @@ class SettingsUserView extends StatelessWidget { Widget _renderUserNameInput(BuildContext context) { String name = context.read().state.userProfile.name; - debugPrint(name); return _UserNameInput(name); } } From 1a887979c4991db4fc2ae95c91327debb8b50015 Mon Sep 17 00:00:00 2001 From: Ian Su Date: Fri, 22 Jul 2022 00:54:11 +0800 Subject: [PATCH 052/112] fix: fix merge from main --- .../workspace/application/menu/menu_user_bloc.dart | 8 ++++++++ .../application/settings/settings_dialog_bloc.dart | 12 ++++++------ .../application/user/settings_user_bloc.dart | 12 ++++++------ .../presentation/settings/settings_dialog.dart | 6 +++--- .../settings/widgets/settings_user_view.dart | 4 ++-- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart b/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart index e6cadcfe3a..0f30bb9d45 100644 --- a/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/menu/menu_user_bloc.dart @@ -34,6 +34,14 @@ class MenuUserBloc extends Bloc { didReceiveUserProfile: (UserProfilePB newUserProfile) { emit(state.copyWith(userProfile: newUserProfile)); }, + updateUserName: (String name) { + _userService.updateUserProfile(name: name).then((result) { + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }); + }, ); }); } diff --git a/frontend/app_flowy/lib/workspace/application/settings/settings_dialog_bloc.dart b/frontend/app_flowy/lib/workspace/application/settings/settings_dialog_bloc.dart index 1dd73638b2..3c40f767b1 100644 --- a/frontend/app_flowy/lib/workspace/application/settings/settings_dialog_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/settings/settings_dialog_bloc.dart @@ -10,7 +10,7 @@ part 'settings_dialog_bloc.freezed.dart'; class SettingsDialogBloc extends Bloc { final UserListener _userListener; - final UserProfile userProfile; + final UserProfilePB userProfile; SettingsDialogBloc(this.userProfile) : _userListener = UserListener(userProfile: userProfile), @@ -20,7 +20,7 @@ class SettingsDialogBloc extends Bloc initial: () async { _userListener.start(onProfileUpdated: _profileUpdated); }, - didReceiveUserProfile: (UserProfile newUserProfile) { + didReceiveUserProfile: (UserProfilePB newUserProfile) { emit(state.copyWith(userProfile: newUserProfile)); }, setViewIndex: (int viewIndex) { @@ -36,7 +36,7 @@ class SettingsDialogBloc extends Bloc super.close(); } - void _profileUpdated(Either userProfileOrFailed) { + void _profileUpdated(Either userProfileOrFailed) { userProfileOrFailed.fold( (newUserProfile) => add(SettingsDialogEvent.didReceiveUserProfile(newUserProfile)), (err) => Log.error(err), @@ -47,19 +47,19 @@ class SettingsDialogBloc extends Bloc @freezed class SettingsDialogEvent with _$SettingsDialogEvent { const factory SettingsDialogEvent.initial() = _Initial; - const factory SettingsDialogEvent.didReceiveUserProfile(UserProfile newUserProfile) = _DidReceiveUserProfile; + const factory SettingsDialogEvent.didReceiveUserProfile(UserProfilePB newUserProfile) = _DidReceiveUserProfile; const factory SettingsDialogEvent.setViewIndex(int index) = _SetViewIndex; } @freezed class SettingsDialogState with _$SettingsDialogState { const factory SettingsDialogState({ - required UserProfile userProfile, + required UserProfilePB userProfile, required Either successOrFailure, required int viewIndex, }) = _SettingsDialogState; - factory SettingsDialogState.initial(UserProfile userProfile) => SettingsDialogState( + factory SettingsDialogState.initial(UserProfilePB userProfile) => SettingsDialogState( userProfile: userProfile, successOrFailure: left(unit), viewIndex: 0, diff --git a/frontend/app_flowy/lib/workspace/application/user/settings_user_bloc.dart b/frontend/app_flowy/lib/workspace/application/user/settings_user_bloc.dart index 5a4954c068..7435778471 100644 --- a/frontend/app_flowy/lib/workspace/application/user/settings_user_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/user/settings_user_bloc.dart @@ -12,7 +12,7 @@ part 'settings_user_bloc.freezed.dart'; class SettingsUserViewBloc extends Bloc { final UserService _userService; final UserListener _userListener; - final UserProfile userProfile; + final UserProfilePB userProfile; SettingsUserViewBloc(this.userProfile) : _userListener = UserListener(userProfile: userProfile), @@ -24,7 +24,7 @@ class SettingsUserViewBloc extends Bloc { _userListener.start(onProfileUpdated: _profileUpdated); await _initUser(); }, - didReceiveUserProfile: (UserProfile newUserProfile) { + didReceiveUserProfile: (UserProfilePB newUserProfile) { emit(state.copyWith(userProfile: newUserProfile)); }, updateUserName: (String name) { @@ -50,7 +50,7 @@ class SettingsUserViewBloc extends Bloc { result.fold((l) => null, (error) => Log.error(error)); } - void _profileUpdated(Either userProfileOrFailed) { + void _profileUpdated(Either userProfileOrFailed) { userProfileOrFailed.fold( (newUserProfile) => add(SettingsUserEvent.didReceiveUserProfile(newUserProfile)), (err) => Log.error(err), @@ -62,17 +62,17 @@ class SettingsUserViewBloc extends Bloc { class SettingsUserEvent with _$SettingsUserEvent { const factory SettingsUserEvent.initial() = _Initial; const factory SettingsUserEvent.updateUserName(String name) = _UpdateUserName; - const factory SettingsUserEvent.didReceiveUserProfile(UserProfile newUserProfile) = _DidReceiveUserProfile; + const factory SettingsUserEvent.didReceiveUserProfile(UserProfilePB newUserProfile) = _DidReceiveUserProfile; } @freezed class SettingsUserState with _$SettingsUserState { const factory SettingsUserState({ - required UserProfile userProfile, + required UserProfilePB userProfile, required Either successOrFailure, }) = _SettingsUserState; - factory SettingsUserState.initial(UserProfile userProfile) => SettingsUserState( + factory SettingsUserState.initial(UserProfilePB userProfile) => SettingsUserState( userProfile: userProfile, successOrFailure: left(unit), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart b/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart index ae4d3f5e52..eaf09d770f 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/settings_dialog.dart @@ -6,17 +6,17 @@ import 'package:app_flowy/workspace/presentation/settings/widgets/settings_langu import 'package:app_flowy/workspace/presentation/settings/widgets/settings_user_view.dart'; import 'package:app_flowy/workspace/presentation/settings/widgets/settings_menu.dart'; import 'package:app_flowy/workspace/application/settings/settings_dialog_bloc.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:provider/provider.dart'; class SettingsDialog extends StatelessWidget { - final UserProfile user; + final UserProfilePB user; SettingsDialog(this.user, {Key? key}) : super(key: ValueKey(user.id)); - Widget getSettingsView(int index, UserProfile user) { + Widget getSettingsView(int index, UserProfilePB user) { final List settingsViews = [ const SettingsAppearanceView(), const SettingsLanguageView(), diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart index 6cc56ccf74..f8f094d1b0 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_user_view.dart @@ -2,10 +2,10 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:flutter/material.dart'; import 'package:app_flowy/workspace/application/user/settings_user_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flowy_sdk/protobuf/flowy-user/protobuf.dart' show UserProfile; +import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; class SettingsUserView extends StatelessWidget { - final UserProfile user; + final UserProfilePB user; SettingsUserView(this.user, {Key? key}) : super(key: ValueKey(user.id)); @override From ab414b77f6cd55381e7d4f00fb58915c739735e1 Mon Sep 17 00:00:00 2001 From: mastergyp Date: Mon, 18 Jul 2022 11:32:18 +0800 Subject: [PATCH 053/112] fix: unable to run build_runner - The getter 'imports' isn't defined for the class 'PrefixElement' --- frontend/app_flowy/pubspec.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/app_flowy/pubspec.yaml b/frontend/app_flowy/pubspec.yaml index 8dbc3b4c70..5f4ff9c9b8 100644 --- a/frontend/app_flowy/pubspec.yaml +++ b/frontend/app_flowy/pubspec.yaml @@ -85,6 +85,9 @@ dev_dependencies: freezed: bloc_test: ^9.0.2 +dependency_overrides: + analyzer: ">=4.2.0 <5.0.0" + # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your From 414bb75688e5f225a9ee1a5959a3e2eec7159d7a Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 22 Jul 2022 09:57:20 +0800 Subject: [PATCH 054/112] chore: replace Ilshidur/action-discord@0.3.2 with Ilshidur/action-discord@master --- .github/workflows/translation_notify.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/translation_notify.yml b/.github/workflows/translation_notify.yml index 8c12ccb0b8..00f1576b6f 100644 --- a/.github/workflows/translation_notify.yml +++ b/.github/workflows/translation_notify.yml @@ -4,15 +4,12 @@ on: branches: [ main ] paths: - "frontend/app_flowy/assets/translations/en.json" - pull_request: - branches: [ main ] - paths: - - "frontend/app_flowy/assets/translations/en.json" + jobs: Discord-Notify: runs-on: ubuntu-latest steps: - - uses: Ilshidur/action-discord@0.3.2 + - uses: Ilshidur/action-discord@master env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }} with: From a273184afd01cdb23fd301bbb54f9a0a221c6482 Mon Sep 17 00:00:00 2001 From: kakzaki Date: Fri, 22 Jul 2022 13:19:03 +0700 Subject: [PATCH 055/112] feat: add indonesian translation --- .../app_flowy/assets/translations/id-ID.json | 218 ++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 frontend/app_flowy/assets/translations/id-ID.json diff --git a/frontend/app_flowy/assets/translations/id-ID.json b/frontend/app_flowy/assets/translations/id-ID.json new file mode 100644 index 0000000000..bc9aed8a45 --- /dev/null +++ b/frontend/app_flowy/assets/translations/id-ID.json @@ -0,0 +1,218 @@ +{ + "appName": "AppFlowy", + "defaultUsername": "Saya", + "welcomeText": "Selamat datang di @:appName", + "githubStarText": "Bintangi GitHub", + "subscribeNewsletterText": "Berlangganan buletin", + "letsGoButtonText": "Ayo", + "title": "Judul", + "signUp": { + "buttonText": "Daftar", + "title": "Daftar ke @:appName", + "getStartedText": "Mulai", + "emptyPasswordError": "Sandi tidak boleh kosong", + "repeatPasswordEmptyError": "Sandi ulang tidak boleh kosong", + "unmatchedPasswordError": "Sandi ulang tidak sama dengan sandi", + "alreadyHaveAnAccount": "Sudah punya akun?", + "emailHint": "Email", + "passwordHint": "Sandi", + "repeatPasswordHint": "Sandi ulang" + }, + "signIn": { + "loginTitle": "Masuk ke @:appName", + "loginButtonText": "Masuk", + "buttonText": "Masuk", + "forgotPassword": "Lupa Sandi?", + "emailHint": "Email", + "passwordHint": "Sandi", + "dontHaveAnAccount": "Belum punya akun?", + "repeatPasswordEmptyError": "Sandi ulang tidak boleh kosong", + "unmatchedPasswordError": "Sandi ulang tidak sama dengan sandi" + }, + "workspace": { + "create": "Buat workspace", + "hint": "workspace", + "notFoundError": "Workspace tidak ditemukan" + }, + "shareAction": { + "buttonText": "Bagikan", + "workInProgress": "Segera", + "markdown": "Markdown", + "copyLink": "Salin tautan" + }, + "disclosureAction": { + "rename": "Ganti nama", + "delete": "Hapus", + "duplicate": "Duplikat" + }, + "blankPageTitle": "Halaman kosong", + "newPageText": "Halaman baru", + "trash": { + "text": "Sampah", + "restoreAll": "Pulihkan Semua", + "deleteAll": "Hapus semua", + "pageHeader": { + "fileName": "Nama file", + "lastModified": "Terakhir diubah", + "created": "Dibuat" + } + }, + "deletePagePrompt": { + "text": "Halaman ini di tempat sampah", + "restore": "Pulihkan halaman", + "deletePermanent": "Hapus secara permanen" + }, + "dialogCreatePageNameHint": "Nama halaman", + "questionBubble": { + "whatsNew": "Apa yang baru?", + "help": "Bantuan & Dukungan", + "debug": { + "name": "Info debug", + "success": "Info debug disalin ke papan klip!", + "fail": "Tidak dapat menyalin info debug ke papan klip" + } + }, + "menuAppHeader": { + "addPageTooltip": "Menambahkan halaman di dalam dengan cepat", + "defaultNewPageName": "Tanpa Judul", + "renameDialog": "Ganti nama" + }, + "toolbar": { + "undo": "Undo", + "redo": "Redo", + "bold": "Tebal", + "italic": "Miring", + "underline": "Garis bawah", + "strike": "Dicoret", + "numList": "Daftar bernomor", + "bulletList": "Daftar berpoin", + "checkList": "Daftar periksa", + "inlineCode": "Kode sebaris", + "quote": "Blok kutipan", + "header": "Tajuk", + "highlight": "Sorotan" + }, + "tooltip": { + "lightMode": "Ganti mode terang", + "darkMode": "Ganti mode gelap" + }, + "notifications": { + "export": { + "markdown": "Mengekspor Catatan ke Markdown", + "path": "Documents/flowy" + } + }, + "contactsPage": { + "title": "Kontak", + "whatsHappening": "Apa yang terjadi minggu ini?", + "addContact": "Tambahkan Kontak", + "editContact": "Ubah Kontak" + }, + "button": { + "OK": "Ya", + "Cancel": "Batal", + "signIn": "Masuk", + "signOut": "Keluar", + "complete": "Selesai", + "save": "Simpan" + }, + "label": { + "welcome": "Selamat datang!", + "firstName": "Nama Depan", + "middleName": "Nama Tengah", + "lastName": "Nama Akhir", + "stepX": "Langkah {X}" + }, + "oAuth": { + "err": { + "failedTitle": "Tidak dapat terhubung ke akun anda", + "failedMsg": "Mohon pastikan anda menyelesaikan proses pendaftaran pada browser anda." + }, + "google": { + "title": "MASUK GOOGLE", + "instruction1": "Untuk mengimpor kontak Google Contacts anda, anda harus mengizinkan aplikasi ini menggunakan browser web anda.", + "instruction2": "Salin kode ini ke papan klip anda dengan cara mengklik ikon atau memilih teks:", + "instruction3": "Arahkan ke tautan berikut di browser web Anda, dan masukkan kode di atas:", + "instruction4": "Tekan tombol di bawah ini setelah Anda menyelesaikan pendaftaran:" + } + }, + "settings": { + "title": "Pengaturan", + "menu": { + "appearance": "Tampilan", + "language": "Bahasa", + "user": "Pengguna", + "open": "Buka Pengaturan" + }, + "appearance": { + "lightLabel": "Mode Terang", + "darkLabel": "Mode Gelap" + } + }, + "grid": { + "settings": { + "filter": "Filter", + "sortBy": "Sortir dengan", + "Properties": "Properti" + }, + "field": { + "hide": "Sembunyikan", + "insertLeft": "Sisipkan Kiri", + "insertRight": "Sisipkan Kanan", + "duplicate": "Duplikasi", + "delete": "Hapus", + "textFieldName": "Teks", + "checkboxFieldName": "Kotak Centang", + "dateFieldName": "Tanggal", + "numberFieldName": "Angka", + "singleSelectFieldName": "seleksi", + "multiSelectFieldName": "Multi seleksi", + "urlFieldName": "URL", + "numberFormat": " Format angka", + "dateFormat": " Format tanggal", + "includeTime": " Sertakan waktu", + "dateFormatFriendly": "Bulan Hari,Tahun", + "dateFormatISO": "Tahun-Bulan-Hari", + "dateFormatLocal": "Tahun/Bulan/Hari", + "dateFormatUS": "Tahun/Bulan/Hari", + "timeFormat": " Format waktu", + "invalidTimeFormat": "Format yang tidak valid", + "timeFormatTwelveHour": "12 jam", + "timeFormatTwentyFourHour": "24 jam", + "addSelectOption": "Tambahkan opsi", + "optionTitle": "Opsi", + "addOption": "Tambahkan opsi", + "editProperty": "Ubah properti", + }, + "row": { + "duplicate": "Duplikasi", + "delete": "Hapus", + "textPlaceholder": "Kosong", + "copyProperty": "Salin properti ke papan klip", + }, + "selectOption": { + "create": "Buat", + "purpleColor": "Ungu", + "pinkColor": "Merah Jambu", + "lightPinkColor": "Merah Jambu Muda", + "orangeColor": "Oranye", + "yellowColor": "Kuning", + "limeColor": "Limau", + "greenColor": "Hijau", + "aquaColor": "Air", + "blueColor": "Biru", + "deleteTag": "Hapus tag", + "colorPannelTitle": "Warna", + "pannelTitle": "Pilih opsi atau buat baru", + "searchOption": "Cari opsi" + }, + "menuName": "Grid" + }, + "document": { + "menuName": "Doc", + "date": { + "timeHintTextInTwelveHour": "12:00 AM", + "timeHintTextInTwentyFourHour": "12:00" + } + } +} \ No newline at end of file From ab89aa2ba90e9003f1ed7fae7848ddbe0a507c2f Mon Sep 17 00:00:00 2001 From: kakzaki Date: Fri, 22 Jul 2022 14:29:01 +0700 Subject: [PATCH 056/112] feat: add indonesian transation --- frontend/app_flowy/assets/translations/id-ID.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/app_flowy/assets/translations/id-ID.json b/frontend/app_flowy/assets/translations/id-ID.json index bc9aed8a45..cbe721c2b8 100644 --- a/frontend/app_flowy/assets/translations/id-ID.json +++ b/frontend/app_flowy/assets/translations/id-ID.json @@ -182,13 +182,13 @@ "addSelectOption": "Tambahkan opsi", "optionTitle": "Opsi", "addOption": "Tambahkan opsi", - "editProperty": "Ubah properti", + "editProperty": "Ubah properti" }, "row": { "duplicate": "Duplikasi", "delete": "Hapus", "textPlaceholder": "Kosong", - "copyProperty": "Salin properti ke papan klip", + "copyProperty": "Salin properti ke papan klip" }, "selectOption": { "create": "Buat", From 6a8bddcf75435dba776e79705d68a32d822ec44b Mon Sep 17 00:00:00 2001 From: kakzaki Date: Fri, 22 Jul 2022 14:36:58 +0700 Subject: [PATCH 057/112] feat: add indonesian translation --- .../app_flowy/assets/translations/id-ID.json | 218 ++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 frontend/app_flowy/assets/translations/id-ID.json diff --git a/frontend/app_flowy/assets/translations/id-ID.json b/frontend/app_flowy/assets/translations/id-ID.json new file mode 100644 index 0000000000..cbe721c2b8 --- /dev/null +++ b/frontend/app_flowy/assets/translations/id-ID.json @@ -0,0 +1,218 @@ +{ + "appName": "AppFlowy", + "defaultUsername": "Saya", + "welcomeText": "Selamat datang di @:appName", + "githubStarText": "Bintangi GitHub", + "subscribeNewsletterText": "Berlangganan buletin", + "letsGoButtonText": "Ayo", + "title": "Judul", + "signUp": { + "buttonText": "Daftar", + "title": "Daftar ke @:appName", + "getStartedText": "Mulai", + "emptyPasswordError": "Sandi tidak boleh kosong", + "repeatPasswordEmptyError": "Sandi ulang tidak boleh kosong", + "unmatchedPasswordError": "Sandi ulang tidak sama dengan sandi", + "alreadyHaveAnAccount": "Sudah punya akun?", + "emailHint": "Email", + "passwordHint": "Sandi", + "repeatPasswordHint": "Sandi ulang" + }, + "signIn": { + "loginTitle": "Masuk ke @:appName", + "loginButtonText": "Masuk", + "buttonText": "Masuk", + "forgotPassword": "Lupa Sandi?", + "emailHint": "Email", + "passwordHint": "Sandi", + "dontHaveAnAccount": "Belum punya akun?", + "repeatPasswordEmptyError": "Sandi ulang tidak boleh kosong", + "unmatchedPasswordError": "Sandi ulang tidak sama dengan sandi" + }, + "workspace": { + "create": "Buat workspace", + "hint": "workspace", + "notFoundError": "Workspace tidak ditemukan" + }, + "shareAction": { + "buttonText": "Bagikan", + "workInProgress": "Segera", + "markdown": "Markdown", + "copyLink": "Salin tautan" + }, + "disclosureAction": { + "rename": "Ganti nama", + "delete": "Hapus", + "duplicate": "Duplikat" + }, + "blankPageTitle": "Halaman kosong", + "newPageText": "Halaman baru", + "trash": { + "text": "Sampah", + "restoreAll": "Pulihkan Semua", + "deleteAll": "Hapus semua", + "pageHeader": { + "fileName": "Nama file", + "lastModified": "Terakhir diubah", + "created": "Dibuat" + } + }, + "deletePagePrompt": { + "text": "Halaman ini di tempat sampah", + "restore": "Pulihkan halaman", + "deletePermanent": "Hapus secara permanen" + }, + "dialogCreatePageNameHint": "Nama halaman", + "questionBubble": { + "whatsNew": "Apa yang baru?", + "help": "Bantuan & Dukungan", + "debug": { + "name": "Info debug", + "success": "Info debug disalin ke papan klip!", + "fail": "Tidak dapat menyalin info debug ke papan klip" + } + }, + "menuAppHeader": { + "addPageTooltip": "Menambahkan halaman di dalam dengan cepat", + "defaultNewPageName": "Tanpa Judul", + "renameDialog": "Ganti nama" + }, + "toolbar": { + "undo": "Undo", + "redo": "Redo", + "bold": "Tebal", + "italic": "Miring", + "underline": "Garis bawah", + "strike": "Dicoret", + "numList": "Daftar bernomor", + "bulletList": "Daftar berpoin", + "checkList": "Daftar periksa", + "inlineCode": "Kode sebaris", + "quote": "Blok kutipan", + "header": "Tajuk", + "highlight": "Sorotan" + }, + "tooltip": { + "lightMode": "Ganti mode terang", + "darkMode": "Ganti mode gelap" + }, + "notifications": { + "export": { + "markdown": "Mengekspor Catatan ke Markdown", + "path": "Documents/flowy" + } + }, + "contactsPage": { + "title": "Kontak", + "whatsHappening": "Apa yang terjadi minggu ini?", + "addContact": "Tambahkan Kontak", + "editContact": "Ubah Kontak" + }, + "button": { + "OK": "Ya", + "Cancel": "Batal", + "signIn": "Masuk", + "signOut": "Keluar", + "complete": "Selesai", + "save": "Simpan" + }, + "label": { + "welcome": "Selamat datang!", + "firstName": "Nama Depan", + "middleName": "Nama Tengah", + "lastName": "Nama Akhir", + "stepX": "Langkah {X}" + }, + "oAuth": { + "err": { + "failedTitle": "Tidak dapat terhubung ke akun anda", + "failedMsg": "Mohon pastikan anda menyelesaikan proses pendaftaran pada browser anda." + }, + "google": { + "title": "MASUK GOOGLE", + "instruction1": "Untuk mengimpor kontak Google Contacts anda, anda harus mengizinkan aplikasi ini menggunakan browser web anda.", + "instruction2": "Salin kode ini ke papan klip anda dengan cara mengklik ikon atau memilih teks:", + "instruction3": "Arahkan ke tautan berikut di browser web Anda, dan masukkan kode di atas:", + "instruction4": "Tekan tombol di bawah ini setelah Anda menyelesaikan pendaftaran:" + } + }, + "settings": { + "title": "Pengaturan", + "menu": { + "appearance": "Tampilan", + "language": "Bahasa", + "user": "Pengguna", + "open": "Buka Pengaturan" + }, + "appearance": { + "lightLabel": "Mode Terang", + "darkLabel": "Mode Gelap" + } + }, + "grid": { + "settings": { + "filter": "Filter", + "sortBy": "Sortir dengan", + "Properties": "Properti" + }, + "field": { + "hide": "Sembunyikan", + "insertLeft": "Sisipkan Kiri", + "insertRight": "Sisipkan Kanan", + "duplicate": "Duplikasi", + "delete": "Hapus", + "textFieldName": "Teks", + "checkboxFieldName": "Kotak Centang", + "dateFieldName": "Tanggal", + "numberFieldName": "Angka", + "singleSelectFieldName": "seleksi", + "multiSelectFieldName": "Multi seleksi", + "urlFieldName": "URL", + "numberFormat": " Format angka", + "dateFormat": " Format tanggal", + "includeTime": " Sertakan waktu", + "dateFormatFriendly": "Bulan Hari,Tahun", + "dateFormatISO": "Tahun-Bulan-Hari", + "dateFormatLocal": "Tahun/Bulan/Hari", + "dateFormatUS": "Tahun/Bulan/Hari", + "timeFormat": " Format waktu", + "invalidTimeFormat": "Format yang tidak valid", + "timeFormatTwelveHour": "12 jam", + "timeFormatTwentyFourHour": "24 jam", + "addSelectOption": "Tambahkan opsi", + "optionTitle": "Opsi", + "addOption": "Tambahkan opsi", + "editProperty": "Ubah properti" + }, + "row": { + "duplicate": "Duplikasi", + "delete": "Hapus", + "textPlaceholder": "Kosong", + "copyProperty": "Salin properti ke papan klip" + }, + "selectOption": { + "create": "Buat", + "purpleColor": "Ungu", + "pinkColor": "Merah Jambu", + "lightPinkColor": "Merah Jambu Muda", + "orangeColor": "Oranye", + "yellowColor": "Kuning", + "limeColor": "Limau", + "greenColor": "Hijau", + "aquaColor": "Air", + "blueColor": "Biru", + "deleteTag": "Hapus tag", + "colorPannelTitle": "Warna", + "pannelTitle": "Pilih opsi atau buat baru", + "searchOption": "Cari opsi" + }, + "menuName": "Grid" + }, + "document": { + "menuName": "Doc", + "date": { + "timeHintTextInTwelveHour": "12:00 AM", + "timeHintTextInTwentyFourHour": "12:00" + } + } +} \ No newline at end of file From 492d35dd05674dc994e98cbb243d460b97b9a8c2 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 22 Jul 2022 14:47:15 +0100 Subject: [PATCH 058/112] feat: add spanish translations --- .../app_flowy/assets/translations/es-VE.json | 78 ++++++++++++++++++- 1 file changed, 75 insertions(+), 3 deletions(-) diff --git a/frontend/app_flowy/assets/translations/es-VE.json b/frontend/app_flowy/assets/translations/es-VE.json index 4aabe23674..d3740db8ec 100644 --- a/frontend/app_flowy/assets/translations/es-VE.json +++ b/frontend/app_flowy/assets/translations/es-VE.json @@ -96,6 +96,12 @@ "lightMode": "Cambiar a modo Claro", "darkMode": "Cambiar a modo Oscuro" }, + "notifications": { + "export": { + "markdown": "Nota exportada a Markdown", + "path": "Documentos/flowy" + } + }, "contactsPage": { "title": "Contactos", "whatsHappening": "¿Qué está pasando esta semana?", @@ -120,13 +126,13 @@ "oAuth": { "err": { "failedTitle": "Imposible conectarse con sus credenciales.", - "failedMsg": "Por favor asegurese haber completado el proceso de ingreso en su buscador." + "failedMsg": "Por favor asegurese haber completado el proceso de ingreso en su navegador." }, "google": { "title": "Ingresar con Google", - "instruction1": "Para importar sus contactos de Google, debe autorizar esta aplicación usando su buscador web.", + "instruction1": "Para importar sus contactos de Google, debe autorizar esta aplicación usando su navegador web.", "instruction2": "Copie este código al presionar el icono o al seleccionar el texto:", - "instruction3": "Navege al siguiente enlace en su buscador web, e ingrese el código anterior:", + "instruction3": "Navege al siguiente enlace en su navegador web, e ingrese el código anterior:", "instruction4": "Presione el botón de abajo cuando haya completado su registro:" } }, @@ -141,5 +147,71 @@ "lightLabel": "Modo Claro", "darkLabel": "Modo Oscuro" } + }, + "grid": { + "settings": { + "filter": "Filtrar", + "sortBy": "Ordenar por", + "Properties": "Propiedades" + }, + "field": { + "hide": "Ocultar", + "insertLeft": "Insertar a la Izquierda", + "insertRight": "Insertar a la Derecha", + "duplicate": "Duplicar", + "delete": "Eliminar", + "textFieldName": "Texto", + "checkboxFieldName": "Casilla de verificación", + "dateFieldName": "Fecha", + "numberFieldName": "Números", + "singleSelectFieldName": "Seleccionar", + "multiSelectFieldName": "Selección múltiple", + "urlFieldName": "URL", + "numberFormat": " Formato numérico", + "dateFormat": " Formato de fecha", + "includeTime": " Incluir tiempo", + "dateFormatFriendly": "Mes Día, Año", + "dateFormatISO": "Año-Mes-Día", + "dateFormatLocal": "Año/Mes/Día", + "dateFormatUS": "Año/Mes/Día", + "timeFormat": " Time format", + "invalidTimeFormat": "Formato de tiempo", + "timeFormatTwelveHour": "12 horas", + "timeFormatTwentyFourHour": "24 horas", + "addSelectOption": "Añadir una opción", + "optionTitle": "Opciones", + "addOption": "Añadir opción", + "editProperty": "Editar propiedad" + }, + "row": { + "duplicate": "Duplicar", + "delete": "Eliminar", + "textPlaceholder": "Vacío", + "copyProperty": "Propiedad copiada al portapapeles" + }, + "selectOption": { + "create": "Crear", + "purpleColor": "Morado", + "pinkColor": "Rosa", + "lightPinkColor": "Rosa Claro", + "orangeColor": "Naranja", + "yellowColor": "Amarillo", + "limeColor": "Lima", + "greenColor": "Verde", + "aquaColor": "Agua", + "blueColor": "Azul", + "deleteTag": "Borrar etiqueta", + "colorPannelTitle": "Colores", + "pannelTitle": "Selecciona una opción o crea una", + "searchOption": "Buscar una opción" + }, + "menuName": "Grid" + }, + "document": { + "menuName": "Doc", + "date": { + "timeHintTextInTwelveHour": "12:00 AM", + "timeHintTextInTwentyFourHour": "12:00" + } } } From ed26ffe39369d02797f5f46cec2c829606af720e Mon Sep 17 00:00:00 2001 From: SiderealArt Date: Sat, 23 Jul 2022 10:22:51 +0800 Subject: [PATCH 059/112] feat: add zh-TW translation --- .../app_flowy/assets/translations/zh-TW.json | 218 ++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 frontend/app_flowy/assets/translations/zh-TW.json diff --git a/frontend/app_flowy/assets/translations/zh-TW.json b/frontend/app_flowy/assets/translations/zh-TW.json new file mode 100644 index 0000000000..1971d4f33c --- /dev/null +++ b/frontend/app_flowy/assets/translations/zh-TW.json @@ -0,0 +1,218 @@ +{ + "appName": "AppFlowy", + "defaultUsername": "我", + "welcomeText": "歡迎使用 @:appName", + "githubStarText": "在 GitHub 點星", + "subscribeNewsletterText": "訂閱電子報", + "letsGoButtonText": "出發吧", + "title": "標題", + "signUp": { + "buttonText": "註冊", + "title": "註冊 @:appName", + "getStartedText": "Get Started", + "emptyPasswordError": "密碼不能為空", + "repeatPasswordEmptyError": "確認密碼不能為空", + "unmatchedPasswordError": "確認密碼與密碼不符", + "alreadyHaveAnAccount": "已經有帳號了嗎?", + "emailHint": "電子郵件地址", + "passwordHint": "密碼", + "repeatPasswordHint": "確認密碼" + }, + "signIn": { + "loginTitle": "登入 @:appName", + "loginButtonText": "登入", + "buttonText": "登入", + "forgotPassword": "忘記密碼?", + "emailHint": "電子郵件地址", + "passwordHint": "密碼", + "dontHaveAnAccount": "沒有帳號?", + "repeatPasswordEmptyError": "確認密碼不能為空", + "unmatchedPasswordError": "確認密碼與密碼不符" + }, + "workspace": { + "create": "建立工作區", + "hint": "工作區", + "notFoundError": "找不到工作區" + }, + "shareAction": { + "buttonText": "分享", + "workInProgress": "即將推出", + "markdown": "Markdown", + "copyLink": "複製連結" + }, + "disclosureAction": { + "rename": "重新命名", + "delete": "刪除", + "duplicate": "複製" + }, + "blankPageTitle": "空白頁面", + "newPageText": "新頁面", + "trash": { + "text": "垃圾筒", + "restoreAll": "全部復原", + "deleteAll": "全部刪除", + "pageHeader": { + "fileName": "檔案名稱", + "lastModified": "最後修改時間", + "created": "建立時間" + } + }, + "deletePagePrompt": { + "text": "此頁面在垃圾筒中", + "restore": "復原頁面", + "deletePermanent": "永久刪除" + }, + "dialogCreatePageNameHint": "頁面名稱", + "questionBubble": { + "whatsNew": "新功能", + "help": "幫助 & 支援", + "debug": { + "name": "除錯資訊", + "success": "已將除錯資訊複製至剪貼簿!", + "fail": "無法將除錯資訊複製至剪貼簿" + } + }, + "menuAppHeader": { + "addPageTooltip": "快速新增頁面", + "defaultNewPageName": "未命名", + "renameDialog": "重新命名" + }, + "toolbar": { + "undo": "復原", + "redo": "取消復原", + "bold": "粗體", + "italic": "斜體", + "underline": "底線", + "strike": "刪除線", + "numList": "有序清單", + "bulletList": "無序清單", + "checkList": "核取清單", + "inlineCode": "程式碼", + "quote": "區塊引言", + "header": "標題", + "highlight": "反白" + }, + "tooltip": { + "lightMode": "切換至亮色模式", + "darkMode": "切換至暗色模式" + }, + "notifications": { + "export": { + "markdown": "已將筆記匯出成 Markdown", + "path": "Documents/flowy" + } + }, + "contactsPage": { + "title": "聯絡人", + "whatsHappening": "這周有甚麼新鮮事?", + "addContact": "新增聯絡人", + "editContact": "編輯聯絡人" + }, + "button": { + "OK": "OK", + "Cancel": "取消", + "signIn": "登入", + "signOut": "登出", + "complete": "完成", + "save": "儲存" + }, + "label": { + "welcome": "歡迎!", + "firstName": "名", + "middleName": "中間名", + "lastName": "姓", + "stepX": "步驟 {X}" + }, + "oAuth": { + "err": { + "failedTitle": "無法連接至您的帳號。", + "failedMsg": "請確認您已在瀏覽器中完成登入程序:" + }, + "google": { + "title": "GOOGLE 登入", + "instruction1": "若要匯入您的 Google 聯絡人,您必須透過瀏覽器授權此應用程式:", + "instruction2": "點擊圖示或選取文字以複製代碼:", + "instruction3": "前往下列網址,並輸入上述代碼:", + "instruction4": "完成註冊後,請點擊下方按鈕:" + } + }, + "settings": { + "title": "設定", + "menu": { + "appearance": "外觀", + "language": "語言", + "user": "使用者", + "open": "開啟設定" + }, + "appearance": { + "lightLabel": "亮色模式", + "darkLabel": "暗色模式" + } + }, + "grid": { + "settings": { + "filter": "篩選", + "sortBy": "排序方式", + "Properties": "內容" + }, + "field": { + "hide": "隱藏", + "insertLeft": "插入左方欄", + "insertRight": "插入右方欄", + "duplicate": "複製", + "delete": "刪除", + "textFieldName": "文字", + "checkboxFieldName": "核取方塊", + "dateFieldName": "日期", + "numberFieldName": "數字", + "singleSelectFieldName": "單選", + "multiSelectFieldName": "多選", + "urlFieldName": "網址", + "numberFormat": " 數字格式", + "dateFormat": " 日期格式", + "includeTime": " 包含時間", + "dateFormatFriendly": "月 日,年", + "dateFormatISO": "年-月-日", + "dateFormatLocal": "年/月/日", + "dateFormatUS": "年/月/日", + "timeFormat": " 時間格式", + "invalidTimeFormat": "格式無效", + "timeFormatTwelveHour": "12 小時", + "timeFormatTwentyFourHour": "24 小時", + "addSelectOption": "新增選項", + "optionTitle": "選項", + "addOption": "新增選項", + "editProperty": "編輯內容" + }, + "row": { + "duplicate": "複製", + "delete": "刪除", + "textPlaceholder": "空", + "copyProperty": "已將內容複製至剪貼簿" + }, + "selectOption": { + "create": "建立", + "purpleColor": "紫色", + "pinkColor": "粉色", + "lightPinkColor": "淡粉色", + "orangeColor": "橘色", + "yellowColor": "黃色", + "limeColor": "萊姆色", + "greenColor": "綠色", + "aquaColor": "水藍色", + "blueColor": "藍色", + "deleteTag": "刪除標籤", + "colorPannelTitle": "顏色", + "pannelTitle": "搜尋或建立選項", + "searchOption": "搜尋選項" + }, + "menuName": "網格" + }, + "document": { + "menuName": "檔案", + "date": { + "timeHintTextInTwelveHour": "12:00 AM", + "timeHintTextInTwentyFourHour": "12:00" + } + } +} \ No newline at end of file From 3fde59836e349db47b450caf7f24f41eab0d98df Mon Sep 17 00:00:00 2001 From: SiderealArt Date: Sat, 23 Jul 2022 04:35:53 +0000 Subject: [PATCH 060/112] feat: add zh-tw translation --- frontend/app_flowy/assets/translations/zh-TW.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app_flowy/assets/translations/zh-TW.json b/frontend/app_flowy/assets/translations/zh-TW.json index 1971d4f33c..9f72b90512 100644 --- a/frontend/app_flowy/assets/translations/zh-TW.json +++ b/frontend/app_flowy/assets/translations/zh-TW.json @@ -9,7 +9,7 @@ "signUp": { "buttonText": "註冊", "title": "註冊 @:appName", - "getStartedText": "Get Started", + "getStartedText": "開始使用", "emptyPasswordError": "密碼不能為空", "repeatPasswordEmptyError": "確認密碼不能為空", "unmatchedPasswordError": "確認密碼與密碼不符", From f5268178c4e888a2fbc81f25e885dc242bfd451b Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 23 Jul 2022 16:57:28 +0800 Subject: [PATCH 061/112] chore: add documentation in grid uint test --- .../checkbox_type_option/checkbox_tests.rs | 50 ++-- .../checkbox_type_option_entities.rs | 10 +- .../date_type_option/date_tests.rs | 241 +++++------------- .../number_type_option/number_tests.rs | 71 +++--- .../type_options/url_type_option/url_tests.rs | 38 +-- .../tests/grid/block_test/row_test.rs | 4 +- 6 files changed, 158 insertions(+), 256 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs index 1a60a0a5a8..b9d155da7d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs @@ -1,30 +1,44 @@ #[cfg(test)] mod tests { - use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data}; - use crate::services::field::type_options::checkbox_type_option::{NO, YES}; - use crate::services::field::FieldBuilder; - use crate::entities::FieldType; + use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellDataOperation}; + use crate::services::field::type_options::checkbox_type_option::*; + use crate::services::field::FieldBuilder; + use flowy_grid_data_model::revision::FieldRevision; #[test] fn checkout_box_description_test() { - let field_rev = FieldBuilder::from_field_type(&FieldType::Checkbox).build(); - let data = apply_cell_data_changeset("true", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev).to_string(), YES); + let type_option = CheckboxTypeOption::default(); + let field_type = FieldType::Checkbox; + let field_rev = FieldBuilder::from_field_type(&field_type).build(); - let data = apply_cell_data_changeset("1", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES); + // the checkout value will be checked if the value is "1", "true" or "yes" + assert_checkbox(&type_option, "1", CHECK, &field_type, &field_rev); + assert_checkbox(&type_option, "true", CHECK, &field_type, &field_rev); + assert_checkbox(&type_option, "yes", CHECK, &field_type, &field_rev); - let data = apply_cell_data_changeset("yes", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), YES); + // the checkout value will be uncheck if the value is "false" or "No" + assert_checkbox(&type_option, "false", UNCHECK, &field_type, &field_rev); + assert_checkbox(&type_option, "No", UNCHECK, &field_type, &field_rev); - let data = apply_cell_data_changeset("false", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); + // the checkout value will be empty if the value is letters or empty string + assert_checkbox(&type_option, "abc", "", &field_type, &field_rev); + assert_checkbox(&type_option, "", "", &field_type, &field_rev); + } - let data = apply_cell_data_changeset("no", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), NO); - - let data = apply_cell_data_changeset("12", None, &field_rev).unwrap(); - assert_eq!(decode_any_cell_data(data, &field_rev,).to_string(), ""); + fn assert_checkbox( + type_option: &CheckboxTypeOption, + input_str: &str, + expected_str: &str, + field_type: &FieldType, + field_rev: &FieldRevision, + ) { + assert_eq!( + type_option + .decode_cell_data(input_str.to_owned().into(), field_type, field_rev) + .unwrap() + .to_string(), + expected_str.to_owned() + ); } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs index 233c481eb6..3da9ebd23f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_type_option_entities.rs @@ -3,14 +3,14 @@ use bytes::Bytes; use flowy_error::{FlowyError, FlowyResult}; use std::str::FromStr; -pub const YES: &str = "Yes"; -pub const NO: &str = "No"; +pub const CHECK: &str = "Yes"; +pub const UNCHECK: &str = "No"; pub struct CheckboxCellData(String); impl CheckboxCellData { pub fn is_check(&self) -> bool { - self.0 == YES + self.0 == CHECK } } @@ -36,8 +36,8 @@ impl FromStr for CheckboxCellData { }; match val { - Some(true) => Ok(Self(YES.to_string())), - Some(false) => Ok(Self(NO.to_string())), + Some(true) => Ok(Self(CHECK.to_string())), + Some(false) => Ok(Self(UNCHECK.to_string())), None => Ok(Self("".to_string())), } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs index 5bb2b1c415..74b6ee6fd8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs @@ -7,23 +7,6 @@ mod tests { use flowy_grid_data_model::revision::FieldRevision; use strum::IntoEnumIterator; - #[test] - fn date_type_option_invalid_input_test() { - let type_option = DateTypeOption::default(); - let field_type = FieldType::DateTime; - let field_rev = FieldBuilder::from_field_type(&field_type).build(); - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some("1e".to_string()), - time: Some("23:00".to_owned()), - }, - &field_type, - &field_rev, - "", - ); - } - #[test] fn date_type_option_date_format_test() { let mut type_option = DateTypeOption::default(); @@ -32,23 +15,23 @@ mod tests { type_option.date_format = date_format; match date_format { DateFormat::Friendly => { - assert_decode_timestamp(1647251762, &type_option, &field_rev, "Mar 14,2022"); + assert_date(&type_option, 1647251762, None, "Mar 14,2022", &field_rev); } DateFormat::US => { - assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022/03/14"); + assert_date(&type_option, 1647251762, None, "2022/03/14", &field_rev); } DateFormat::ISO => { - assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022-03-14"); + assert_date(&type_option, 1647251762, None, "2022-03-14", &field_rev); } DateFormat::Local => { - assert_decode_timestamp(1647251762, &type_option, &field_rev, "2022/03/14"); + assert_date(&type_option, 1647251762, None, "2022/03/14", &field_rev); } } } } #[test] - fn date_type_option_time_format_test() { + fn date_type_option_different_time_format_test() { let mut type_option = DateTypeOption::default(); let field_type = FieldType::DateTime; let field_rev = FieldBuilder::from_field_type(&field_type).build(); @@ -58,59 +41,23 @@ mod tests { type_option.include_time = true; match time_format { TimeFormat::TwentyFourHour => { - assert_changeset_result( + assert_date(&type_option, 1653609600, None, "May 27,2022", &field_rev); + assert_date( &type_option, - DateCellChangesetPB { - date: Some(1653609600.to_string()), - time: None, - }, - &field_type, - &field_rev, - "May 27,2022", - ); - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(1653609600.to_string()), - time: Some("23:00".to_owned()), - }, - &field_type, - &field_rev, + 1653609600, + Some("23:00".to_owned()), "May 27,2022 23:00", + &field_rev, ); } TimeFormat::TwelveHour => { - assert_changeset_result( + assert_date(&type_option, 1653609600, None, "May 27,2022", &field_rev); + assert_date( &type_option, - DateCellChangesetPB { - date: Some(1653609600.to_string()), - time: None, - }, - &field_type, - &field_rev, - "May 27,2022", - ); - // - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(1653609600.to_string()), - time: Some("".to_owned()), - }, - &field_type, - &field_rev, - "May 27,2022", - ); - - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(1653609600.to_string()), - time: Some("11:23 pm".to_owned()), - }, - &field_type, - &field_rev, + 1653609600, + Some("11:23 pm".to_owned()), "May 27,2022 11:23 PM", + &field_rev, ); } } @@ -118,141 +65,71 @@ mod tests { } #[test] - fn date_type_option_apply_changeset_test() { - let mut type_option = DateTypeOption::new(); + fn date_type_option_invalid_date_str_test() { + let type_option = DateTypeOption::default(); let field_type = FieldType::DateTime; let field_rev = FieldBuilder::from_field_type(&field_type).build(); - let date_timestamp = "1653609600".to_owned(); - - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(date_timestamp.clone()), - time: None, - }, - &field_type, - &field_rev, - "May 27,2022", - ); + assert_date(&type_option, "abc", None, "", &field_rev); + } + #[test] + #[should_panic] + fn date_type_option_invalid_include_time_str_test() { + let mut type_option = DateTypeOption::new(); type_option.include_time = true; - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(date_timestamp.clone()), - time: None, - }, - &field_type, - &field_rev, - "May 27,2022", - ); + let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); - assert_changeset_result( + assert_date( &type_option, - DateCellChangesetPB { - date: Some(date_timestamp.clone()), - time: Some("1:00".to_owned()), - }, - &field_type, - &field_rev, + 1653609600, + Some("1:".to_owned()), "May 27,2022 01:00", - ); - - type_option.time_format = TimeFormat::TwelveHour; - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(date_timestamp), - time: Some("1:00 am".to_owned()), - }, - &field_type, &field_rev, + ); + } + + #[test] + fn date_type_option_empty_include_time_str_test() { + let mut type_option = DateTypeOption::new(); + type_option.include_time = true; + let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); + + assert_date(&type_option, 1653609600, Some("".to_owned()), "May 27,2022", &field_rev); + } + + /// The default time format is TwentyFourHour, so the include_time_str in twelve_hours_format will cause parser error. + #[test] + #[should_panic] + fn date_type_option_twelve_hours_include_time_str_in_twenty_four_hours_format() { + let mut type_option = DateTypeOption::new(); + type_option.include_time = true; + let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); + + assert_date( + &type_option, + 1653609600, + Some("1:00 am".to_owned()), "May 27,2022 01:00 AM", + &field_rev, ); } - - #[test] - #[should_panic] - fn date_type_option_apply_changeset_error_test() { - let mut type_option = DateTypeOption::new(); - type_option.include_time = true; - let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); - let date_timestamp = "1653609600".to_owned(); - - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(date_timestamp.clone()), - time: Some("1:".to_owned()), - }, - &FieldType::DateTime, - &field_rev, - "May 27,2022 01:00", - ); - - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(date_timestamp), - time: Some("1:00".to_owned()), - }, - &FieldType::DateTime, - &field_rev, - "May 27,2022 01:00", - ); - } - - #[test] - #[should_panic] - fn date_type_option_twelve_hours_to_twenty_four_hours() { - let mut type_option = DateTypeOption::new(); - type_option.include_time = true; - let field_rev = FieldBuilder::from_field_type(&FieldType::DateTime).build(); - let date_timestamp = "1653609600".to_owned(); - - assert_changeset_result( - &type_option, - DateCellChangesetPB { - date: Some(date_timestamp), - time: Some("1:00 am".to_owned()), - }, - &FieldType::DateTime, - &field_rev, - "May 27,2022 01:00", - ); - } - - fn assert_changeset_result( + fn assert_date( type_option: &DateTypeOption, - changeset: DateCellChangesetPB, - _field_type: &FieldType, + timestamp: T, + include_time_str: Option, + expected_str: &str, field_rev: &FieldRevision, - expected: &str, - ) { - let changeset = CellDataChangeset(Some(changeset)); - let encoded_data = type_option.apply_changeset(changeset, None).unwrap(); - assert_eq!( - expected.to_owned(), - decode_cell_data(encoded_data, type_option, field_rev) - ); - } - - fn assert_decode_timestamp( - timestamp: i64, - type_option: &DateTypeOption, - field_rev: &FieldRevision, - expected: &str, ) { let s = serde_json::to_string(&DateCellChangesetPB { date: Some(timestamp.to_string()), - time: None, + time: include_time_str, }) .unwrap(); let encoded_data = type_option.apply_changeset(s.into(), None).unwrap(); assert_eq!( - expected.to_owned(), - decode_cell_data(encoded_data, type_option, field_rev) + decode_cell_data(encoded_data, type_option, field_rev), + expected_str.to_owned(), ); } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs index 6ea1e8f302..41132ecfe4 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option/number_tests.rs @@ -7,25 +7,30 @@ mod tests { use flowy_grid_data_model::revision::FieldRevision; use strum::IntoEnumIterator; + /// Testing when the input is not a number. #[test] fn number_type_option_invalid_input_test() { let type_option = NumberTypeOption::default(); let field_type = FieldType::Number; let field_rev = FieldBuilder::from_field_type(&field_type).build(); - assert_equal(&type_option, "", "", &field_type, &field_rev); - assert_equal(&type_option, "abc", "", &field_type, &field_rev); + + // Input is empty String + assert_number(&type_option, "", "", &field_type, &field_rev); + + // Input is letter + assert_number(&type_option, "abc", "", &field_type, &field_rev); } + /// Testing the strip_currency_symbol function. It should return the string without the input symbol. #[test] fn number_type_option_strip_symbol_test() { - let mut type_option = NumberTypeOption::new(); - type_option.format = NumberFormat::USD; + // Remove the $ symbol assert_eq!(strip_currency_symbol("$18,443"), "18,443".to_owned()); - - type_option.format = NumberFormat::Yuan; - assert_eq!(strip_currency_symbol("$0.2"), "0.2".to_owned()); + // Remove the ¥ symbol + assert_eq!(strip_currency_symbol("¥0.2"), "0.2".to_owned()); } + /// Format the input number to the corresponding format string. #[test] fn number_type_option_format_number_test() { let mut type_option = NumberTypeOption::default(); @@ -36,25 +41,26 @@ mod tests { type_option.format = format; match format { NumberFormat::Num => { - assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); + assert_number(&type_option, "18443", "18443", &field_type, &field_rev); } NumberFormat::USD => { - assert_equal(&type_option, "18443", "$18,443", &field_type, &field_rev); + assert_number(&type_option, "18443", "$18,443", &field_type, &field_rev); } NumberFormat::Yen => { - assert_equal(&type_option, "18443", "¥18,443", &field_type, &field_rev); + assert_number(&type_option, "18443", "¥18,443", &field_type, &field_rev); } NumberFormat::Yuan => { - assert_equal(&type_option, "18443", "CN¥18,443", &field_type, &field_rev); + assert_number(&type_option, "18443", "CN¥18,443", &field_type, &field_rev); } NumberFormat::EUR => { - assert_equal(&type_option, "18443", "€18.443", &field_type, &field_rev); + assert_number(&type_option, "18443", "€18.443", &field_type, &field_rev); } _ => {} } } } + /// Format the input String to the corresponding format string. #[test] fn number_type_option_format_str_test() { let mut type_option = NumberTypeOption::default(); @@ -65,33 +71,34 @@ mod tests { type_option.format = format; match format { NumberFormat::Num => { - assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); - assert_equal(&type_option, "0.2", "0.2", &field_type, &field_rev); + assert_number(&type_option, "18443", "18443", &field_type, &field_rev); + assert_number(&type_option, "0.2", "0.2", &field_type, &field_rev); } NumberFormat::USD => { - assert_equal(&type_option, "$18,44", "$1,844", &field_type, &field_rev); - assert_equal(&type_option, "$0.2", "$0.2", &field_type, &field_rev); - assert_equal(&type_option, "", "", &field_type, &field_rev); - assert_equal(&type_option, "abc", "", &field_type, &field_rev); + assert_number(&type_option, "$18,44", "$1,844", &field_type, &field_rev); + assert_number(&type_option, "$0.2", "$0.2", &field_type, &field_rev); + assert_number(&type_option, "", "", &field_type, &field_rev); + assert_number(&type_option, "abc", "", &field_type, &field_rev); } NumberFormat::Yen => { - assert_equal(&type_option, "¥18,44", "¥1,844", &field_type, &field_rev); - assert_equal(&type_option, "¥1844", "¥1,844", &field_type, &field_rev); + assert_number(&type_option, "¥18,44", "¥1,844", &field_type, &field_rev); + assert_number(&type_option, "¥1844", "¥1,844", &field_type, &field_rev); } NumberFormat::Yuan => { - assert_equal(&type_option, "CN¥18,44", "CN¥1,844", &field_type, &field_rev); - assert_equal(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field_rev); + assert_number(&type_option, "CN¥18,44", "CN¥1,844", &field_type, &field_rev); + assert_number(&type_option, "CN¥1844", "CN¥1,844", &field_type, &field_rev); } NumberFormat::EUR => { - assert_equal(&type_option, "€18.44", "€18,44", &field_type, &field_rev); - assert_equal(&type_option, "€0.5", "€0,5", &field_type, &field_rev); - assert_equal(&type_option, "€1844", "€1.844", &field_type, &field_rev); + assert_number(&type_option, "€18.44", "€18,44", &field_type, &field_rev); + assert_number(&type_option, "€0.5", "€0,5", &field_type, &field_rev); + assert_number(&type_option, "€1844", "€1.844", &field_type, &field_rev); } _ => {} } } } + /// Carry out the sign positive to input number #[test] fn number_description_sign_test() { let mut type_option = NumberTypeOption { @@ -105,32 +112,32 @@ mod tests { type_option.format = format; match format { NumberFormat::Num => { - assert_equal(&type_option, "18443", "18443", &field_type, &field_rev); + assert_number(&type_option, "18443", "18443", &field_type, &field_rev); } NumberFormat::USD => { - assert_equal(&type_option, "18443", "-$18,443", &field_type, &field_rev); + assert_number(&type_option, "18443", "-$18,443", &field_type, &field_rev); } NumberFormat::Yen => { - assert_equal(&type_option, "18443", "-¥18,443", &field_type, &field_rev); + assert_number(&type_option, "18443", "-¥18,443", &field_type, &field_rev); } NumberFormat::EUR => { - assert_equal(&type_option, "18443", "-€18.443", &field_type, &field_rev); + assert_number(&type_option, "18443", "-€18.443", &field_type, &field_rev); } _ => {} } } } - fn assert_equal( + fn assert_number( type_option: &NumberTypeOption, - cell_data: &str, + input_str: &str, expected_str: &str, field_type: &FieldType, field_rev: &FieldRevision, ) { assert_eq!( type_option - .decode_cell_data(cell_data.to_owned().into(), field_type, field_rev) + .decode_cell_data(input_str.to_owned().into(), field_type, field_rev) .unwrap() .to_string(), expected_str.to_owned() diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs index 77f4ea767e..ba221853bb 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/url_type_option/url_tests.rs @@ -6,49 +6,53 @@ mod tests { use crate::services::field::{URLCellDataPB, URLTypeOption}; use flowy_grid_data_model::revision::FieldRevision; + /// The expected_str will equal to the input string, but the expected_url will be empty if there's no + /// http url in the input string. #[test] - fn url_type_option_test_no_url() { + fn url_type_option_does_not_contain_url_test() { let type_option = URLTypeOption::default(); let field_type = FieldType::URL; let field_rev = FieldBuilder::from_field_type(&field_type).build(); - assert_changeset(&type_option, "123", &field_type, &field_rev, "123", ""); + assert_url(&type_option, "123", "123", "", &field_type, &field_rev); } + /// The expected_str will equal to the input string, but the expected_url will not be empty + /// if there's a http url in the input string. #[test] - fn url_type_option_test_contains_url() { + fn url_type_option_contains_url_test() { let type_option = URLTypeOption::default(); let field_type = FieldType::URL; let field_rev = FieldBuilder::from_field_type(&field_type).build(); - assert_changeset( + assert_url( &type_option, "AppFlowy website - https://www.appflowy.io", - &field_type, - &field_rev, "AppFlowy website - https://www.appflowy.io", "https://www.appflowy.io/", - ); - - assert_changeset( - &type_option, - "AppFlowy website appflowy.io", &field_type, &field_rev, + ); + + assert_url( + &type_option, + "AppFlowy website appflowy.io", "AppFlowy website appflowy.io", "https://appflowy.io", + &field_type, + &field_rev, ); } - fn assert_changeset( + fn assert_url( type_option: &URLTypeOption, - cell_data: &str, + input_str: &str, + expected_str: &str, + expected_url: &str, field_type: &FieldType, field_rev: &FieldRevision, - expected: &str, - expected_url: &str, ) { - let encoded_data = type_option.apply_changeset(cell_data.to_owned().into(), None).unwrap(); + let encoded_data = type_option.apply_changeset(input_str.to_owned().into(), None).unwrap(); let decode_cell_data = decode_cell_data(encoded_data, type_option, field_rev, field_type); - assert_eq!(expected.to_owned(), decode_cell_data.content); + assert_eq!(expected_str.to_owned(), decode_cell_data.content); assert_eq!(expected_url.to_owned(), decode_cell_data.url); } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs index 7b64a44b48..85bfed576d 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/row_test.rs @@ -2,7 +2,7 @@ use crate::grid::block_test::script::RowScript::*; use crate::grid::block_test::script::{CreateRowScriptBuilder, GridRowTest}; use crate::grid::grid_editor::{COMPLETED, FACEBOOK, GOOGLE, PAUSED, TWITTER}; use flowy_grid::entities::FieldType; -use flowy_grid::services::field::{NO, SELECTION_IDS_SEPARATOR}; +use flowy_grid::services::field::{SELECTION_IDS_SEPARATOR, UNCHECK}; use flowy_grid_data_model::revision::RowMetaChangeset; #[tokio::test] @@ -72,7 +72,7 @@ async fn grid_row_add_cells_test() { builder.insert(FieldType::RichText, "hello world", "hello world"); builder.insert(FieldType::DateTime, "1647251762", "2022/03/14"); builder.insert(FieldType::Number, "18,443", "$18,443.00"); - builder.insert(FieldType::Checkbox, "false", NO); + builder.insert(FieldType::Checkbox, "false", UNCHECK); builder.insert(FieldType::URL, "https://appflowy.io", "https://appflowy.io"); builder.insert_single_select_cell(|mut options| options.remove(0), COMPLETED); builder.insert_multi_select_cell( From 59b511c52ce6ed4e894d2aea281d1e79137e348c Mon Sep 17 00:00:00 2001 From: sunny7dusk Date: Sat, 23 Jul 2022 13:15:34 -0400 Subject: [PATCH 062/112] feat: Initial implementation of updated language selector ui based on figma --- .../widgets/settings_language_view.dart | 101 ++++++++++++++---- 1 file changed, 82 insertions(+), 19 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_language_view.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_language_view.dart index 5617750a77..e95e6e83ab 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_language_view.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_language_view.dart @@ -1,18 +1,37 @@ +import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/theme.dart'; import 'package:flutter/material.dart'; import 'package:flowy_infra/language.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:provider/provider.dart'; class SettingsLanguageView extends StatelessWidget { const SettingsLanguageView({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: const [LanguageSelectorDropdown()], + context.watch(); + return ChangeNotifierProvider.value( + value: Provider.of(context, listen: true), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + LocaleKeys.settings_menu_language.tr(), + style: const TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + ), + ), + const LanguageSelectorDropdown(), + ], + ), + ], + ), ), ); } @@ -28,22 +47,66 @@ class LanguageSelectorDropdown extends StatefulWidget { } class _LanguageSelectorDropdownState extends State { + Color currHoverColor = Colors.white.withOpacity(0.0); + late Color themedHoverColor; + void hoverExitLanguage() { + setState(() { + currHoverColor = Colors.white.withOpacity(0.0); + }); + } + + void hoverEnterLanguage() { + setState(() { + currHoverColor = themedHoverColor; + }); + } + @override Widget build(BuildContext context) { - return DropdownButton( - value: context.read().locale, - onChanged: (val) { - setState(() { - context.read().setLocale(context, val!); - }); - }, - autofocus: true, - items: EasyLocalization.of(context)!.supportedLocales.map((locale) { - return DropdownMenuItem( - value: locale, - child: Text(languageFromLocale(locale)), - ); - }).toList(), + final theme = context.watch(); + themedHoverColor = theme.main2; + + return MouseRegion( + onEnter: (event) => {hoverEnterLanguage()}, + onExit: (event) => {hoverExitLanguage()}, + child: Container( + margin: const EdgeInsets.only(left: 8, right: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: currHoverColor, + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: context.read().locale, + onChanged: (val) { + setState(() { + context.read().setLocale(context, val!); + }); + }, + icon: const Visibility( + child: (Icon(Icons.arrow_downward)), + visible: false, + ), + borderRadius: BorderRadius.circular(8), + items: EasyLocalization.of(context)!.supportedLocales.map((locale) { + return DropdownMenuItem( + value: locale, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Text( + languageFromLocale(locale), + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w500, + color: theme.textColor, + ), + ), + ), + ); + }).toList(), + ), + ), + ), ); } } From 3c5b9e6b5009aeaa6019e720fb05b1e7627b19a0 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 24 Jul 2022 17:31:03 +0800 Subject: [PATCH 063/112] chore: add documentation for lib-ot crate --- .../checkbox_type_option/checkbox_tests.rs | 2 +- .../date_type_option/date_tests.rs | 2 +- .../flowy-text-block/tests/editor/op_test.rs | 235 ++++++++++-------- .../tests/editor/serde_test.rs | 6 +- .../tests/editor/undo_redo_test.rs | 1 + .../delete/preserve_line_format_merge.rs | 4 +- .../extensions/format/resolve_block_format.rs | 4 +- .../format/resolve_inline_format.rs | 4 +- .../extensions/insert/auto_exit_block.rs | 8 +- .../extensions/insert/auto_format.rs | 4 +- .../extensions/insert/default_insert.rs | 4 +- .../insert/preserve_block_format.rs | 4 +- .../insert/preserve_inline_format.rs | 6 +- .../insert/reset_format_on_new_line.rs | 4 +- shared-lib/lib-ot/src/core/delta/builder.rs | 13 +- shared-lib/lib-ot/src/core/delta/cursor.rs | 121 +++++---- shared-lib/lib-ot/src/core/delta/delta.rs | 160 ++++++++---- .../lib-ot/src/core/delta/delta_serde.rs | 3 +- shared-lib/lib-ot/src/core/delta/iterator.rs | 34 +-- shared-lib/lib-ot/src/core/flowy_str.rs | 5 +- shared-lib/lib-ot/src/core/interval.rs | 2 +- shared-lib/lib-ot/src/core/mod.rs | 21 -- .../lib-ot/src/core/operation/builder.rs | 32 ++- .../lib-ot/src/core/operation/operation.rs | 115 ++++++--- .../src/core/operation/operation_serde.rs | 3 +- shared-lib/lib-ot/src/rich_text/attributes.rs | 8 +- shared-lib/lib-ot/src/rich_text/delta.rs | 6 +- 27 files changed, 493 insertions(+), 318 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs index b9d155da7d..ddd1ba049d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::entities::FieldType; - use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellDataOperation}; + use crate::services::cell::CellDataOperation; use crate::services::field::type_options::checkbox_type_option::*; use crate::services::field::FieldBuilder; use flowy_grid_data_model::revision::FieldRevision; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs index 74b6ee6fd8..1229a8f5e1 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::entities::FieldType; - use crate::services::cell::{CellDataChangeset, CellDataOperation}; + use crate::services::cell::CellDataOperation; use crate::services::field::*; // use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; use flowy_grid_data_model::revision::FieldRevision; diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index 3f174fa3bc..47d3c5ebfe 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -2,6 +2,7 @@ use crate::editor::{Rng, TestBuilder, TestOp::*}; use flowy_sync::client_document::{NewlineDoc, PlainDoc}; use lib_ot::{ + core::Interval, core::*, rich_text::{AttributeBuilder, RichTextAttribute, RichTextAttributes, RichTextDelta}, }; @@ -39,23 +40,23 @@ fn attributes_insert_text_at_middle() { #[test] fn delta_get_ops_in_interval_1() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("123").build(); - let insert_b = OpBuilder::insert("4").build(); + let insert_a = OperationBuilder::insert("123").build(); + let insert_b = OperationBuilder::insert("4").build(); delta.add(insert_a.clone()); delta.add(insert_b.clone()); - let mut iterator = DeltaIter::from_interval(&delta, Interval::new(0, 4)); + let mut iterator = DeltaIterator::from_interval(&delta, Interval::new(0, 4)); assert_eq!(iterator.ops(), delta.ops); } #[test] fn delta_get_ops_in_interval_2() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("123").build(); - let insert_b = OpBuilder::insert("4").build(); - let insert_c = OpBuilder::insert("5").build(); - let retain_a = OpBuilder::retain(3).build(); + let insert_a = OperationBuilder::insert("123").build(); + let insert_b = OperationBuilder::insert("4").build(); + let insert_c = OperationBuilder::insert("5").build(); + let retain_a = OperationBuilder::retain(3).build(); delta.add(insert_a.clone()); delta.add(retain_a.clone()); @@ -63,32 +64,32 @@ fn delta_get_ops_in_interval_2() { delta.add(insert_c.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 2)).ops(), - vec![OpBuilder::insert("12").build()] + DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), + vec![OperationBuilder::insert("12").build()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(1, 3)).ops(), - vec![OpBuilder::insert("23").build()] + DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(), + vec![OperationBuilder::insert("23").build()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 3)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), vec![insert_a.clone()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 4)).ops(), - vec![insert_a.clone(), OpBuilder::retain(1).build()] + DeltaIterator::from_interval(&delta, Interval::new(0, 4)).ops(), + vec![insert_a.clone(), OperationBuilder::retain(1).build()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 6)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(0, 6)).ops(), vec![insert_a.clone(), retain_a.clone()] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 7)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(0, 7)).ops(), vec![insert_a.clone(), retain_a.clone(), insert_b.clone()] ); } @@ -96,54 +97,60 @@ fn delta_get_ops_in_interval_2() { #[test] fn delta_get_ops_in_interval_3() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("123456").build(); + let insert_a = OperationBuilder::insert("123456").build(); delta.add(insert_a.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(3, 5)).ops(), - vec![OpBuilder::insert("45").build()] + DeltaIterator::from_interval(&delta, Interval::new(3, 5)).ops(), + vec![OperationBuilder::insert("45").build()] ); } #[test] fn delta_get_ops_in_interval_4() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("12").build(); - let insert_b = OpBuilder::insert("34").build(); - let insert_c = OpBuilder::insert("56").build(); + let insert_a = OperationBuilder::insert("12").build(); + let insert_b = OperationBuilder::insert("34").build(); + let insert_c = OperationBuilder::insert("56").build(); delta.ops.push(insert_a.clone()); delta.ops.push(insert_b.clone()); delta.ops.push(insert_c.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(0, 2)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), vec![insert_a] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(2, 4)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(2, 4)).ops(), vec![insert_b] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(4, 6)).ops(), + DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(), vec![insert_c] ); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(2, 5)).ops(), - vec![OpBuilder::insert("34").build(), OpBuilder::insert("5").build()] + DeltaIterator::from_interval(&delta, Interval::new(2, 5)).ops(), + vec![ + OperationBuilder::insert("34").build(), + OperationBuilder::insert("5").build() + ] ); } #[test] fn delta_get_ops_in_interval_5() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("123456").build(); - let insert_b = OpBuilder::insert("789").build(); + let insert_a = OperationBuilder::insert("123456").build(); + let insert_b = OperationBuilder::insert("789").build(); delta.ops.push(insert_a.clone()); delta.ops.push(insert_b.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(4, 8)).ops(), - vec![OpBuilder::insert("56").build(), OpBuilder::insert("78").build()] + DeltaIterator::from_interval(&delta, Interval::new(4, 8)).ops(), + vec![ + OperationBuilder::insert("56").build(), + OperationBuilder::insert("78").build() + ] ); // assert_eq!( @@ -155,54 +162,60 @@ fn delta_get_ops_in_interval_5() { #[test] fn delta_get_ops_in_interval_6() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("12345678").build(); + let insert_a = OperationBuilder::insert("12345678").build(); delta.add(insert_a.clone()); assert_eq!( - DeltaIter::from_interval(&delta, Interval::new(4, 6)).ops(), - vec![OpBuilder::insert("56").build()] + DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(), + vec![OperationBuilder::insert("56").build()] ); } #[test] fn delta_get_ops_in_interval_7() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("12345").build(); - let retain_a = OpBuilder::retain(3).build(); + let insert_a = OperationBuilder::insert("12345").build(); + let retain_a = OperationBuilder::retain(3).build(); delta.add(insert_a.clone()); delta.add(retain_a.clone()); - let mut iter_1 = DeltaIter::from_offset(&delta, 2); - assert_eq!(iter_1.next_op().unwrap(), OpBuilder::insert("345").build()); - assert_eq!(iter_1.next_op().unwrap(), OpBuilder::retain(3).build()); + let mut iter_1 = DeltaIterator::from_offset(&delta, 2); + assert_eq!(iter_1.next_op().unwrap(), OperationBuilder::insert("345").build()); + assert_eq!(iter_1.next_op().unwrap(), OperationBuilder::retain(3).build()); - let mut iter_2 = DeltaIter::new(&delta); - assert_eq!(iter_2.next_op_with_len(2).unwrap(), OpBuilder::insert("12").build()); - assert_eq!(iter_2.next_op().unwrap(), OpBuilder::insert("345").build()); + let mut iter_2 = DeltaIterator::new(&delta); + assert_eq!( + iter_2.next_op_with_len(2).unwrap(), + OperationBuilder::insert("12").build() + ); + assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::insert("345").build()); - assert_eq!(iter_2.next_op().unwrap(), OpBuilder::retain(3).build()); + assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::retain(3).build()); } #[test] fn delta_op_seek() { let mut delta = RichTextDelta::default(); - let insert_a = OpBuilder::insert("12345").build(); - let retain_a = OpBuilder::retain(3).build(); + let insert_a = OperationBuilder::insert("12345").build(); + let retain_a = OperationBuilder::retain(3).build(); delta.add(insert_a.clone()); delta.add(retain_a.clone()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); iter.seek::(1); - assert_eq!(iter.next_op().unwrap(), OpBuilder::retain(3).build()); + assert_eq!(iter.next_op().unwrap(), retain_a); } #[test] fn delta_utf16_code_unit_seek() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); + delta.add(OperationBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); iter.seek::(3); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("45").build()); + assert_eq!( + iter.next_op_with_len(2).unwrap(), + OperationBuilder::insert("45").build() + ); } #[test] @@ -213,77 +226,92 @@ fn delta_utf16_code_unit_seek_with_attributes() { .add_attr(RichTextAttribute::Italic(true)) .build(); - delta.add(OpBuilder::insert("1234").attributes(attributes.clone()).build()); - delta.add(OpBuilder::insert("\n").build()); + delta.add(OperationBuilder::insert("1234").attributes(attributes.clone()).build()); + delta.add(OperationBuilder::insert("\n").build()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); iter.seek::(0); assert_eq!( iter.next_op_with_len(4).unwrap(), - OpBuilder::insert("1234").attributes(attributes).build(), + OperationBuilder::insert("1234").attributes(attributes).build(), ); } #[test] fn delta_next_op_len() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("12").build()); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("34").build()); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("5").build()); + delta.add(OperationBuilder::insert("12345").build()); + let mut iter = DeltaIterator::new(&delta); + assert_eq!( + iter.next_op_with_len(2).unwrap(), + OperationBuilder::insert("12").build() + ); + assert_eq!( + iter.next_op_with_len(2).unwrap(), + OperationBuilder::insert("34").build() + ); + assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::insert("5").build()); assert_eq!(iter.next_op_with_len(1), None); } #[test] fn delta_next_op_len_with_chinese() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("你好").build()); + delta.add(OperationBuilder::insert("你好").build()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("你好").build()); + assert_eq!( + iter.next_op_with_len(2).unwrap(), + OperationBuilder::insert("你好").build() + ); } #[test] fn delta_next_op_len_with_english() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("ab").build()); - let mut iter = DeltaIter::new(&delta); + delta.add(OperationBuilder::insert("ab").build()); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::insert("ab").build()); + assert_eq!( + iter.next_op_with_len(2).unwrap(), + OperationBuilder::insert("ab").build() + ); } #[test] fn delta_next_op_len_after_seek() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); + delta.add(OperationBuilder::insert("12345").build()); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 5); iter.seek::(3); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!(iter.next_op_with_len(1).unwrap(), OpBuilder::insert("4").build()); + assert_eq!(iter.next_op_with_len(1).unwrap(), OperationBuilder::insert("4").build()); assert_eq!(iter.next_op_len().unwrap(), 1); - assert_eq!(iter.next_op().unwrap(), OpBuilder::insert("5").build()); + assert_eq!(iter.next_op().unwrap(), OperationBuilder::insert("5").build()); } #[test] fn delta_next_op_len_none() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); + delta.add(OperationBuilder::insert("12345").build()); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 5); - assert_eq!(iter.next_op_with_len(5).unwrap(), OpBuilder::insert("12345").build()); + assert_eq!( + iter.next_op_with_len(5).unwrap(), + OperationBuilder::insert("12345").build() + ); assert_eq!(iter.next_op_len(), None); } #[test] fn delta_next_op_with_len_zero() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - let mut iter = DeltaIter::new(&delta); + delta.add(OperationBuilder::insert("12345").build()); + let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_with_len(0), None,); assert_eq!(iter.next_op_len().unwrap(), 5); } @@ -291,14 +319,14 @@ fn delta_next_op_with_len_zero() { #[test] fn delta_next_op_with_len_cross_op_return_last() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("12345").build()); - delta.add(OpBuilder::retain(1).build()); - delta.add(OpBuilder::insert("678").build()); + delta.add(OperationBuilder::insert("12345").build()); + delta.add(OperationBuilder::retain(1).build()); + delta.add(OperationBuilder::insert("678").build()); - let mut iter = DeltaIter::new(&delta); + let mut iter = DeltaIterator::new(&delta); iter.seek::(4); assert_eq!(iter.next_op_len().unwrap(), 1); - assert_eq!(iter.next_op_with_len(2).unwrap(), OpBuilder::retain(1).build()); + assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::retain(1).build()); } #[test] @@ -342,18 +370,17 @@ fn apply_1000() { } #[test] -fn apply() { - let s = "hello world,".to_owned(); - let mut delta_a = RichTextDelta::default(); - delta_a.insert(&s, RichTextAttributes::default()); +fn apply_test() { + let s = "hello"; + let delta_a = PlainTextDeltaBuilder::new().insert(s).build(); + let delta_b = PlainTextDeltaBuilder::new() + .retain(s.len()) + .insert(", AppFlowy") + .build(); - let mut delta_b = RichTextDelta::default(); - delta_b.retain(s.len(), RichTextAttributes::default()); - delta_b.insert("appflowy", RichTextAttributes::default()); - - let after_a = delta_a.apply("").unwrap(); + let after_a = delta_a.to_str().unwrap(); let after_b = delta_b.apply(&after_a).unwrap(); - assert_eq!("hello world,appflowy", &after_b); + assert_eq!("hello, AppFlowy", &after_b); } #[test] @@ -384,6 +411,17 @@ fn invert() { } } +#[test] +fn invert_test() { + let s = "hello world"; + let delta = PlainTextDeltaBuilder::new().insert(s).build(); + let invert_delta = delta.invert_str(""); + assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len); + assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len); + + assert_eq!(invert_delta.apply(s).unwrap(), "") +} + #[test] fn empty_ops() { let mut delta = RichTextDelta::default(); @@ -415,23 +453,24 @@ fn ops_merging() { assert_eq!(delta.ops.len(), 0); delta.retain(2, RichTextAttributes::default()); assert_eq!(delta.ops.len(), 1); - assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(2).build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(2).build())); delta.retain(3, RichTextAttributes::default()); assert_eq!(delta.ops.len(), 1); - assert_eq!(delta.ops.last(), Some(&OpBuilder::retain(5).build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(5).build())); delta.insert("abc", RichTextAttributes::default()); assert_eq!(delta.ops.len(), 2); - assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abc").build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abc").build())); delta.insert("xyz", RichTextAttributes::default()); assert_eq!(delta.ops.len(), 2); - assert_eq!(delta.ops.last(), Some(&OpBuilder::insert("abcxyz").build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abcxyz").build())); delta.delete(1); assert_eq!(delta.ops.len(), 3); - assert_eq!(delta.ops.last(), Some(&OpBuilder::delete(1).build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(1).build())); delta.delete(1); assert_eq!(delta.ops.len(), 3); - assert_eq!(delta.ops.last(), Some(&OpBuilder::delete(2).build())); + assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(2).build())); } + #[test] fn is_noop() { let mut delta = RichTextDelta::default(); @@ -582,11 +621,11 @@ fn transform_two_conflict_non_seq_delta() { #[test] fn delta_invert_no_attribute_delta() { let mut delta = RichTextDelta::default(); - delta.add(OpBuilder::insert("123").build()); + delta.add(OperationBuilder::insert("123").build()); let mut change = RichTextDelta::default(); - change.add(OpBuilder::retain(3).build()); - change.add(OpBuilder::insert("456").build()); + change.add(OperationBuilder::retain(3).build()); + change.add(OperationBuilder::insert("456").build()); let undo = change.invert(&delta); let new_delta = delta.compose(&change).unwrap(); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs index 87d425901b..ae9e57b3c6 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs @@ -11,7 +11,7 @@ fn operation_insert_serialize_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let operation = OpBuilder::insert("123").attributes(attributes).build(); + let operation = OperationBuilder::insert("123").attributes(attributes).build(); let json = serde_json::to_string(&operation).unwrap(); eprintln!("{}", json); @@ -42,7 +42,7 @@ fn attributes_serialize_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let retain = OpBuilder::insert("123").attributes(attributes).build(); + let retain = OperationBuilder::insert("123").attributes(attributes).build(); let json = serde_json::to_string(&retain).unwrap(); eprintln!("{}", json); @@ -56,7 +56,7 @@ fn delta_serialize_multi_attribute_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let retain = OpBuilder::insert("123").attributes(attributes).build(); + let retain = OperationBuilder::insert("123").attributes(attributes).build(); delta.add(retain); delta.add(Operation::Retain(5.into())); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs index e6ea9200ab..78aa034744 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/undo_redo_test.rs @@ -108,6 +108,7 @@ fn history_bold_redo_with_lagging() { fn history_delete_undo() { let ops = vec![ Insert(0, "123", 0), + Wait(RECORD_THRESHOLD), AssertDocJson(0, r#"[{"insert":"123"}]"#), Delete(0, Interval::new(0, 3)), AssertDocJson(0, r#"[]"#), diff --git a/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs b/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs index 4da15e5f06..6c7283e4c7 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/delete/preserve_line_format_merge.rs @@ -1,6 +1,6 @@ use crate::{client_document::DeleteExt, util::is_newline}; use lib_ot::{ - core::{Attributes, DeltaBuilder, DeltaIter, Interval, Utf16CodeUnitMetric, NEW_LINE}, + core::{Attributes, DeltaBuilder, DeltaIterator, Interval, Utf16CodeUnitMetric, NEW_LINE}, rich_text::{plain_attributes, RichTextDelta}, }; @@ -16,7 +16,7 @@ impl DeleteExt for PreserveLineFormatOnMerge { } // seek to the interval start pos. e.g. You backspace enter pos - let mut iter = DeltaIter::from_offset(delta, interval.start); + let mut iter = DeltaIterator::from_offset(delta, interval.start); // op will be the "\n" let newline_op = iter.next_op_with_len(1)?; diff --git a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs index 46a0e0290d..4a4c00a19d 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_block_format.rs @@ -1,5 +1,5 @@ use lib_ot::{ - core::{DeltaBuilder, DeltaIter, Interval}, + core::{DeltaBuilder, DeltaIterator, Interval}, rich_text::{plain_attributes, AttributeScope, RichTextAttribute, RichTextDelta}, }; @@ -20,7 +20,7 @@ impl FormatExt for ResolveBlockFormat { } let mut new_delta = DeltaBuilder::new().retain(interval.start).build(); - let mut iter = DeltaIter::from_offset(delta, interval.start); + let mut iter = DeltaIterator::from_offset(delta, interval.start); let mut start = 0; let end = interval.size(); while start < end && iter.has_next() { diff --git a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs index 383b780aca..567d06d6f2 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/format/resolve_inline_format.rs @@ -1,5 +1,5 @@ use lib_ot::{ - core::{DeltaBuilder, DeltaIter, Interval}, + core::{DeltaBuilder, DeltaIterator, Interval}, rich_text::{AttributeScope, RichTextAttribute, RichTextDelta}, }; @@ -19,7 +19,7 @@ impl FormatExt for ResolveInlineFormat { return None; } let mut new_delta = DeltaBuilder::new().retain(interval.start).build(); - let mut iter = DeltaIter::from_offset(delta, interval.start); + let mut iter = DeltaIterator::from_offset(delta, interval.start); let mut start = 0; let end = interval.size(); diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs index e41470b9eb..253833d255 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_exit_block.rs @@ -1,8 +1,6 @@ use crate::{client_document::InsertExt, util::is_newline}; -use lib_ot::{ - core::{is_empty_line_at_index, DeltaBuilder, DeltaIter}, - rich_text::{attributes_except_header, RichTextAttributeKey, RichTextDelta}, -}; +use lib_ot::core::{is_empty_line_at_index, DeltaBuilder, DeltaIterator}; +use lib_ot::rich_text::{attributes_except_header, RichTextAttributeKey, RichTextDelta}; pub struct AutoExitBlock {} @@ -21,7 +19,7 @@ impl InsertExt for AutoExitBlock { return None; } - let mut iter = DeltaIter::from_offset(delta, index); + let mut iter = DeltaIterator::from_offset(delta, index); let next = iter.next_op()?; let mut attributes = next.get_attributes(); diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs index d7f1da4f89..4c7cd642c2 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/auto_format.rs @@ -1,6 +1,6 @@ use crate::{client_document::InsertExt, util::is_whitespace}; use lib_ot::{ - core::{count_utf16_code_units, DeltaBuilder, DeltaIter}, + core::{count_utf16_code_units, DeltaBuilder, DeltaIterator}, rich_text::{plain_attributes, RichTextAttribute, RichTextAttributes, RichTextDelta}, }; use std::cmp::min; @@ -17,7 +17,7 @@ impl InsertExt for AutoFormatExt { if !is_whitespace(text) { return None; } - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); if let Some(prev) = iter.next_op_with_len(index) { match AutoFormat::parse(prev.get_data()) { None => {} diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs index 628d55cb24..c165985493 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/default_insert.rs @@ -1,6 +1,6 @@ use crate::client_document::InsertExt; use lib_ot::{ - core::{Attributes, DeltaBuilder, DeltaIter, NEW_LINE}, + core::{Attributes, DeltaBuilder, DeltaIterator, NEW_LINE}, rich_text::{RichTextAttributeKey, RichTextAttributes, RichTextDelta}, }; @@ -11,7 +11,7 @@ impl InsertExt for DefaultInsertAttribute { } fn apply(&self, delta: &RichTextDelta, replace_len: usize, text: &str, index: usize) -> Option { - let iter = DeltaIter::new(delta); + let iter = DeltaIterator::new(delta); let mut attributes = RichTextAttributes::new(); // Enable each line split by "\n" remains the block attributes. for example: diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs index 2c0ceae111..03c9723d7b 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_block_format.rs @@ -1,6 +1,6 @@ use crate::{client_document::InsertExt, util::is_newline}; use lib_ot::{ - core::{DeltaBuilder, DeltaIter, NEW_LINE}, + core::{DeltaBuilder, DeltaIterator, NEW_LINE}, rich_text::{ attributes_except_header, plain_attributes, RichTextAttribute, RichTextAttributeKey, RichTextAttributes, RichTextDelta, @@ -18,7 +18,7 @@ impl InsertExt for PreserveBlockFormatOnInsert { return None; } - let mut iter = DeltaIter::from_offset(delta, index); + let mut iter = DeltaIterator::from_offset(delta, index); match iter.next_op_with_newline() { None => {} Some((newline_op, offset)) => { diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs index 37b31e3d26..b0de6451aa 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/preserve_inline_format.rs @@ -3,7 +3,7 @@ use crate::{ util::{contain_newline, is_newline}, }; use lib_ot::{ - core::{DeltaBuilder, DeltaIter, OpNewline, NEW_LINE}, + core::{DeltaBuilder, DeltaIterator, OpNewline, NEW_LINE}, rich_text::{plain_attributes, RichTextAttributeKey, RichTextDelta}, }; @@ -18,7 +18,7 @@ impl InsertExt for PreserveInlineFormat { return None; } - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); let prev = iter.next_op_with_len(index)?; if OpNewline::parse(&prev).is_contain() { return None; @@ -64,7 +64,7 @@ impl InsertExt for PreserveLineFormatOnSplit { return None; } - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); let prev = iter.next_op_with_len(index)?; if OpNewline::parse(&prev).is_end() { return None; diff --git a/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs b/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs index f63bf9bddf..8671049ee7 100644 --- a/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs +++ b/shared-lib/flowy-sync/src/client_document/extensions/insert/reset_format_on_new_line.rs @@ -1,6 +1,6 @@ use crate::{client_document::InsertExt, util::is_newline}; use lib_ot::{ - core::{DeltaBuilder, DeltaIter, Utf16CodeUnitMetric, NEW_LINE}, + core::{DeltaBuilder, DeltaIterator, Utf16CodeUnitMetric, NEW_LINE}, rich_text::{RichTextAttributeKey, RichTextAttributes, RichTextDelta}, }; @@ -15,7 +15,7 @@ impl InsertExt for ResetLineFormatOnNewLine { return None; } - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); iter.seek::(index); let next_op = iter.next_op()?; if !next_op.get_data().starts_with(NEW_LINE) { diff --git a/shared-lib/lib-ot/src/core/delta/builder.rs b/shared-lib/lib-ot/src/core/delta/builder.rs index b065b645af..184284393a 100644 --- a/shared-lib/lib-ot/src/core/delta/builder.rs +++ b/shared-lib/lib-ot/src/core/delta/builder.rs @@ -1,7 +1,12 @@ -use crate::core::{trim, Attributes, Delta, PlainTextAttributes}; +use crate::core::delta::{trim, Delta}; +use crate::core::operation::{Attributes, PlainTextAttributes}; pub type PlainTextDeltaBuilder = DeltaBuilder; +/// A builder for creating new [Delta] objects. +/// +/// Note that all edit operations must be sorted; the start point of each +/// interval must be no less than the end point of the previous one. pub struct DeltaBuilder { delta: Delta, } @@ -23,6 +28,8 @@ where DeltaBuilder::default() } + /// Retain the 'n' characters with the attributes. Use 'retain' instead if you don't + /// need any attributes. pub fn retain_with_attributes(mut self, n: usize, attrs: T) -> Self { self.delta.retain(n, attrs); self @@ -33,11 +40,14 @@ where self } + /// Deletes the given interval. Panics if interval is not properly sorted. pub fn delete(mut self, n: usize) -> Self { self.delta.delete(n); self } + /// Insert the string with attributes. Use 'insert' instead if you don't + /// need any attributes. pub fn insert_with_attributes(mut self, s: &str, attrs: T) -> Self { self.delta.insert(s, attrs); self @@ -53,6 +63,7 @@ where self } + /// Builds the `Delta` pub fn build(self) -> Delta { self.delta } diff --git a/shared-lib/lib-ot/src/core/delta/cursor.rs b/shared-lib/lib-ot/src/core/delta/cursor.rs index d6ebb8b3cc..a465d62dea 100644 --- a/shared-lib/lib-ot/src/core/delta/cursor.rs +++ b/shared-lib/lib-ot/src/core/delta/cursor.rs @@ -1,33 +1,51 @@ #![allow(clippy::while_let_on_iterator)] -use crate::{ - core::{Attributes, Delta, Interval, Operation}, - errors::{ErrorBuilder, OTError, OTErrorCode}, -}; +use crate::core::delta::Delta; +use crate::core::interval::Interval; +use crate::core::operation::{Attributes, Operation}; +use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use std::{cmp::min, iter::Enumerate, slice::Iter}; +/// A [DeltaCursor] is used to iterate the delta and return the corresponding delta. #[derive(Debug)] -pub struct OpCursor<'a, T: Attributes> { +pub struct DeltaCursor<'a, T: Attributes> { pub(crate) delta: &'a Delta, pub(crate) origin_iv: Interval, pub(crate) consume_iv: Interval, pub(crate) consume_count: usize, - pub(crate) op_index: usize, + pub(crate) op_offset: usize, iter: Enumerate>>, next_op: Option>, } -impl<'a, T> OpCursor<'a, T> +impl<'a, T> DeltaCursor<'a, T> where T: Attributes, { - pub fn new(delta: &'a Delta, interval: Interval) -> OpCursor<'a, T> { + /// # Arguments + /// + /// * `delta`: The delta you want to iterate over. + /// * `interval`: The range for the cursor movement. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{DeltaIterator, Interval, OperationBuilder}; + /// use lib_ot::rich_text::RichTextDelta; + /// let mut delta = RichTextDelta::default(); + /// let op_1 = OperationBuilder::insert("123").build(); + /// let op_2 = OperationBuilder::insert("4").build(); + /// delta.add(op_1.clone()); + /// delta.add(op_2.clone()); + /// assert_eq!(DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), vec![op_1.clone()]); + /// ``` + pub fn new(delta: &'a Delta, interval: Interval) -> DeltaCursor<'a, T> { // debug_assert!(interval.start <= delta.target_len); let mut cursor = Self { delta, origin_iv: interval, consume_iv: interval, consume_count: 0, - op_index: 0, + op_offset: 0, iter: delta.ops.iter().enumerate(), next_op: None, }; @@ -35,17 +53,37 @@ where cursor } - // get the next operation interval + /// Return the next operation interval pub fn next_iv(&self) -> Interval { self.next_iv_with_len(None).unwrap_or_else(|| Interval::new(0, 0)) } - pub fn next_op(&mut self) -> Option> { + /// Return the next operation + pub fn get_next_op(&mut self) -> Option> { self.next_with_len(None) } - // get the last operation before the end. - // checkout the delta_next_op_with_len_cross_op_return_last test for more detail + /// Return the reference of the next operation + pub fn next_op(&self) -> Option<&Operation> { + let mut next_op = self.next_op.as_ref(); + if next_op.is_none() { + let mut offset = 0; + for op in &self.delta.ops { + offset += op.len(); + if offset > self.consume_count { + next_op = Some(op); + break; + } + } + } + next_op + } + + /// # Arguments + /// + /// * `expected_len`: Return the next operation with the specified length. + /// + /// pub fn next_with_len(&mut self, expected_len: Option) -> Option> { let mut find_op = None; let holder = self.next_op.clone(); @@ -97,17 +135,24 @@ where } pub fn has_next(&self) -> bool { - self.next_iter_op().is_some() + self.next_op().is_some() } - fn descend(&mut self, index: usize) { - self.consume_iv.start += index; + /// Find the op within the current offset. + /// This function sets the start of the consume_iv to the offset, update the consume_count + /// and the next_op reference. + /// + /// # Arguments + /// + /// * `offset`: Represents the offset of the delta string, in Utf16CodeUnit unit. + fn descend(&mut self, offset: usize) { + self.consume_iv.start += offset; if self.consume_count >= self.consume_iv.start { return; } while let Some((o_index, op)) = self.iter.next() { - self.op_index = o_index; + self.op_offset = o_index; let start = self.consume_count; let end = start + op.len(); let intersect = Interval::new(start, end).intersect(self.consume_iv); @@ -121,7 +166,7 @@ where } fn next_iv_with_len(&self, expected_len: Option) -> Option { - let op = self.next_iter_op()?; + let op = self.next_op()?; let start = self.consume_count; let end = match expected_len { None => self.consume_count + op.len(), @@ -132,31 +177,16 @@ where let interval = intersect.translate_neg(start); Some(interval) } - - pub fn next_iter_op(&self) -> Option<&Operation> { - let mut next_op = self.next_op.as_ref(); - if next_op.is_none() { - let mut offset = 0; - for op in &self.delta.ops { - offset += op.len(); - if offset > self.consume_count { - next_op = Some(op); - break; - } - } - } - next_op - } } -fn find_next<'a, T>(cursor: &mut OpCursor<'a, T>) -> Option<&'a Operation> +fn find_next<'a, T>(cursor: &mut DeltaCursor<'a, T>) -> Option<&'a Operation> where T: Attributes, { match cursor.iter.next() { None => None, Some((o_index, op)) => { - cursor.op_index = o_index; + cursor.op_offset = o_index; Some(op) } } @@ -164,31 +194,34 @@ where type SeekResult = Result<(), OTError>; pub trait Metric { - fn seek(cursor: &mut OpCursor, offset: usize) -> SeekResult; + fn seek(cursor: &mut DeltaCursor, offset: usize) -> SeekResult; } +/// [OpMetric] is used by [DeltaIterator] for seeking operations +/// The unit of the movement is Operation pub struct OpMetric(); impl Metric for OpMetric { - fn seek(cursor: &mut OpCursor, offset: usize) -> SeekResult { - let _ = check_bound(cursor.op_index, offset)?; - let mut seek_cursor = OpCursor::new(cursor.delta, cursor.origin_iv); - let mut cur_offset = 0; + fn seek(cursor: &mut DeltaCursor, op_offset: usize) -> SeekResult { + let _ = check_bound(cursor.op_offset, op_offset)?; + let mut seek_cursor = DeltaCursor::new(cursor.delta, cursor.origin_iv); + while let Some((_, op)) = seek_cursor.iter.next() { - cur_offset += op.len(); - if cur_offset > offset { + cursor.descend(op.len()); + if cursor.op_offset >= op_offset { break; } } - cursor.descend(cur_offset); Ok(()) } } +/// [Utf16CodeUnitMetric] is used by [DeltaIterator] for seeking operations. +/// The unit of the movement is Utf16CodeUnit pub struct Utf16CodeUnitMetric(); impl Metric for Utf16CodeUnitMetric { - fn seek(cursor: &mut OpCursor, offset: usize) -> SeekResult { + fn seek(cursor: &mut DeltaCursor, offset: usize) -> SeekResult { if offset > 0 { let _ = check_bound(cursor.consume_count, offset)?; let _ = cursor.next_with_len(Some(offset)); diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 29fd424dcb..6edf817bdf 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -1,8 +1,9 @@ -use crate::{ - core::{operation::*, DeltaIter, FlowyStr, Interval, OperationTransformable, MAX_IV_LEN}, - errors::{ErrorBuilder, OTError, OTErrorCode}, -}; +use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; +use crate::core::delta::{DeltaIterator, MAX_IV_LEN}; +use crate::core::flowy_str::FlowyStr; +use crate::core::interval::Interval; +use crate::core::operation::{Attributes, Operation, OperationBuilder, OperationTransformable, PlainTextAttributes}; use bytes::Bytes; use serde::de::DeserializeOwned; use std::{ @@ -15,11 +16,20 @@ use std::{ pub type PlainTextDelta = Delta; -// TODO: optimize the memory usage with Arc::make_mut or Cow +/// A [Delta] contains list of operations that consists of 'Retain', 'Delete' and 'Insert' operation. +/// Check out the [Operation] for more details. It describes the document as a sequence of +/// operations. +/// #[derive(Clone, Debug, PartialEq, Eq)] pub struct Delta { pub ops: Vec>, + + /// 'Delete' and 'Retain' operation will update the [utf16_base_len] + /// Transforming the other delta, it requires the utf16_base_len must be equal. pub utf16_base_len: usize, + + /// Represents the current len of the delta. + /// 'Insert' and 'Retain' operation will update the [utf16_target_len] pub utf16_target_len: usize, } @@ -81,6 +91,7 @@ where } } + /// Adding an operation. It will be added in sequence. pub fn add(&mut self, op: Operation) { match op { Operation::Delete(i) => self.delete(i), @@ -89,6 +100,7 @@ where } } + /// Creating a [Delete] operation with len [n] pub fn delete(&mut self, n: usize) { if n == 0 { return; @@ -97,10 +109,11 @@ where if let Some(Operation::Delete(n_last)) = self.ops.last_mut() { *n_last += n; } else { - self.ops.push(OpBuilder::delete(n).build()); + self.ops.push(OperationBuilder::delete(n).build()); } } + /// Creating a [Insert] operation with string, [s]. pub fn insert(&mut self, s: &str, attributes: T) { let s: FlowyStr = s.into(); if s.is_empty() { @@ -119,10 +132,10 @@ where } [.., op_last @ Operation::::Delete(_)] => { let new_last = op_last.clone(); - *op_last = OpBuilder::::insert(&s).attributes(attributes).build(); + *op_last = OperationBuilder::::insert(&s).attributes(attributes).build(); Some(new_last) } - _ => Some(OpBuilder::::insert(&s).attributes(attributes).build()), + _ => Some(OperationBuilder::::insert(&s).attributes(attributes).build()), }; match new_last { @@ -131,6 +144,7 @@ where } } + /// Creating a [Retain] operation with len, [n]. pub fn retain(&mut self, n: usize, attributes: T) { if n == 0 { return; @@ -143,24 +157,48 @@ where self.ops.push(new_op); } } else { - self.ops.push(OpBuilder::::retain(n).attributes(attributes).build()); + self.ops + .push(OperationBuilder::::retain(n).attributes(attributes).build()); } } - /// Applies an operation to a string, returning a new string. - pub fn apply(&self, s: &str) -> Result { - let s: FlowyStr = s.into(); - if s.utf16_size() != self.utf16_base_len { + /// Return the a new string described by this delta. The new string will contains the input string. + /// The length of the [applied_str] must be equal to the the [utf16_base_len]. + /// + /// # Arguments + /// + /// * `applied_str`: A string represents the utf16_base_len content. it will be consumed by the [retain] + /// or [delete] operations. + /// + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::PlainTextDeltaBuilder; + /// let s = "hello"; + /// let delta_a = PlainTextDeltaBuilder::new().insert(s).build(); + /// let delta_b = PlainTextDeltaBuilder::new() + /// .retain(s.len()) + /// .insert(", AppFlowy") + /// .build(); + /// + /// let after_a = delta_a.to_str().unwrap(); + /// let after_b = delta_b.apply(&after_a).unwrap(); + /// assert_eq!("hello, AppFlowy", &after_b); + /// ``` + pub fn apply(&self, applied_str: &str) -> Result { + let applied_str: FlowyStr = applied_str.into(); + if applied_str.utf16_size() != self.utf16_base_len { return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength) .msg(format!( - "Expected: {}, received: {}", + "Expected: {}, but received: {}", self.utf16_base_len, - s.utf16_size() + applied_str.utf16_size() )) .build()); } let mut new_s = String::new(); - let code_point_iter = &mut s.utf16_code_unit_iter(); + let code_point_iter = &mut applied_str.utf16_code_unit_iter(); for op in &self.ops { match &op { Operation::Retain(retain) => { @@ -181,34 +219,60 @@ where Ok(new_s) } - /// Computes the inverse of an operation. The inverse of an operation is the - /// operation that reverts the effects of the operation - pub fn invert_str(&self, s: &str) -> Self { + /// Computes the inverse [Delta]. The inverse of an operation is the + /// operation that reverts the effects of the operation + /// # Arguments + /// + /// * `inverted_s`: A string represents the utf16_base_len content. The len of [inverted_s] + /// must equal to the [utf16_base_len], it will be consumed by the [retain] or [delete] operations. + /// + /// If the delta's operations just contain a insert operation. The inverted_s must be empty string. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::PlainTextDeltaBuilder; + /// let s = "hello world"; + /// let delta = PlainTextDeltaBuilder::new().insert(s).build(); + /// let invert_delta = delta.invert_str(s); + /// assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len); + /// assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len); + /// + /// assert_eq!(invert_delta.apply(s).unwrap(), "") + /// + /// ``` + /// + pub fn invert_str(&self, inverted_s: &str) -> Self { let mut inverted = Delta::default(); - let chars = &mut s.chars(); + let inverted_s: FlowyStr = inverted_s.into(); + let code_point_iter = &mut inverted_s.utf16_code_unit_iter(); + for op in &self.ops { match &op { Operation::Retain(retain) => { inverted.retain(retain.n, T::default()); - // TODO: use advance_by instead, but it's unstable now - // chars.advance_by(retain.num) for _ in 0..retain.n { - chars.next(); + code_point_iter.next(); } } Operation::Insert(insert) => { inverted.delete(insert.utf16_size()); } Operation::Delete(delete) => { - inverted.insert(&chars.take(*delete as usize).collect::(), op.get_attributes()); + let bytes = code_point_iter + .take(*delete as usize) + .into_iter() + .flat_map(|a| str::from_utf8(a.0).ok()) + .collect::(); + + inverted.insert(&bytes, op.get_attributes()); } } } inverted } - /// Checks if this operation has no effect. - #[inline] + /// Return true if the delta doesn't contain any [Insert] or [Delete] operations. pub fn is_noop(&self) -> bool { matches!(self.ops.as_slice(), [] | [Operation::Retain(_)]) } @@ -231,8 +295,8 @@ where Self: Sized, { let mut new_delta = Delta::default(); - let mut iter = DeltaIter::new(self); - let mut other_iter = DeltaIter::new(other); + let mut iter = DeltaIterator::new(self); + let mut other_iter = DeltaIterator::new(other); while iter.has_next() || other_iter.has_next() { if other_iter.is_next_insert() { @@ -252,10 +316,10 @@ where let op = iter .next_op_with_len(length) - .unwrap_or_else(|| OpBuilder::retain(length).build()); + .unwrap_or_else(|| OperationBuilder::retain(length).build()); let other_op = other_iter .next_op_with_len(length) - .unwrap_or_else(|| OpBuilder::retain(length).build()); + .unwrap_or_else(|| OperationBuilder::retain(length).build()); // debug_assert_eq!(op.len(), other_op.len(), "Composing delta failed,"); @@ -263,12 +327,16 @@ where (Operation::Retain(retain), Operation::Retain(other_retain)) => { let composed_attrs = retain.attributes.compose(&other_retain.attributes)?; - new_delta.add(OpBuilder::retain(retain.n).attributes(composed_attrs).build()) + new_delta.add(OperationBuilder::retain(retain.n).attributes(composed_attrs).build()) } (Operation::Insert(insert), Operation::Retain(other_retain)) => { let mut composed_attrs = insert.attributes.compose(&other_retain.attributes)?; composed_attrs.remove_empty(); - new_delta.add(OpBuilder::insert(op.get_data()).attributes(composed_attrs).build()) + new_delta.add( + OperationBuilder::insert(op.get_data()) + .attributes(composed_attrs) + .build(), + ) } (Operation::Retain(_), Operation::Delete(_)) => { new_delta.add(other_op); @@ -331,7 +399,7 @@ where Ordering::Less => { a_prime.retain(retain.n, composed_attrs.clone()); b_prime.retain(retain.n, composed_attrs.clone()); - next_op2 = Some(OpBuilder::retain(o_retain.n - retain.n).build()); + next_op2 = Some(OperationBuilder::retain(o_retain.n - retain.n).build()); next_op1 = ops1.next(); } Ordering::Equal => { @@ -343,14 +411,14 @@ where Ordering::Greater => { a_prime.retain(o_retain.n, composed_attrs.clone()); b_prime.retain(o_retain.n, composed_attrs.clone()); - next_op1 = Some(OpBuilder::retain(retain.n - o_retain.n).build()); + next_op1 = Some(OperationBuilder::retain(retain.n - o_retain.n).build()); next_op2 = ops2.next(); } }; } (Some(Operation::Delete(i)), Some(Operation::Delete(j))) => match i.cmp(j) { Ordering::Less => { - next_op2 = Some(OpBuilder::delete(*j - *i).build()); + next_op2 = Some(OperationBuilder::delete(*j - *i).build()); next_op1 = ops1.next(); } Ordering::Equal => { @@ -358,7 +426,7 @@ where next_op2 = ops2.next(); } Ordering::Greater => { - next_op1 = Some(OpBuilder::delete(*i - *j).build()); + next_op1 = Some(OperationBuilder::delete(*i - *j).build()); next_op2 = ops2.next(); } }, @@ -366,7 +434,7 @@ where match i.cmp(o_retain) { Ordering::Less => { a_prime.delete(*i); - next_op2 = Some(OpBuilder::retain(o_retain.n - *i).build()); + next_op2 = Some(OperationBuilder::retain(o_retain.n - *i).build()); next_op1 = ops1.next(); } Ordering::Equal => { @@ -376,7 +444,7 @@ where } Ordering::Greater => { a_prime.delete(o_retain.n); - next_op1 = Some(OpBuilder::delete(*i - o_retain.n).build()); + next_op1 = Some(OperationBuilder::delete(*i - o_retain.n).build()); next_op2 = ops2.next(); } }; @@ -385,7 +453,7 @@ where match retain.cmp(j) { Ordering::Less => { b_prime.delete(retain.n); - next_op2 = Some(OpBuilder::delete(*j - retain.n).build()); + next_op2 = Some(OperationBuilder::delete(*j - retain.n).build()); next_op1 = ops1.next(); } Ordering::Equal => { @@ -395,7 +463,7 @@ where } Ordering::Greater => { b_prime.delete(*j); - next_op1 = Some(OpBuilder::retain(retain.n - *j).build()); + next_op1 = Some(OperationBuilder::retain(retain.n - *j).build()); next_op2 = ops2.next(); } }; @@ -407,21 +475,17 @@ where fn invert(&self, other: &Self) -> Self { let mut inverted = Delta::default(); - if other.is_empty() { - return inverted; - } - let mut index = 0; for op in &self.ops { let len: usize = op.len() as usize; match op { Operation::Delete(n) => { - invert_from_other(&mut inverted, other, op, index, index + *n); + invert_other(&mut inverted, other, op, index, index + *n); index += len; } Operation::Retain(_) => { match op.has_attribute() { - true => invert_from_other(&mut inverted, other, op, index, index + len), + true => invert_other(&mut inverted, other, op, index, index + len), false => { // tracing::trace!("invert retain: {} by retain {} {}", op, len, // op.get_attributes()); @@ -452,7 +516,7 @@ where } } -fn invert_from_other( +fn invert_other( base: &mut Delta, other: &Delta, operation: &Operation, @@ -460,7 +524,7 @@ fn invert_from_other( end: usize, ) { tracing::trace!("invert op: {} [{}:{}]", operation, start, end); - let other_ops = DeltaIter::from_interval(other, Interval::new(start, end)).ops(); + let other_ops = DeltaIterator::from_interval(other, Interval::new(start, end)).ops(); other_ops.into_iter().for_each(|other_op| match operation { Operation::Delete(_n) => { // tracing::trace!("invert delete: {} by add {}", n, other_op); diff --git a/shared-lib/lib-ot/src/core/delta/delta_serde.rs b/shared-lib/lib-ot/src/core/delta/delta_serde.rs index ceac31ee58..7dff063211 100644 --- a/shared-lib/lib-ot/src/core/delta/delta_serde.rs +++ b/shared-lib/lib-ot/src/core/delta/delta_serde.rs @@ -1,4 +1,5 @@ -use crate::core::{Attributes, Delta}; +use crate::core::delta::Delta; +use crate::core::operation::Attributes; use serde::{ de::{SeqAccess, Visitor}, ser::SerializeSeq, diff --git a/shared-lib/lib-ot/src/core/delta/iterator.rs b/shared-lib/lib-ot/src/core/delta/iterator.rs index ccad56845d..ba9db58428 100644 --- a/shared-lib/lib-ot/src/core/delta/iterator.rs +++ b/shared-lib/lib-ot/src/core/delta/iterator.rs @@ -1,17 +1,17 @@ use super::cursor::*; -use crate::{ - core::{Attributes, Delta, Interval, Operation, NEW_LINE}, - rich_text::RichTextAttributes, -}; +use crate::core::delta::{Delta, NEW_LINE}; +use crate::core::interval::Interval; +use crate::core::operation::{Attributes, Operation}; +use crate::rich_text::RichTextAttributes; use std::ops::{Deref, DerefMut}; pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize; -pub struct DeltaIter<'a, T: Attributes> { - cursor: OpCursor<'a, T>, +pub struct DeltaIterator<'a, T: Attributes> { + cursor: DeltaCursor<'a, T>, } -impl<'a, T> DeltaIter<'a, T> +impl<'a, T> DeltaIterator<'a, T> where T: Attributes, { @@ -28,7 +28,7 @@ where } pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self { - let cursor = OpCursor::new(delta, interval); + let cursor = DeltaCursor::new(delta, interval); Self { cursor } } @@ -46,7 +46,7 @@ where } pub fn next_op(&mut self) -> Option> { - self.cursor.next_op() + self.cursor.get_next_op() } pub fn next_op_with_len(&mut self, len: usize) -> Option> { @@ -80,28 +80,28 @@ where } pub fn is_next_insert(&self) -> bool { - match self.cursor.next_iter_op() { + match self.cursor.next_op() { None => false, Some(op) => op.is_insert(), } } pub fn is_next_retain(&self) -> bool { - match self.cursor.next_iter_op() { + match self.cursor.next_op() { None => false, Some(op) => op.is_retain(), } } pub fn is_next_delete(&self) -> bool { - match self.cursor.next_iter_op() { + match self.cursor.next_op() { None => false, Some(op) => op.is_delete(), } } } -impl<'a, T> Iterator for DeltaIter<'a, T> +impl<'a, T> Iterator for DeltaIterator<'a, T> where T: Attributes, { @@ -112,7 +112,7 @@ where } pub fn is_empty_line_at_index(delta: &Delta, index: usize) -> bool { - let mut iter = DeltaIter::new(delta); + let mut iter = DeltaIterator::new(delta); let (prev, next) = (iter.next_op_with_len(index), iter.next_op()); if prev.is_none() { return true; @@ -128,7 +128,7 @@ pub fn is_empty_line_at_index(delta: &Delta, index: usize) - } pub struct AttributesIter<'a, T: Attributes> { - delta_iter: DeltaIter<'a, T>, + delta_iter: DeltaIterator<'a, T>, } impl<'a, T> AttributesIter<'a, T> @@ -141,7 +141,7 @@ where } pub fn from_interval(delta: &'a Delta, interval: Interval) -> Self { - let delta_iter = DeltaIter::from_interval(delta, interval); + let delta_iter = DeltaIterator::from_interval(delta, interval); Self { delta_iter } } @@ -157,7 +157,7 @@ impl<'a, T> Deref for AttributesIter<'a, T> where T: Attributes, { - type Target = DeltaIter<'a, T>; + type Target = DeltaIterator<'a, T>; fn deref(&self) -> &Self::Target { &self.delta_iter diff --git a/shared-lib/lib-ot/src/core/flowy_str.rs b/shared-lib/lib-ot/src/core/flowy_str.rs index 95cc1735cc..9e503672eb 100644 --- a/shared-lib/lib-ot/src/core/flowy_str.rs +++ b/shared-lib/lib-ot/src/core/flowy_str.rs @@ -177,7 +177,7 @@ impl<'a> FlowyUtf16CodePointIterator<'a> { } } -use crate::core::Interval; +use crate::core::interval::Interval; use std::str; impl<'a> Iterator for FlowyUtf16CodePointIterator<'a> { @@ -226,7 +226,8 @@ pub fn len_utf8_from_first_byte(b: u8) -> usize { #[cfg(test)] mod tests { - use crate::core::{FlowyStr, Interval}; + use crate::core::flowy_str::FlowyStr; + use crate::core::interval::Interval; #[test] fn flowy_str_code_unit() { diff --git a/shared-lib/lib-ot/src/core/interval.rs b/shared-lib/lib-ot/src/core/interval.rs index a6f3131b6a..cc907ec3ea 100644 --- a/shared-lib/lib-ot/src/core/interval.rs +++ b/shared-lib/lib-ot/src/core/interval.rs @@ -157,7 +157,7 @@ impl From> for Interval { #[cfg(test)] mod tests { - use crate::core::Interval; + use crate::core::interval::Interval; #[test] fn contains() { diff --git a/shared-lib/lib-ot/src/core/mod.rs b/shared-lib/lib-ot/src/core/mod.rs index b5bc594246..72a6dd9b74 100644 --- a/shared-lib/lib-ot/src/core/mod.rs +++ b/shared-lib/lib-ot/src/core/mod.rs @@ -3,28 +3,7 @@ mod flowy_str; mod interval; mod operation; -use crate::errors::OTError; pub use delta::*; pub use flowy_str::*; pub use interval::*; pub use operation::*; - -pub trait OperationTransformable { - /// Merges the operation with `other` into one operation while preserving - /// the changes of both. - fn compose(&self, other: &Self) -> Result - where - Self: Sized; - /// Transforms two operations a and b that happened concurrently and - /// produces two operations a' and b'. - /// (a', b') = a.transform(b) - /// a.compose(b') = b.compose(a') - fn transform(&self, other: &Self) -> Result<(Self, Self), OTError> - where - Self: Sized; - /// Inverts the operation with `other` to produces undo operation. - /// undo = a.invert(b) - /// new_b = b.compose(a) - /// b = new_b.compose(undo) - fn invert(&self, other: &Self) -> Self; -} diff --git a/shared-lib/lib-ot/src/core/operation/builder.rs b/shared-lib/lib-ot/src/core/operation/builder.rs index dc7b6dd7d9..a42ebdecb3 100644 --- a/shared-lib/lib-ot/src/core/operation/builder.rs +++ b/shared-lib/lib-ot/src/core/operation/builder.rs @@ -1,40 +1,38 @@ -use crate::{ - core::{Attributes, Operation, PlainTextAttributes}, - rich_text::RichTextAttributes, -}; +use crate::core::operation::{Attributes, Operation, PlainTextAttributes}; +use crate::rich_text::RichTextAttributes; -pub type RichTextOpBuilder = OpBuilder; -pub type PlainTextOpBuilder = OpBuilder; +pub type RichTextOpBuilder = OperationBuilder; +pub type PlainTextOpBuilder = OperationBuilder; -pub struct OpBuilder { +pub struct OperationBuilder { ty: Operation, attrs: T, } -impl OpBuilder +impl OperationBuilder where T: Attributes, { - pub fn new(ty: Operation) -> OpBuilder { - OpBuilder { + pub fn new(ty: Operation) -> OperationBuilder { + OperationBuilder { ty, attrs: T::default(), } } - pub fn retain(n: usize) -> OpBuilder { - OpBuilder::new(Operation::Retain(n.into())) + pub fn retain(n: usize) -> OperationBuilder { + OperationBuilder::new(Operation::Retain(n.into())) } - pub fn delete(n: usize) -> OpBuilder { - OpBuilder::new(Operation::Delete(n)) + pub fn delete(n: usize) -> OperationBuilder { + OperationBuilder::new(Operation::Delete(n)) } - pub fn insert(s: &str) -> OpBuilder { - OpBuilder::new(Operation::Insert(s.into())) + pub fn insert(s: &str) -> OperationBuilder { + OperationBuilder::new(Operation::Insert(s.into())) } - pub fn attributes(mut self, attrs: T) -> OpBuilder { + pub fn attributes(mut self, attrs: T) -> OperationBuilder { self.attrs = attrs; self } diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 82228c19fc..8ff47d95e8 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -1,8 +1,9 @@ -use crate::{ - core::{FlowyStr, Interval, OpBuilder, OperationTransformable}, - errors::OTError, -}; +use crate::core::flowy_str::FlowyStr; +use crate::core::interval::Interval; +use crate::core::operation::OperationBuilder; +use crate::errors::OTError; use serde::{Deserialize, Serialize, __private::Formatter}; +use std::fmt::Display; use std::{ cmp::min, fmt, @@ -10,13 +11,73 @@ use std::{ ops::{Deref, DerefMut}, }; -pub trait Attributes: fmt::Display + Eq + PartialEq + Default + Clone + Debug + OperationTransformable { - fn is_empty(&self) -> bool; +pub trait OperationTransformable { + /// Merges the operation with `other` into one operation while preserving + /// the changes of both. + /// + /// # Arguments + /// + /// * `other`: The delta gonna to merge. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{OperationTransformable, PlainTextDeltaBuilder}; + /// let document = PlainTextDeltaBuilder::new().build(); + /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); + /// let new_document = document.compose(&delta).unwrap(); + /// assert_eq!(new_document.to_str().unwrap(), "abc".to_owned()); + /// ``` + fn compose(&self, other: &Self) -> Result + where + Self: Sized; - // Remove the empty attribute which value is None. - fn remove_empty(&mut self); + /// Transforms two operations a and b that happened concurrently and + /// produces two operations a' and b'. + /// (a', b') = a.transform(b) + /// a.compose(b') = b.compose(a') + /// + fn transform(&self, other: &Self) -> Result<(Self, Self), OTError> + where + Self: Sized; - fn extend_other(&mut self, other: Self); + /// Return the invert delta from the other. It can be used to do the undo operation. + /// + /// # Arguments + /// + /// * `other`: Generate the undo delta for [Other]. [Other] can compose the undo delta to return + /// to the previous state. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{OperationTransformable, PlainTextDeltaBuilder}; + /// let original_document = PlainTextDeltaBuilder::new().build(); + /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); + /// + /// let undo_delta = delta.invert(&original_document); + /// let new_document = original_document.compose(&delta).unwrap(); + /// let document = new_document.compose(&undo_delta).unwrap(); + /// + /// assert_eq!(original_document, document); + /// + /// ``` + fn invert(&self, other: &Self) -> Self; +} + +pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransformable { + fn is_empty(&self) -> bool { + true + } + + /// Remove the empty attribute which value is None. + fn remove_empty(&mut self) { + // Do nothing + } + + fn extend_other(&mut self, _other: Self) { + // Do nothing + } } #[derive(Debug, Clone, Eq, PartialEq)] @@ -77,22 +138,22 @@ where let right; match self { Operation::Delete(n) => { - left = Some(OpBuilder::::delete(index).build()); - right = Some(OpBuilder::::delete(*n - index).build()); + left = Some(OperationBuilder::::delete(index).build()); + right = Some(OperationBuilder::::delete(*n - index).build()); } Operation::Retain(retain) => { - left = Some(OpBuilder::::delete(index).build()); - right = Some(OpBuilder::::delete(retain.n - index).build()); + left = Some(OperationBuilder::::delete(index).build()); + right = Some(OperationBuilder::::delete(retain.n - index).build()); } Operation::Insert(insert) => { let attributes = self.get_attributes(); left = Some( - OpBuilder::::insert(&insert.s[0..index]) + OperationBuilder::::insert(&insert.s[0..index]) .attributes(attributes.clone()) .build(), ); right = Some( - OpBuilder::::insert(&insert.s[index..insert.utf16_size()]) + OperationBuilder::::insert(&insert.s[index..insert.utf16_size()]) .attributes(attributes) .build(), ); @@ -104,16 +165,18 @@ where pub fn shrink(&self, interval: Interval) -> Option> { let op = match self { - Operation::Delete(n) => OpBuilder::delete(min(*n, interval.size())).build(), - Operation::Retain(retain) => OpBuilder::retain(min(retain.n, interval.size())) + Operation::Delete(n) => OperationBuilder::delete(min(*n, interval.size())).build(), + Operation::Retain(retain) => OperationBuilder::retain(min(retain.n, interval.size())) .attributes(retain.attributes.clone()) .build(), Operation::Insert(insert) => { if interval.start > insert.utf16_size() { - OpBuilder::insert("").build() + OperationBuilder::insert("").build() } else { let s = insert.s.sub_str(interval).unwrap_or_else(|| "".to_owned()); - OpBuilder::insert(&s).attributes(insert.attributes.clone()).build() + OperationBuilder::insert(&s) + .attributes(insert.attributes.clone()) + .build() } } }; @@ -212,7 +275,7 @@ where self.n += n; None } else { - Some(OpBuilder::retain(n).attributes(attributes).build()) + Some(OperationBuilder::retain(n).attributes(attributes).build()) } } @@ -296,7 +359,7 @@ where self.s += s; None } else { - Some(OpBuilder::::insert(s).attributes(attributes).build()) + Some(OperationBuilder::::insert(s).attributes(attributes).build()) } } @@ -346,15 +409,7 @@ impl fmt::Display for PlainTextAttributes { } } -impl Attributes for PlainTextAttributes { - fn is_empty(&self) -> bool { - true - } - - fn remove_empty(&mut self) {} - - fn extend_other(&mut self, _other: Self) {} -} +impl Attributes for PlainTextAttributes {} impl OperationTransformable for PlainTextAttributes { fn compose(&self, _other: &Self) -> Result { diff --git a/shared-lib/lib-ot/src/core/operation/operation_serde.rs b/shared-lib/lib-ot/src/core/operation/operation_serde.rs index aefb909d0a..d029fb0e16 100644 --- a/shared-lib/lib-ot/src/core/operation/operation_serde.rs +++ b/shared-lib/lib-ot/src/core/operation/operation_serde.rs @@ -1,4 +1,5 @@ -use crate::core::{Attributes, FlowyStr, Insert, Operation, Retain}; +use crate::core::flowy_str::FlowyStr; +use crate::core::operation::{Attributes, Insert, Operation, Retain}; use serde::{ de, de::{MapAccess, SeqAccess, Visitor}, diff --git a/shared-lib/lib-ot/src/rich_text/attributes.rs b/shared-lib/lib-ot/src/rich_text/attributes.rs index d70e23228b..05d37317d2 100644 --- a/shared-lib/lib-ot/src/rich_text/attributes.rs +++ b/shared-lib/lib-ot/src/rich_text/attributes.rs @@ -1,10 +1,6 @@ #![allow(non_snake_case)] -use crate::{ - block_attribute, - core::{Attributes, Operation, OperationTransformable}, - errors::OTError, - ignore_attribute, inline_attribute, list_attribute, -}; +use crate::core::{Attributes, Operation, OperationTransformable}; +use crate::{block_attribute, errors::OTError, ignore_attribute, inline_attribute, list_attribute}; use lazy_static::lazy_static; use std::{ collections::{HashMap, HashSet}, diff --git a/shared-lib/lib-ot/src/rich_text/delta.rs b/shared-lib/lib-ot/src/rich_text/delta.rs index 99cb35f2bc..3a60cf7b02 100644 --- a/shared-lib/lib-ot/src/rich_text/delta.rs +++ b/shared-lib/lib-ot/src/rich_text/delta.rs @@ -1,7 +1,5 @@ -use crate::{ - core::{Delta, DeltaBuilder}, - rich_text::RichTextAttributes, -}; +use crate::core::{Delta, DeltaBuilder}; +use crate::rich_text::RichTextAttributes; pub type RichTextDelta = Delta; pub type RichTextDeltaBuilder = DeltaBuilder; From dd71acf843f6aa4d5697b0480926e882e136dccd Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 24 Jul 2022 18:10:29 +0800 Subject: [PATCH 064/112] chore: rename some function & add more documentation --- frontend/rust-lib/flowy-folder/src/manager.rs | 2 +- .../src/services/folder_editor.rs | 8 ++--- .../src/services/persistence/mod.rs | 2 +- .../flowy-folder/src/services/web_socket.rs | 8 ++--- frontend/rust-lib/flowy-grid/src/manager.rs | 4 +-- .../src/services/block_revision_editor.rs | 8 ++--- .../flowy-grid/src/services/grid_editor.rs | 8 ++--- .../src/services/persistence/migration.rs | 2 +- .../flowy-revision/src/conflict_resolve.rs | 8 ++--- .../rust-lib/flowy-text-block/src/editor.rs | 2 +- .../rust-lib/flowy-text-block/src/queue.rs | 4 +-- .../flowy-text-block/tests/document/script.rs | 2 +- .../tests/editor/attribute_test.rs | 12 +++---- .../flowy-text-block/tests/editor/mod.rs | 26 ++++++++-------- .../flowy-text-block/tests/editor/op_test.rs | 2 +- .../tests/editor/serde_test.rs | 8 ++--- .../src/client_document/default/mod.rs | 6 ++-- .../src/client_document/document_pad.rs | 10 +++--- .../flowy-sync/src/client_folder/builder.rs | 10 +++--- .../src/client_folder/folder_pad.rs | 6 ++-- .../src/client_grid/grid_block_revsion_pad.rs | 30 +++++++++--------- .../src/client_grid/grid_revision_pad.rs | 18 +++++------ .../flowy-sync/src/entities/revision.rs | 2 +- .../flowy-sync/src/entities/text_block.rs | 2 +- .../src/server_document/document_pad.rs | 2 +- .../src/server_folder/folder_manager.rs | 4 +-- .../src/server_folder/folder_pad.rs | 6 ++-- shared-lib/flowy-sync/src/util.rs | 4 +-- shared-lib/lib-ot/src/core/delta/builder.rs | 4 +-- shared-lib/lib-ot/src/core/delta/delta.rs | 21 +++++++------ .../lib-ot/src/core/operation/builder.rs | 4 +-- .../lib-ot/src/core/operation/operation.rs | 31 ++++++++++++------- 32 files changed, 139 insertions(+), 127 deletions(-) diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 356ff15897..8850024f25 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -215,7 +215,7 @@ impl DefaultFolderBuilder { for app in workspace_rev.apps.iter() { for (index, view) in app.belongings.iter().enumerate() { let view_data = if index == 0 { - initial_read_me().to_delta_str() + initial_read_me().to_json_str() } else { initial_quill_delta_string() }; diff --git a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs index b69b303fa1..6fb0ebf565 100644 --- a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs +++ b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs @@ -10,7 +10,7 @@ use flowy_sync::{ entities::{revision::Revision, ws_data::ServerRevisionWSData}, }; use lib_infra::future::FutureResult; -use lib_ot::core::PlainTextAttributes; +use lib_ot::core::PhantomAttributes; use parking_lot::RwLock; use std::sync::Arc; @@ -80,7 +80,7 @@ impl FolderEditor { pub(crate) fn apply_change(&self, change: FolderChange) -> FlowyResult<()> { let FolderChange { delta, md5 } = change; let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_delta_bytes(); + let delta_data = delta.to_json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -132,7 +132,7 @@ impl FolderEditor { pub struct FolderRevisionCompactor(); impl RevisionCompactor for FolderRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { - let delta = make_delta_from_revisions::(revisions)?; - Ok(delta.to_delta_bytes()) + let delta = make_delta_from_revisions::(revisions)?; + Ok(delta.to_json_bytes()) } } diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs index 5676db54da..ee930bd6ff 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs @@ -110,7 +110,7 @@ impl FolderPersistence { pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> { let pool = self.database.db_pool()?; let json = folder.to_json()?; - let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_delta_bytes(); + let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_json_bytes(); let revision = Revision::initial_revision(user_id, folder_id.as_ref(), delta_data); let record = RevisionRecord { revision, diff --git a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs index 75db905d63..eac429dc1f 100644 --- a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs +++ b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs @@ -10,7 +10,7 @@ use flowy_sync::{ }, }; use lib_infra::future::{BoxResultFuture, FutureResult}; -use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta}; +use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta}; use parking_lot::RwLock; use std::{sync::Arc, time::Duration}; @@ -24,7 +24,7 @@ pub(crate) async fn make_folder_ws_manager( ) -> Arc { let ws_data_provider = Arc::new(WSDataProvider::new(folder_id, Arc::new(rev_manager.clone()))); let resolver = Arc::new(FolderConflictResolver { folder_pad }); - let conflict_controller = ConflictController::::new( + let conflict_controller = ConflictController::::new( user_id, resolver, Arc::new(ws_data_provider.clone()), @@ -55,7 +55,7 @@ struct FolderConflictResolver { folder_pad: Arc>, } -impl ConflictResolver for FolderConflictResolver { +impl ConflictResolver for FolderConflictResolver { fn compose_delta(&self, delta: PlainTextDelta) -> BoxResultFuture { let folder_pad = self.folder_pad.clone(); Box::pin(async move { @@ -67,7 +67,7 @@ impl ConflictResolver for FolderConflictResolver { fn transform_delta( &self, delta: PlainTextDelta, - ) -> BoxResultFuture, FlowyError> { + ) -> BoxResultFuture, FlowyError> { let folder_pad = self.folder_pad.clone(); Box::pin(async move { let read_guard = folder_pad.read(); diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 320f18b560..eadd1e47fd 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -192,7 +192,7 @@ pub async fn make_grid_view_data( // Create grid's block let grid_block_delta = make_grid_block_delta(block_meta_data); - let block_delta_data = grid_block_delta.to_delta_bytes(); + let block_delta_data = grid_block_delta.to_json_bytes(); let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, block_id, block_delta_data).into(); let _ = grid_manager.create_grid_block(&block_id, repeated_revision).await?; @@ -202,7 +202,7 @@ pub async fn make_grid_view_data( // Create grid let grid_meta_delta = make_grid_delta(&grid_rev); - let grid_delta_data = grid_meta_delta.to_delta_bytes(); + let grid_delta_data = grid_meta_delta.to_json_bytes(); let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, grid_delta_data.clone()).into(); let _ = grid_manager.create_grid(view_id, repeated_revision).await?; diff --git a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs index f74075ec6e..19f3a885cb 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs @@ -7,7 +7,7 @@ use flowy_sync::client_grid::{GridBlockMetaChange, GridBlockRevisionPad}; use flowy_sync::entities::revision::Revision; use flowy_sync::util::make_delta_from_revisions; use lib_infra::future::FutureResult; -use lib_ot::core::PlainTextAttributes; +use lib_ot::core::PhantomAttributes; use std::borrow::Cow; use std::sync::Arc; use tokio::sync::RwLock; @@ -161,7 +161,7 @@ impl GridBlockRevisionEditor { let GridBlockMetaChange { delta, md5 } = change; let user_id = self.user_id.clone(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_delta_bytes(); + let delta_data = delta.to_json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -200,7 +200,7 @@ impl RevisionObjectBuilder for GridBlockMetaPadBuilder { pub struct GridBlockRevisionCompactor(); impl RevisionCompactor for GridBlockRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { - let delta = make_delta_from_revisions::(revisions)?; - Ok(delta.to_delta_bytes()) + let delta = make_delta_from_revisions::(revisions)?; + Ok(delta.to_json_bytes()) } } 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 572665bd0c..f185c907a7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -21,7 +21,7 @@ use flowy_sync::entities::revision::Revision; use flowy_sync::errors::CollaborateResult; use flowy_sync::util::make_delta_from_revisions; use lib_infra::future::FutureResult; -use lib_ot::core::PlainTextAttributes; +use lib_ot::core::PhantomAttributes; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; @@ -573,7 +573,7 @@ impl GridRevisionEditor { let GridChangeset { delta, md5 } = change; let user_id = self.user.user_id()?; let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_delta_bytes(); + let delta_data = delta.to_json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -664,8 +664,8 @@ impl RevisionCloudService for GridRevisionCloudService { pub struct GridRevisionCompactor(); impl RevisionCompactor for GridRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { - let delta = make_delta_from_revisions::(revisions)?; - Ok(delta.to_delta_bytes()) + let delta = make_delta_from_revisions::(revisions)?; + Ok(delta.to_json_bytes()) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs index 026ba3bc20..9b24d03fda 100644 --- a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs @@ -48,7 +48,7 @@ impl GridMigration { let pool = self.database.db_pool()?; let grid_rev_pad = self.get_grid_revision_pad(grid_id).await?; let json = grid_rev_pad.json_str()?; - let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_delta_bytes(); + let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_json_bytes(); let revision = Revision::initial_revision(&user_id, grid_id, delta_data); let record = RevisionRecord::new(revision); // diff --git a/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs index 0a63f37f3e..5e89e7db32 100644 --- a/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs +++ b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs @@ -9,7 +9,7 @@ use flowy_sync::{ util::make_delta_from_revisions, }; use lib_infra::future::BoxResultFuture; -use lib_ot::core::{Attributes, Delta, PlainTextAttributes}; +use lib_ot::core::{Attributes, Delta, PhantomAttributes}; use lib_ot::rich_text::RichTextAttributes; use serde::de::DeserializeOwned; use std::{convert::TryFrom, sync::Arc}; @@ -31,7 +31,7 @@ pub trait ConflictRevisionSink: Send + Sync + 'static { } pub type RichTextConflictController = ConflictController; -pub type PlainTextConflictController = ConflictController; +pub type PlainTextConflictController = ConflictController; pub struct ConflictController where @@ -154,7 +154,7 @@ where &rev_manager.object_id, base_rev_id, rev_id, - client_delta.to_delta_bytes(), + client_delta.to_json_bytes(), user_id, md5.clone(), ); @@ -166,7 +166,7 @@ where &rev_manager.object_id, base_rev_id, rev_id, - server_delta.to_delta_bytes(), + server_delta.to_json_bytes(), user_id, md5, ); diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 6fed85c913..2a52f43778 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -238,7 +238,7 @@ impl RevisionObjectBuilder for TextBlockInfoBuilder { Result::::Ok(DocumentPB { block_id: object_id.to_owned(), - text: delta.to_delta_str(), + text: delta.to_json_str(), rev_id, base_rev_id, }) diff --git a/frontend/rust-lib/flowy-text-block/src/queue.rs b/frontend/rust-lib/flowy-text-block/src/queue.rs index 343ad11e7b..072c810d9d 100644 --- a/frontend/rust-lib/flowy-text-block/src/queue.rs +++ b/frontend/rust-lib/flowy-text-block/src/queue.rs @@ -175,7 +175,7 @@ impl EditBlockQueue { } async fn save_local_delta(&self, delta: RichTextDelta, md5: String) -> Result { - let delta_data = delta.to_delta_bytes(); + let delta_data = delta.to_json_bytes(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); let user_id = self.user.user_id()?; let revision = Revision::new( @@ -195,7 +195,7 @@ pub(crate) struct TextBlockRevisionCompactor(); impl RevisionCompactor for TextBlockRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; - Ok(delta.to_delta_bytes()) + Ok(delta.to_json_bytes()) } } diff --git a/frontend/rust-lib/flowy-text-block/tests/document/script.rs b/frontend/rust-lib/flowy-text-block/tests/document/script.rs index 1722724c3f..b3ce1cb9bd 100644 --- a/frontend/rust-lib/flowy-text-block/tests/document/script.rs +++ b/frontend/rust-lib/flowy-text-block/tests/document/script.rs @@ -75,7 +75,7 @@ impl TextBlockEditorTest { let delta = self.editor.text_block_delta().await.unwrap(); if expected_delta != delta { eprintln!("✅ expect: {}", expected,); - eprintln!("❌ receive: {}", delta.to_delta_str()); + eprintln!("❌ receive: {}", delta.to_json_str()); } assert_eq!(expected_delta, delta); } diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs index 037b36970b..6dcd372d47 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs @@ -762,19 +762,19 @@ fn attributes_preserve_list_format_on_merge() { #[test] fn delta_compose() { - let mut delta = RichTextDelta::from_delta_str(r#"[{"insert":"\n"}]"#).unwrap(); + let mut delta = RichTextDelta::from_json_str(r#"[{"insert":"\n"}]"#).unwrap(); let deltas = vec![ - RichTextDelta::from_delta_str(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), - RichTextDelta::from_delta_str(r#"[{"insert":"a"}]"#).unwrap(), - RichTextDelta::from_delta_str(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), - RichTextDelta::from_delta_str(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), + RichTextDelta::from_json_str(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), + RichTextDelta::from_json_str(r#"[{"insert":"a"}]"#).unwrap(), + RichTextDelta::from_json_str(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), + RichTextDelta::from_json_str(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), ]; for d in deltas { delta = delta.compose(&d).unwrap(); } assert_eq!( - delta.to_delta_str(), + delta.to_json_str(), r#"[{"insert":"a"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\n"}]"# ); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs index 676b9a1cb0..a6b58ab39b 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs @@ -108,20 +108,20 @@ impl TestBuilder { TestOp::Insert(delta_i, s, index) => { let document = &mut self.documents[*delta_i]; let delta = document.insert(*index, s).unwrap(); - tracing::debug!("Insert delta: {}", delta.to_delta_str()); + tracing::debug!("Insert delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Delete(delta_i, iv) => { let document = &mut self.documents[*delta_i]; let delta = document.replace(*iv, "").unwrap(); - tracing::trace!("Delete delta: {}", delta.to_delta_str()); + tracing::trace!("Delete delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Replace(delta_i, iv, s) => { let document = &mut self.documents[*delta_i]; let delta = document.replace(*iv, s).unwrap(); - tracing::trace!("Replace delta: {}", delta.to_delta_str()); + tracing::trace!("Replace delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::InsertBold(delta_i, s, iv) => { @@ -133,7 +133,7 @@ impl TestBuilder { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Bold(*enable); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Bold delta: {}", delta.to_delta_str()); + tracing::trace!("Bold delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Italic(delta_i, iv, enable) => { @@ -143,28 +143,28 @@ impl TestBuilder { false => RichTextAttribute::Italic(false), }; let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Italic delta: {}", delta.to_delta_str()); + tracing::trace!("Italic delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Header(delta_i, iv, level) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Header(*level); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Header delta: {}", delta.to_delta_str()); + tracing::trace!("Header delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Link(delta_i, iv, link) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Link(link.to_owned()); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Link delta: {}", delta.to_delta_str()); + tracing::trace!("Link delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Bullet(delta_i, iv, enable) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Bullet(*enable); let delta = document.format(*iv, attribute).unwrap(); - tracing::debug!("Bullet delta: {}", delta.to_delta_str()); + tracing::debug!("Bullet delta: {}", delta.to_json_str()); self.deltas.insert(*delta_i, Some(delta)); } @@ -194,15 +194,15 @@ impl TestBuilder { let delta_a = &self.documents[*delta_a_i].delta(); let delta_b = &self.documents[*delta_b_i].delta(); tracing::debug!("Invert: "); - tracing::debug!("a: {}", delta_a.to_delta_str()); - tracing::debug!("b: {}", delta_b.to_delta_str()); + tracing::debug!("a: {}", delta_a.to_json_str()); + tracing::debug!("b: {}", delta_b.to_json_str()); let (_, b_prime) = delta_a.transform(delta_b).unwrap(); let undo = b_prime.invert(delta_a); let new_delta = delta_a.compose(&b_prime).unwrap(); - tracing::debug!("new delta: {}", new_delta.to_delta_str()); - tracing::debug!("undo delta: {}", undo.to_delta_str()); + tracing::debug!("new delta: {}", new_delta.to_json_str()); + tracing::debug!("undo delta: {}", undo.to_json_str()); let new_delta_after_undo = new_delta.compose(&undo).unwrap(); @@ -238,7 +238,7 @@ impl TestBuilder { } TestOp::AssertPrimeJson(doc_i, expected) => { - let prime_json = self.primes[*doc_i].as_ref().unwrap().to_delta_str(); + let prime_json = self.primes[*doc_i].as_ref().unwrap().to_json_str(); let expected_prime: RichTextDelta = serde_json::from_str(expected).unwrap(); let target_prime: RichTextDelta = serde_json::from_str(&prime_json).unwrap(); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index 47d3c5ebfe..f32e70942f 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -378,7 +378,7 @@ fn apply_test() { .insert(", AppFlowy") .build(); - let after_a = delta_a.to_str().unwrap(); + let after_a = delta_a.content_str().unwrap(); let after_b = delta_b.apply(&after_a).unwrap(); assert_eq!("hello, AppFlowy", &after_b); } diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs index ae9e57b3c6..6c578be6c3 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs @@ -65,7 +65,7 @@ fn delta_serialize_multi_attribute_test() { let json = serde_json::to_string(&delta).unwrap(); eprintln!("{}", json); - let delta_from_json = Delta::from_delta_str(&json).unwrap(); + let delta_from_json = Delta::from_json_str(&json).unwrap(); assert_eq!(delta_from_json, delta); } @@ -77,7 +77,7 @@ fn delta_deserialize_test() { {"retain":2,"attributes":{"italic":"true","bold":"true"}}, {"retain":2,"attributes":{"italic":true,"bold":true}} ]"#; - let delta = RichTextDelta::from_delta_str(json).unwrap(); + let delta = RichTextDelta::from_json_str(json).unwrap(); eprintln!("{}", delta); } @@ -86,13 +86,13 @@ fn delta_deserialize_null_test() { let json = r#"[ {"retain":7,"attributes":{"bold":null}} ]"#; - let delta1 = RichTextDelta::from_delta_str(json).unwrap(); + let delta1 = RichTextDelta::from_json_str(json).unwrap(); let mut attribute = RichTextAttribute::Bold(true); attribute.value = RichTextAttributeValue(None); let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); - assert_eq!(delta2.to_delta_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); + assert_eq!(delta2.to_json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); assert_eq!(delta1, delta2); } diff --git a/shared-lib/flowy-sync/src/client_document/default/mod.rs b/shared-lib/flowy-sync/src/client_document/default/mod.rs index f5fb180571..582e3eac2e 100644 --- a/shared-lib/flowy-sync/src/client_document/default/mod.rs +++ b/shared-lib/flowy-sync/src/client_document/default/mod.rs @@ -7,13 +7,13 @@ pub fn initial_quill_delta() -> RichTextDelta { #[inline] pub fn initial_quill_delta_string() -> String { - initial_quill_delta().to_delta_str() + initial_quill_delta().to_json_str() } #[inline] pub fn initial_read_me() -> RichTextDelta { let json = include_str!("READ_ME.json"); - RichTextDelta::from_delta_str(json).unwrap() + RichTextDelta::from_json_str(json).unwrap() } #[cfg(test)] @@ -22,6 +22,6 @@ mod tests { #[test] fn load_read_me() { - println!("{}", initial_read_me().to_delta_str()); + println!("{}", initial_read_me().to_json_str()); } } diff --git a/shared-lib/flowy-sync/src/client_document/document_pad.rs b/shared-lib/flowy-sync/src/client_document/document_pad.rs index 72b52f6415..d63d2194ad 100644 --- a/shared-lib/flowy-sync/src/client_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/client_document/document_pad.rs @@ -55,16 +55,16 @@ impl ClientDocument { } pub fn from_json(json: &str) -> Result { - let delta = RichTextDelta::from_delta_str(json)?; + let delta = RichTextDelta::from_json_str(json)?; Ok(Self::from_delta(delta)) } pub fn delta_str(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } pub fn to_bytes(&self) -> Bytes { - self.delta.to_delta_bytes() + self.delta.to_json_bytes() } pub fn to_plain_string(&self) -> String { @@ -85,7 +85,7 @@ impl ClientDocument { } pub fn set_delta(&mut self, data: RichTextDelta) { - tracing::trace!("document: {}", data.to_delta_str()); + tracing::trace!("document: {}", data.to_json_str()); self.delta = data; match &self.notify { @@ -97,7 +97,7 @@ impl ClientDocument { } pub fn compose_delta(&mut self, delta: RichTextDelta) -> Result<(), CollaborateError> { - tracing::trace!("{} compose {}", &self.delta.to_delta_str(), delta.to_delta_str()); + tracing::trace!("{} compose {}", &self.delta.to_json_str(), delta.to_json_str()); let composed_delta = self.delta.compose(&delta)?; let mut undo_delta = delta.invert(&self.delta); diff --git a/shared-lib/flowy-sync/src/client_folder/builder.rs b/shared-lib/flowy-sync/src/client_folder/builder.rs index 4c27f278f5..b055f91fb8 100644 --- a/shared-lib/flowy-sync/src/client_folder/builder.rs +++ b/shared-lib/flowy-sync/src/client_folder/builder.rs @@ -7,7 +7,7 @@ use crate::{ }; use flowy_folder_data_model::revision::{TrashRevision, WorkspaceRevision}; -use lib_ot::core::{PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -41,9 +41,9 @@ impl FolderPadBuilder { } // TODO: Reconvert from history if delta.to_str() failed. - let folder_json = delta.to_str()?; - let mut folder: FolderPad = serde_json::from_str(&folder_json).map_err(|e| { - tracing::error!("Deserialize folder from json failed: {}", folder_json); + let content = delta.content_str()?; + let mut folder: FolderPad = serde_json::from_str(&content).map_err(|e| { + tracing::error!("Deserialize folder from {} failed", content); return CollaborateError::internal().context(format!("Deserialize delta to folder failed: {}", e)); })?; folder.delta = delta; @@ -51,7 +51,7 @@ impl FolderPadBuilder { } pub(crate) fn build_with_revisions(self, revisions: Vec) -> CollaborateResult { - let folder_delta: FolderDelta = make_delta_from_revisions::(revisions)?; + let folder_delta: FolderDelta = make_delta_from_revisions::(revisions)?; self.build_with_delta(folder_delta) } diff --git a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs index f821c03e6f..0cbc33598e 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs @@ -295,7 +295,7 @@ impl FolderPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_delta_bytes()) + md5(&self.delta.to_json_bytes()) } pub fn to_json(&self) -> CollaborateResult { @@ -315,7 +315,7 @@ impl FolderPad { Some(_) => { let old = cloned_self.to_json()?; let new = self.to_json()?; - match cal_diff::(old, new) { + match cal_diff::(old, new) { None => Ok(None), Some(delta) => { self.delta = self.delta.compose(&delta)?; @@ -350,7 +350,7 @@ impl FolderPad { Some(_) => { let old = cloned_self.to_json()?; let new = self.to_json()?; - match cal_diff::(old, new) { + match cal_diff::(old, new) { None => Ok(None), Some(delta) => { self.delta = self.delta.compose(&delta)?; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs index 16b98dc7fc..cea6d7fd03 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs @@ -4,7 +4,7 @@ use crate::util::{cal_diff, make_delta_from_revisions}; use flowy_grid_data_model::revision::{ gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision, }; -use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; @@ -46,7 +46,7 @@ impl GridBlockRevisionPad { } pub fn from_delta(delta: GridBlockRevisionDelta) -> CollaborateResult { - let s = delta.to_str()?; + let s = delta.content_str()?; let block_revision: GridBlockRevision = serde_json::from_str(&s).map_err(|e| { let msg = format!("Deserialize delta to block meta failed: {}", e); tracing::error!("{}", s); @@ -56,7 +56,7 @@ impl GridBlockRevisionPad { } pub fn from_revisions(_grid_id: &str, revisions: Vec) -> CollaborateResult { - let block_delta: GridBlockRevisionDelta = make_delta_from_revisions::(revisions)?; + let block_delta: GridBlockRevisionDelta = make_delta_from_revisions::(revisions)?; Self::from_delta(block_delta) } @@ -195,10 +195,10 @@ impl GridBlockRevisionPad { Some(_) => { let old = cloned_self.to_json()?; let new = self.to_json()?; - match cal_diff::(old, new) { + match cal_diff::(old, new) { None => Ok(None), Some(delta) => { - tracing::trace!("[GridBlockMeta] Composing delta {}", delta.to_delta_str()); + tracing::trace!("[GridBlockMeta] Composing delta {}", delta.to_json_str()); // tracing::debug!( // "[GridBlockMeta] current delta: {}", // self.delta.to_str().unwrap_or_else(|_| "".to_string()) @@ -231,11 +231,11 @@ impl GridBlockRevisionPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_delta_bytes()) + md5(&self.delta.to_json_bytes()) } pub fn delta_str(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } } @@ -252,7 +252,7 @@ pub fn make_grid_block_delta(block_rev: &GridBlockRevision) -> GridBlockRevision pub fn make_grid_block_revisions(user_id: &str, grid_block_meta_data: &GridBlockRevision) -> RepeatedRevision { let delta = make_grid_block_delta(grid_block_meta_data); - let bytes = delta.to_delta_bytes(); + let bytes = delta.to_json_bytes(); let revision = Revision::initial_revision(user_id, &grid_block_meta_data.block_id, bytes); revision.into() } @@ -289,7 +289,7 @@ mod tests { let change = pad.add_row_rev(row.clone(), None).unwrap().unwrap(); assert_eq!(pad.rows.first().unwrap().as_ref(), &row); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); } @@ -303,19 +303,19 @@ mod tests { let change = pad.add_row_rev(row_1.clone(), None).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); let change = pad.add_row_rev(row_2.clone(), None).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":90},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); let change = pad.add_row_rev(row_3.clone(), Some("2".to_string())).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":157},{"insert":",{\"id\":\"3\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); @@ -381,7 +381,7 @@ mod tests { let _ = pad.add_row_rev(row.clone(), None).unwrap().unwrap(); let change = pad.delete_rows(vec![Cow::Borrowed(&row.id)]).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":24},{"delete":66},{"retain":2}]"# ); @@ -410,7 +410,7 @@ mod tests { let change = pad.update_row(changeset).unwrap().unwrap(); assert_eq!( - change.delta.to_delta_str(), + change.delta.to_json_str(), r#"[{"retain":69},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"# ); @@ -422,7 +422,7 @@ mod tests { fn test_pad() -> GridBlockRevisionPad { let delta = - GridBlockRevisionDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); + GridBlockRevisionDelta::from_json_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); GridBlockRevisionPad::from_delta(delta).unwrap() } } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index eaa6f1823a..d1232a261d 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -9,7 +9,7 @@ use flowy_grid_data_model::revision::{ GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision, }; use lib_infra::util::move_vec_element; -use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use std::collections::HashMap; use std::sync::Arc; @@ -52,8 +52,8 @@ impl GridRevisionPad { } pub fn from_delta(delta: GridRevisionDelta) -> CollaborateResult { - let s = delta.to_str()?; - let grid: GridRevision = serde_json::from_str(&s) + let content = delta.content_str()?; + let grid: GridRevision = serde_json::from_str(&content) .map_err(|e| CollaborateError::internal().context(format!("Deserialize delta to grid failed: {}", e)))?; Ok(Self { @@ -63,7 +63,7 @@ impl GridRevisionPad { } pub fn from_revisions(revisions: Vec) -> CollaborateResult { - let grid_delta: GridRevisionDelta = make_delta_from_revisions::(revisions)?; + let grid_delta: GridRevisionDelta = make_delta_from_revisions::(revisions)?; Self::from_delta(grid_delta) } @@ -457,15 +457,15 @@ impl GridRevisionPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_delta_bytes()) + md5(&self.delta.to_json_bytes()) } pub fn delta_str(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } pub fn delta_bytes(&self) -> Bytes { - self.delta.to_delta_bytes() + self.delta.to_json_bytes() } pub fn fields(&self) -> &[Arc] { @@ -482,7 +482,7 @@ impl GridRevisionPad { Some(_) => { let old = make_grid_rev_json_str(&cloned_grid)?; let new = self.json_str()?; - match cal_diff::(old, new) { + match cal_diff::(old, new) { None => Ok(None), Some(delta) => { self.delta = self.delta.compose(&delta)?; @@ -553,7 +553,7 @@ pub fn make_grid_delta(grid_rev: &GridRevision) -> GridRevisionDelta { pub fn make_grid_revisions(user_id: &str, grid_rev: &GridRevision) -> RepeatedRevision { let delta = make_grid_delta(grid_rev); - let bytes = delta.to_delta_bytes(); + let bytes = delta.to_json_bytes(); let revision = Revision::initial_revision(user_id, &grid_rev.grid_id, bytes); revision.into() } diff --git a/shared-lib/flowy-sync/src/entities/revision.rs b/shared-lib/flowy-sync/src/entities/revision.rs index d909efa3d5..408026607c 100644 --- a/shared-lib/flowy-sync/src/entities/revision.rs +++ b/shared-lib/flowy-sync/src/entities/revision.rs @@ -89,7 +89,7 @@ impl std::fmt::Debug for Revision { let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?; match RichTextDelta::from_bytes(&self.delta_data) { Ok(delta) => { - let _ = f.write_fmt(format_args!("delta {:?}", delta.to_delta_str()))?; + let _ = f.write_fmt(format_args!("delta {:?}", delta.to_json_str()))?; } Err(e) => { let _ = f.write_fmt(format_args!("delta {:?}", e))?; diff --git a/shared-lib/flowy-sync/src/entities/text_block.rs b/shared-lib/flowy-sync/src/entities/text_block.rs index 8753103369..91ff7e65c4 100644 --- a/shared-lib/flowy-sync/src/entities/text_block.rs +++ b/shared-lib/flowy-sync/src/entities/text_block.rs @@ -46,7 +46,7 @@ impl std::convert::TryFrom for DocumentPB { } let delta = RichTextDelta::from_bytes(&revision.delta_data)?; - let doc_json = delta.to_delta_str(); + let doc_json = delta.to_json_str(); Ok(DocumentPB { block_id: revision.object_id, diff --git a/shared-lib/flowy-sync/src/server_document/document_pad.rs b/shared-lib/flowy-sync/src/server_document/document_pad.rs index 1f4fa7bda1..d51919f048 100644 --- a/shared-lib/flowy-sync/src/server_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/server_document/document_pad.rs @@ -39,7 +39,7 @@ impl RevisionSyncObject for ServerDocument { } fn to_json(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } fn set_delta(&mut self, new_delta: Delta) { diff --git a/shared-lib/flowy-sync/src/server_folder/folder_manager.rs b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs index 16b753f50b..95e3c2330f 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_manager.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_manager.rs @@ -13,7 +13,7 @@ use crate::{ use async_stream::stream; use futures::stream::StreamExt; use lib_infra::future::BoxResultFuture; -use lib_ot::core::PlainTextAttributes; +use lib_ot::core::PhantomAttributes; use std::{collections::HashMap, fmt::Debug, sync::Arc}; use tokio::{ sync::{mpsc, oneshot, RwLock}, @@ -188,7 +188,7 @@ impl ServerFolderManager { } } -type FolderRevisionSynchronizer = RevisionSynchronizer; +type FolderRevisionSynchronizer = RevisionSynchronizer; struct OpenFolderHandler { folder_id: String, diff --git a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs index 09b4c9d048..29457eb65e 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs @@ -1,5 +1,5 @@ use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject}; -use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta}; +use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta}; pub struct ServerFolder { folder_id: String, @@ -15,7 +15,7 @@ impl ServerFolder { } } -impl RevisionSyncObject for ServerFolder { +impl RevisionSyncObject for ServerFolder { fn id(&self) -> &str { &self.folder_id } @@ -32,7 +32,7 @@ impl RevisionSyncObject for ServerFolder { } fn to_json(&self) -> String { - self.delta.to_delta_str() + self.delta.to_json_str() } fn set_delta(&mut self, new_delta: PlainTextDelta) { diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index c4504a806a..b845550137 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -149,7 +149,7 @@ pub fn make_folder_from_revisions_pb( folder_delta = folder_delta.compose(&delta)?; } - let text = folder_delta.to_delta_str(); + let text = folder_delta.to_json_str(); Ok(Some(FolderInfo { folder_id: folder_id.to_string(), text, @@ -183,7 +183,7 @@ pub fn make_document_from_revision_pbs( delta = delta.compose(&new_delta)?; } - let text = delta.to_delta_str(); + let text = delta.to_json_str(); Ok(Some(DocumentPB { block_id: doc_id.to_owned(), diff --git a/shared-lib/lib-ot/src/core/delta/builder.rs b/shared-lib/lib-ot/src/core/delta/builder.rs index 184284393a..9e67495da0 100644 --- a/shared-lib/lib-ot/src/core/delta/builder.rs +++ b/shared-lib/lib-ot/src/core/delta/builder.rs @@ -1,7 +1,7 @@ use crate::core::delta::{trim, Delta}; -use crate::core::operation::{Attributes, PlainTextAttributes}; +use crate::core::operation::{Attributes, PhantomAttributes}; -pub type PlainTextDeltaBuilder = DeltaBuilder; +pub type PlainTextDeltaBuilder = DeltaBuilder; /// A builder for creating new [Delta] objects. /// diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 6edf817bdf..2bff1a3edc 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -3,7 +3,7 @@ use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::core::delta::{DeltaIterator, MAX_IV_LEN}; use crate::core::flowy_str::FlowyStr; use crate::core::interval::Interval; -use crate::core::operation::{Attributes, Operation, OperationBuilder, OperationTransformable, PlainTextAttributes}; +use crate::core::operation::{Attributes, Operation, OperationBuilder, OperationTransformable, PhantomAttributes}; use bytes::Bytes; use serde::de::DeserializeOwned; use std::{ @@ -14,12 +14,15 @@ use std::{ str::FromStr, }; -pub type PlainTextDelta = Delta; +pub type PlainTextDelta = Delta; /// A [Delta] contains list of operations that consists of 'Retain', 'Delete' and 'Insert' operation. /// Check out the [Operation] for more details. It describes the document as a sequence of /// operations. /// +/// If the [T] supports 'serde', that will enable delta to serialize to JSON or deserialize from +/// a JSON string. +/// #[derive(Clone, Debug, PartialEq, Eq)] pub struct Delta { pub ops: Vec>, @@ -182,7 +185,7 @@ where /// .insert(", AppFlowy") /// .build(); /// - /// let after_a = delta_a.to_str().unwrap(); + /// let after_a = delta_a.content_str().unwrap(); /// let after_b = delta_b.apply(&after_a).unwrap(); /// assert_eq!("hello, AppFlowy", &after_b); /// ``` @@ -565,7 +568,7 @@ impl Delta where T: Attributes + DeserializeOwned, { - pub fn from_delta_str(json: &str) -> Result { + pub fn from_json_str(json: &str) -> Result { let delta = serde_json::from_str(json).map_err(|e| { tracing::trace!("Deserialize failed: {:?}", e); tracing::trace!("{:?}", json); @@ -576,7 +579,7 @@ where pub fn from_bytes>(bytes: B) -> Result { let json = str::from_utf8(bytes.as_ref())?.to_owned(); - let val = Self::from_delta_str(&json)?; + let val = Self::from_json_str(&json)?; Ok(val) } } @@ -585,16 +588,16 @@ impl Delta where T: Attributes + serde::Serialize, { - pub fn to_delta_str(&self) -> String { + pub fn to_json_str(&self) -> String { serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) } - pub fn to_str(&self) -> Result { + pub fn content_str(&self) -> Result { self.apply("") } - pub fn to_delta_bytes(&self) -> Bytes { - let json = self.to_delta_str(); + pub fn to_json_bytes(&self) -> Bytes { + let json = self.to_json_str(); Bytes::from(json.into_bytes()) } } diff --git a/shared-lib/lib-ot/src/core/operation/builder.rs b/shared-lib/lib-ot/src/core/operation/builder.rs index a42ebdecb3..c2cf774617 100644 --- a/shared-lib/lib-ot/src/core/operation/builder.rs +++ b/shared-lib/lib-ot/src/core/operation/builder.rs @@ -1,8 +1,8 @@ -use crate::core::operation::{Attributes, Operation, PlainTextAttributes}; +use crate::core::operation::{Attributes, Operation, PhantomAttributes}; use crate::rich_text::RichTextAttributes; pub type RichTextOpBuilder = OperationBuilder; -pub type PlainTextOpBuilder = OperationBuilder; +pub type PlainTextOpBuilder = OperationBuilder; pub struct OperationBuilder { ty: Operation, diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 8ff47d95e8..ac56025621 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -26,7 +26,7 @@ pub trait OperationTransformable { /// let document = PlainTextDeltaBuilder::new().build(); /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); /// let new_document = document.compose(&delta).unwrap(); - /// assert_eq!(new_document.to_str().unwrap(), "abc".to_owned()); + /// assert_eq!(new_document.content_str().unwrap(), "abc".to_owned()); /// ``` fn compose(&self, other: &Self) -> Result where @@ -65,6 +65,12 @@ pub trait OperationTransformable { fn invert(&self, other: &Self) -> Self; } +/// Each operation can carry attributes. For example, the [RichTextAttributes] has a list of key/value attributes. +/// Such as { bold: true, italic: true }. +/// +/// Because [Operation] is generic over the T, so you must specify the T. For example, the [PlainTextDelta]. It use +/// use [PhantomAttributes] as the T. [PhantomAttributes] does nothing, just a phantom. +/// pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransformable { fn is_empty(&self) -> bool { true @@ -80,6 +86,14 @@ pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + Opera } } +/// [Operation] consists of three types. +/// * Delete +/// * Retain +/// * Insert +/// +/// The [T] should support serde if you want to serialize/deserialize the operation +/// to json string. You could check out the operation_serde.rs for more information. +/// #[derive(Debug, Clone, Eq, PartialEq)] pub enum Operation { Delete(usize), @@ -241,9 +255,7 @@ where #[derive(Clone, Debug, Eq, PartialEq)] pub struct Retain { - // #[serde(rename(serialize = "retain", deserialize = "retain"))] pub n: usize, - // #[serde(skip_serializing_if = "is_empty")] pub attributes: T, } @@ -318,10 +330,7 @@ where #[derive(Clone, Debug, Eq, PartialEq)] pub struct Insert { - // #[serde(rename(serialize = "insert", deserialize = "insert"))] pub s: FlowyStr, - - // #[serde(skip_serializing_if = "is_empty")] pub attributes: T, } @@ -402,16 +411,16 @@ where } #[derive(Debug, Clone, Eq, PartialEq, Default, Serialize, Deserialize)] -pub struct PlainTextAttributes(); -impl fmt::Display for PlainTextAttributes { +pub struct PhantomAttributes(); +impl fmt::Display for PhantomAttributes { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("PlainAttributes") + f.write_str("PhantomAttributes") } } -impl Attributes for PlainTextAttributes {} +impl Attributes for PhantomAttributes {} -impl OperationTransformable for PlainTextAttributes { +impl OperationTransformable for PhantomAttributes { fn compose(&self, _other: &Self) -> Result { Ok(self.clone()) } From 85850af541ae58ed5f7b18a92294dd7a339195fc Mon Sep 17 00:00:00 2001 From: Poly-Pixel <79737178+Poly-Pixel@users.noreply.github.com> Date: Tue, 26 Jul 2022 18:26:44 -0700 Subject: [PATCH 065/112] feat: add windows dev environment install script --- .gitignore | 1 + .../install_dev_env/install_windows.sh | 90 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 frontend/scripts/install_dev_env/install_windows.sh diff --git a/.gitignore b/.gitignore index b4bd54c6be..3d544c712e 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ pubspec.lock # ignore tool used for commit linting .githooks/gitlint +.githooks/gitlint.exe diff --git a/frontend/scripts/install_dev_env/install_windows.sh b/frontend/scripts/install_dev_env/install_windows.sh new file mode 100644 index 0000000000..1f65745e45 --- /dev/null +++ b/frontend/scripts/install_dev_env/install_windows.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +YELLOW="\e[93m" +GREEN="\e[32m" +RED="\e[31m" +ENDCOLOR="\e[0m" + +printMessage() { + printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n" +} + +printSuccess() { + printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n" +} + +printError() { + printf "${RED}AppFlowy : $1${ENDCOLOR}\n" +} + + +# Note: This script does not install applications which are installed by the package manager. There are too many package managers out there. + +# Install Rust +if ! rustc --version; then + + printMessage "The Rust programming language is required to compile AppFlowy." + printMessage "It has not been detected on your system." + + read -p "$(printSuccess "Do you want to install Rust? [y/N]") " installrust + + if [ ${installrust^^} == "Y" ]; then + printMessage "Installing Rust." + if ! curl --proto '=https' --tlsv1.2 -sSf https://win.rustup.rs/x86_64 -o rustup-init.exe; then + printError "Failed to download the Rust installer" + exit 1 + fi + start "Rust Installer" rustup-init.exe + read -p "$(printSuccess "Press enter when Rust installation is done") " isDone + rm rustup-init.exe + rustup toolchain install stable + rustup default stable + else + printMessage "Skipping Rust installation." + fi +else + printSuccess "Rust has been detected on your system, so Rust installation has been skipped" +fi + +# Enable the flutter stable channel +printMessage "Setting up Flutter" +flutter channel stable + +# Enable linux desktop +flutter config --enable-windows-desktop + +# Fix any problems reported by flutter doctor +flutter doctor + +# Add the githooks directory to your git configuration +printMessage "Setting up githooks." +git config core.hooksPath .githooks + +# Change to the frontend directory +cd frontend + +# Install cargo make +printMessage "Installing cargo-make." +cargo install --force cargo-make + +# Install duckscript +printMessage "Installing duckscript." +cargo install --force duckscript_cli + +# Install go-gitlint +printMessage "Installing go-gitlint." +GOLINT_FILENAME="go-gitlint_1.1.0_windows_x86_64.tar.gz" +if curl --proto '=https' --tlsv1.2 -sSfL https://github.com/llorllale/go-gitlint/releases/download/1.1.0/${GOLINT_FILENAME} -o ${GOLINT_FILENAME}; then + tar -zxv --directory .githooks/. -f ${GOLINT_FILENAME} gitlint.exe + rm ${GOLINT_FILENAME} +else + printError "Failed to install go-gitlint" +fi + +# Enable vcpkg integration +# Note: Requires admin +vcpkg integrate install + +# Check prerequisites +printMessage "Checking prerequisites." +cargo make flowy_dev From 7eb7fad336bcaadaca3e4da9eab21383b3cd58ae Mon Sep 17 00:00:00 2001 From: Poly-Pixel <79737178+Poly-Pixel@users.noreply.github.com> Date: Wed, 27 Jul 2022 18:09:59 -0700 Subject: [PATCH 066/112] fix: fix most PATH-related issues --- .../install_dev_env/install_windows.sh | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/frontend/scripts/install_dev_env/install_windows.sh b/frontend/scripts/install_dev_env/install_windows.sh index 1f65745e45..69d5a64137 100644 --- a/frontend/scripts/install_dev_env/install_windows.sh +++ b/frontend/scripts/install_dev_env/install_windows.sh @@ -37,8 +37,8 @@ if ! rustc --version; then start "Rust Installer" rustup-init.exe read -p "$(printSuccess "Press enter when Rust installation is done") " isDone rm rustup-init.exe - rustup toolchain install stable - rustup default stable + $USERPROFILE/.cargo/bin/rustup toolchain install stable + $USERPROFILE/.cargo/bin/rustup default stable else printMessage "Skipping Rust installation." fi @@ -50,6 +50,9 @@ fi printMessage "Setting up Flutter" flutter channel stable +# Add pub cache to PATH +powershell '[Environment]::SetEnvironmentVariable("PATH", $Env:PATH + ";" + $Env:LOCALAPPDATA + "\Pub\Cache\Bin", [EnvironmentVariableTarget]::User)' + # Enable linux desktop flutter config --enable-windows-desktop @@ -60,17 +63,6 @@ flutter doctor printMessage "Setting up githooks." git config core.hooksPath .githooks -# Change to the frontend directory -cd frontend - -# Install cargo make -printMessage "Installing cargo-make." -cargo install --force cargo-make - -# Install duckscript -printMessage "Installing duckscript." -cargo install --force duckscript_cli - # Install go-gitlint printMessage "Installing go-gitlint." GOLINT_FILENAME="go-gitlint_1.1.0_windows_x86_64.tar.gz" @@ -81,10 +73,22 @@ else printError "Failed to install go-gitlint" fi +# Change to the frontend directory +cd frontend + +# Install cargo make +printMessage "Installing cargo-make." +#$USERPROFILE/.cargo/bin/cargo install --force cargo-make + +# Install duckscript +printMessage "Installing duckscript." +$USERPROFILE/.cargo/bin/cargo install --force duckscript_cli + # Enable vcpkg integration # Note: Requires admin +printMessage "Setting up vcpkg." vcpkg integrate install # Check prerequisites printMessage "Checking prerequisites." -cargo make flowy_dev +$USERPROFILE/.cargo/bin/cargo make flowy_dev From 89dc2f0370fb16adcbf09998c7d7ca2ee6e3ec16 Mon Sep 17 00:00:00 2001 From: Poly-Pixel <79737178+Poly-Pixel@users.noreply.github.com> Date: Sun, 24 Jul 2022 12:34:55 -0700 Subject: [PATCH 067/112] fix: forgot to uncomment a line! --- frontend/scripts/install_dev_env/install_windows.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/scripts/install_dev_env/install_windows.sh b/frontend/scripts/install_dev_env/install_windows.sh index 69d5a64137..bf6498b587 100644 --- a/frontend/scripts/install_dev_env/install_windows.sh +++ b/frontend/scripts/install_dev_env/install_windows.sh @@ -78,7 +78,7 @@ cd frontend # Install cargo make printMessage "Installing cargo-make." -#$USERPROFILE/.cargo/bin/cargo install --force cargo-make +$USERPROFILE/.cargo/bin/cargo install --force cargo-make # Install duckscript printMessage "Installing duckscript." From 8cdecd50fe1105593749f096a04f209c277aefe3 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 25 Jul 2022 13:15:11 +0800 Subject: [PATCH 068/112] chore: rename structs --- .../cell_service/cell_data_persistence.dart | 4 +- .../grid/cell/cell_service/cell_service.dart | 2 +- .../grid/cell/select_option_service.dart | 8 +- .../application/grid/field/field_service.dart | 10 +- .../type_option/type_option_service.dart | 7 +- .../application/grid/row/row_service.dart | 8 +- frontend/app_flowy/pubspec.lock | 6 +- .../flowy-grid/src/entities/cell_entities.rs | 33 +++-- .../flowy-grid/src/entities/field_entities.rs | 114 ++++++++++++++++-- .../flowy-grid/src/entities/row_entities.rs | 23 ++-- .../rust-lib/flowy-grid/src/event_handler.rs | 34 +++--- frontend/rust-lib/flowy-grid/src/event_map.rs | 18 +-- .../checkbox_type_option/checkbox_tests.rs | 2 +- .../date_type_option/date_tests.rs | 2 +- .../date_type_option_entities.rs | 8 +- .../selection_type_option/select_option.rs | 12 +- .../flowy-grid/src/services/grid_editor.rs | 6 +- .../tests/grid/block_test/script.rs | 6 +- 18 files changed, 191 insertions(+), 112 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart index a38a771158..71927bae14 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_data_persistence.dart @@ -58,8 +58,8 @@ class DateCellDataPersistence implements IGridCellDataPersistence } } -GridCellIdentifierPayloadPB _makeCellIdPayload(GridCellIdentifier cellId) { - return GridCellIdentifierPayloadPB.create() +GridCellIdPB _makeCellIdPayload(GridCellIdentifier cellId) { + return GridCellIdPB.create() ..gridId = cellId.gridId ..fieldId = cellId.fieldId ..rowId = cellId.rowId; 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 3e8746c20a..47cd67a55f 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 @@ -46,7 +46,7 @@ class CellService { Future> getCell({ required GridCellIdentifier cellId, }) { - final payload = GridCellIdentifierPayloadPB.create() + final payload = GridCellIdPB.create() ..gridId = cellId.gridId ..fieldId = cellId.fieldId ..rowId = cellId.rowId; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart index 54ac384267..b6966a3e4e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -19,7 +19,7 @@ class SelectOptionService { (result) { return result.fold( (option) { - final cellIdentifier = GridCellIdentifierPayloadPB.create() + final cellIdentifier = GridCellIdPB.create() ..gridId = gridId ..fieldId = fieldId ..rowId = rowId; @@ -54,7 +54,7 @@ class SelectOptionService { } Future> getOpitonContext() { - final payload = GridCellIdentifierPayloadPB.create() + final payload = GridCellIdPB.create() ..gridId = gridId ..fieldId = fieldId ..rowId = rowId; @@ -76,8 +76,8 @@ class SelectOptionService { return GridEventUpdateSelectOptionCell(payload).send(); } - GridCellIdentifierPayloadPB _cellIdentifier() { - return GridCellIdentifierPayloadPB.create() + GridCellIdPB _cellIdentifier() { + return GridCellIdPB.create() ..gridId = gridId ..fieldId = fieldId ..rowId = rowId; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index a0c6fc7d21..9274770b21 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -103,7 +103,7 @@ class FieldService { } Future> deleteField() { - final payload = GridFieldIdentifierPayloadPB.create() + final payload = DeleteFieldPayloadPB.create() ..gridId = gridId ..fieldId = fieldId; @@ -111,7 +111,7 @@ class FieldService { } Future> duplicateField() { - final payload = GridFieldIdentifierPayloadPB.create() + final payload = DuplicateFieldPayloadPB.create() ..gridId = gridId ..fieldId = fieldId; @@ -121,7 +121,7 @@ class FieldService { Future> getFieldTypeOptionData({ required FieldType fieldType, }) { - final payload = EditFieldPayloadPB.create() + final payload = GridFieldTypeOptionIdPB.create() ..gridId = gridId ..fieldId = fieldId ..fieldType = fieldType; @@ -165,7 +165,7 @@ class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader { @override Future> load() { - final payload = EditFieldPayloadPB.create() + final payload = CreateFieldPayloadPB.create() ..gridId = gridId ..fieldType = FieldType.RichText; @@ -185,7 +185,7 @@ class FieldTypeOptionLoader extends IFieldTypeOptionLoader { @override Future> load() { - final payload = EditFieldPayloadPB.create() + final payload = GridFieldTypeOptionIdPB.create() ..gridId = gridId ..fieldId = field.id ..fieldType = field.fieldType; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart index b45cc6f869..fca6995b3f 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart @@ -21,13 +21,10 @@ class TypeOptionService { Future> newOption({ required String name, }) { - final fieldIdentifier = GridFieldIdentifierPayloadPB.create() - ..gridId = gridId - ..fieldId = fieldId; - final payload = CreateSelectOptionPayloadPB.create() ..optionName = name - ..fieldIdentifier = fieldIdentifier; + ..gridId = gridId + ..fieldId = fieldId; return GridEventNewSelectOption(payload).send(); } 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 f8f9c7ee3c..893ebb719b 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 @@ -191,7 +191,7 @@ class GridRowCache { } Future _loadRow(String rowId) async { - final payload = GridRowIdPayloadPB.create() + final payload = GridRowIdPB.create() ..gridId = gridId ..blockId = block.id ..rowId = rowId; @@ -297,7 +297,7 @@ class RowService { } Future> getRow() { - final payload = GridRowIdPayloadPB.create() + final payload = GridRowIdPB.create() ..gridId = gridId ..blockId = blockId ..rowId = rowId; @@ -306,7 +306,7 @@ class RowService { } Future> deleteRow() { - final payload = GridRowIdPayloadPB.create() + final payload = GridRowIdPB.create() ..gridId = gridId ..blockId = blockId ..rowId = rowId; @@ -315,7 +315,7 @@ class RowService { } Future> duplicateRow() { - final payload = GridRowIdPayloadPB.create() + final payload = GridRowIdPB.create() ..gridId = gridId ..blockId = blockId ..rowId = rowId; diff --git a/frontend/app_flowy/pubspec.lock b/frontend/app_flowy/pubspec.lock index 958debd9dd..505280115f 100644 --- a/frontend/app_flowy/pubspec.lock +++ b/frontend/app_flowy/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "38.0.0" + version: "42.0.0" analyzer: - dependency: transitive + dependency: "direct overridden" description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "3.4.1" + version: "4.3.0" animations: dependency: transitive description: diff --git a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs index 11cbdeb88e..30e8d65018 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs @@ -1,4 +1,4 @@ -use crate::entities::{FieldIdentifierParams, GridFieldIdentifierPayloadPB}; + use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; @@ -8,23 +8,20 @@ use std::collections::HashMap; #[derive(ProtoBuf, Default)] pub struct CreateSelectOptionPayloadPB { #[pb(index = 1)] - pub field_identifier: GridFieldIdentifierPayloadPB, + pub field_id: String, #[pb(index = 2)] + pub grid_id: String, + + #[pb(index = 3)] pub option_name: String, } pub struct CreateSelectOptionParams { - pub field_identifier: FieldIdentifierParams, + pub field_id: String, + pub grid_id: String, pub option_name: String, -} -impl std::ops::Deref for CreateSelectOptionParams { - type Target = FieldIdentifierParams; - - fn deref(&self) -> &Self::Target { - &self.field_identifier - } } impl TryInto for CreateSelectOptionPayloadPB { @@ -32,16 +29,18 @@ impl TryInto for CreateSelectOptionPayloadPB { fn try_into(self) -> Result { let option_name = NotEmptyStr::parse(self.option_name).map_err(|_| ErrorCode::SelectOptionNameIsEmpty)?; - let field_identifier = self.field_identifier.try_into()?; + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; Ok(CreateSelectOptionParams { - field_identifier, + field_id: field_id.0, option_name: option_name.0, + grid_id: grid_id.0, }) } } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridCellIdentifierPayloadPB { +pub struct GridCellIdPB { #[pb(index = 1)] pub grid_id: String, @@ -52,20 +51,20 @@ pub struct GridCellIdentifierPayloadPB { pub row_id: String, } -pub struct CellIdentifierParams { +pub struct GridCellIdParams { pub grid_id: String, pub field_id: String, pub row_id: String, } -impl TryInto for GridCellIdentifierPayloadPB { +impl TryInto for GridCellIdPB { type Error = ErrorCode; - fn try_into(self) -> Result { + fn try_into(self) -> Result { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; - Ok(CellIdentifierParams { + Ok(GridCellIdParams { grid_id: grid_id.0, field_id: field_id.0, row_id: row_id.0, diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index c769b4f08b..760b820233 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -155,6 +155,45 @@ pub struct GetEditFieldContextPayloadPB { pub field_type: FieldType, } + + +#[derive(Debug, Default, ProtoBuf)] +pub struct CreateFieldPayloadPB { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub field_type: FieldType, + + #[pb(index = 4)] + pub create_if_not_exist: bool, +} + +pub struct CreateFieldParams { + pub grid_id: String, + pub field_id: String, + pub field_type: FieldType, +} + +impl TryInto for CreateFieldPayloadPB { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + Ok(CreateFieldParams { + grid_id: grid_id.0, + field_id: field_id.0, + field_type: self.field_type, + }) + } +} + + + #[derive(Debug, Default, ProtoBuf)] pub struct EditFieldPayloadPB { #[pb(index = 1)] @@ -190,19 +229,34 @@ impl TryInto for EditFieldPayloadPB { } } -pub struct CreateFieldParams { +#[derive(Debug, Default, ProtoBuf)] +pub struct GridFieldTypeOptionIdPB { + #[pb(index = 1)] pub grid_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] pub field_type: FieldType, } -impl TryInto for EditFieldPayloadPB { + +pub struct GridFieldTypeOptionIdParams { + pub grid_id: String, + pub field_id: String, + pub field_type: FieldType, +} + +impl TryInto for GridFieldTypeOptionIdPB { type Error = ErrorCode; - fn try_into(self) -> Result { + fn try_into(self) -> Result { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - - Ok(CreateFieldParams { + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + Ok(GridFieldTypeOptionIdParams { grid_id: grid_id.0, + field_id: field_id.0, field_type: self.field_type, }) } @@ -556,6 +610,16 @@ impl std::convert::From for FieldType { } } } +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct DuplicateFieldPayloadPB { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub grid_id: String, +} + + #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridFieldIdentifierPayloadPB { #[pb(index = 1)] @@ -565,20 +629,44 @@ pub struct GridFieldIdentifierPayloadPB { pub grid_id: String, } -pub struct FieldIdentifierParams { - pub field_id: String, - pub grid_id: String, -} - -impl TryInto for GridFieldIdentifierPayloadPB { +impl TryInto for DuplicateFieldPayloadPB { type Error = ErrorCode; - fn try_into(self) -> Result { + fn try_into(self) -> Result { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; - Ok(FieldIdentifierParams { + Ok(GridFieldIdParams { grid_id: grid_id.0, field_id: field_id.0, }) } } + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct DeleteFieldPayloadPB { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub grid_id: String, +} + +impl TryInto for DeleteFieldPayloadPB { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + Ok(GridFieldIdParams { + grid_id: grid_id.0, + field_id: field_id.0, + }) + } +} + +pub struct GridFieldIdParams { + pub field_id: String, + pub grid_id: String, +} + + diff --git a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs index f66e1c1d06..d8ae0eba7a 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs @@ -2,17 +2,6 @@ use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; -#[derive(ProtoBuf, Default)] -pub struct GridRowIdPayloadPB { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub block_id: String, - - #[pb(index = 3)] - pub row_id: String, -} #[derive(Debug, Default, Clone, ProtoBuf)] pub struct GridRowIdPB { @@ -26,15 +15,21 @@ pub struct GridRowIdPB { pub row_id: String, } -impl TryInto for GridRowIdPayloadPB { +pub struct GridRowIdParams { + pub grid_id: String, + pub block_id: String, + pub row_id: String, +} + +impl TryInto for GridRowIdPB { type Error = ErrorCode; - fn try_into(self) -> Result { + fn try_into(self) -> Result { 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(GridRowIdPB { + Ok(GridRowIdParams { grid_id: grid_id.0, block_id: block_id.0, row_id: row_id.0, diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 4c4bfe5559..b0ef43f5ad 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -113,10 +113,10 @@ pub(crate) async fn update_field_type_option_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn delete_field_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: FieldIdentifierParams = data.into_inner().try_into()?; + let params: GridFieldIdParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.delete_field(¶ms.field_id).await?; Ok(()) @@ -151,10 +151,10 @@ pub(crate) async fn switch_to_field_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn duplicate_field_handler( - data: Data, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: FieldIdentifierParams = data.into_inner().try_into()?; + let params: GridFieldIdParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.duplicate_field(¶ms.field_id).await?; Ok(()) @@ -163,10 +163,10 @@ pub(crate) async fn duplicate_field_handler( /// Return the FieldTypeOptionData if the Field exists otherwise return record not found error. #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn get_field_type_option_data_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { - let params: EditFieldParams = data.into_inner().try_into()?; + let params: GridFieldTypeOptionIdParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_field_rev(¶ms.field_id).await { None => Err(FlowyError::record_not_found()), @@ -186,7 +186,7 @@ pub(crate) async fn get_field_type_option_data_handler( /// Create FieldMeta and save it. Return the FieldTypeOptionData. #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn create_field_type_option_data_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { let params: CreateFieldParams = data.into_inner().try_into()?; @@ -227,10 +227,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, + data: Data, manager: AppData>, ) -> DataResult { - let params: GridRowIdPB = data.into_inner().try_into()?; + let params: GridRowIdParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let row = editor .get_row_rev(¶ms.row_id) @@ -242,10 +242,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, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: GridRowIdPB = data.into_inner().try_into()?; + let params: GridRowIdParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.delete_row(¶ms.row_id).await?; Ok(()) @@ -253,10 +253,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, + data: Data, manager: AppData>, ) -> Result<(), FlowyError> { - let params: GridRowIdPB = data.into_inner().try_into()?; + let params: GridRowIdParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let _ = editor.duplicate_row(¶ms.row_id).await?; Ok(()) @@ -275,10 +275,10 @@ pub(crate) async fn create_row_handler( // #[tracing::instrument(level = "debug", skip_all, err)] pub(crate) async fn get_cell_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { - let params: CellIdentifierParams = data.into_inner().try_into()?; + let params: GridCellIdParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_cell(¶ms).await { None => data_result(GridCellPB::empty(¶ms.field_id)), @@ -357,10 +357,10 @@ pub(crate) async fn update_select_option_handler( #[tracing::instrument(level = "trace", skip(data, manager), err)] pub(crate) async fn get_select_option_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { - let params: CellIdentifierParams = data.into_inner().try_into()?; + let params: GridCellIdParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_field_rev(¶ms.field_id).await { None => { diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index 5abda48c1b..9165d8f7f9 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -69,28 +69,28 @@ pub enum GridEvent { #[event(input = "InsertFieldPayloadPB")] InsertField = 13, - #[event(input = "GridFieldIdentifierPayloadPB")] + #[event(input = "DeleteFieldPayloadPB")] DeleteField = 14, #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")] SwitchToField = 20, - #[event(input = "GridFieldIdentifierPayloadPB")] + #[event(input = "DuplicateFieldPayloadPB")] DuplicateField = 21, #[event(input = "MoveItemPayloadPB")] MoveItem = 22, - #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")] + #[event(input = "GridFieldTypeOptionIdPB", output = "FieldTypeOptionDataPB")] GetFieldTypeOption = 23, - #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")] + #[event(input = "CreateFieldPayloadPB", output = "FieldTypeOptionDataPB")] CreateFieldTypeOption = 24, #[event(input = "CreateSelectOptionPayloadPB", output = "SelectOptionPB")] NewSelectOption = 30, - #[event(input = "GridCellIdentifierPayloadPB", output = "SelectOptionCellDataPB")] + #[event(input = "GridCellIdPB", output = "SelectOptionCellDataPB")] GetSelectOptionCellData = 31, #[event(input = "SelectOptionChangesetPayloadPB")] @@ -99,16 +99,16 @@ pub enum GridEvent { #[event(input = "CreateRowPayloadPB", output = "GridRowPB")] CreateRow = 50, - #[event(input = "GridRowIdPayloadPB", output = "OptionalRowPB")] + #[event(input = "GridRowIdPB", output = "OptionalRowPB")] GetRow = 51, - #[event(input = "GridRowIdPayloadPB")] + #[event(input = "GridRowIdPB")] DeleteRow = 52, - #[event(input = "GridRowIdPayloadPB")] + #[event(input = "GridRowIdPB")] DuplicateRow = 53, - #[event(input = "GridCellIdentifierPayloadPB", output = "GridCellPB")] + #[event(input = "GridCellIdPB", output = "GridCellPB")] GetCell = 70, #[event(input = "CellChangesetPB")] diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs index b9d155da7d..11d8b8f09e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option/checkbox_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::entities::FieldType; - use crate::services::cell::{apply_cell_data_changeset, decode_any_cell_data, CellDataOperation}; + use crate::services::cell::{CellDataOperation}; use crate::services::field::type_options::checkbox_type_option::*; use crate::services::field::FieldBuilder; use flowy_grid_data_model::revision::FieldRevision; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs index 74b6ee6fd8..87e4efa4a8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::entities::FieldType; - use crate::services::cell::{CellDataChangeset, CellDataOperation}; + use crate::services::cell::{CellDataOperation}; use crate::services::field::*; // use crate::services::field::{DateCellChangeset, DateCellData, DateFormat, DateTypeOption, TimeFormat}; use flowy_grid_data_model::revision::FieldRevision; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs index aa8fab221a..d5da516bf1 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs @@ -1,5 +1,5 @@ use crate::entities::CellChangesetPB; -use crate::entities::{CellIdentifierParams, GridCellIdentifierPayloadPB}; +use crate::entities::{GridCellIdParams, GridCellIdPB}; use crate::services::cell::{CellBytesParser, FromCellChangeset, FromCellString}; use bytes::Bytes; @@ -24,7 +24,7 @@ pub struct DateCellDataPB { #[derive(Clone, Debug, Default, ProtoBuf)] pub struct DateChangesetPayloadPB { #[pb(index = 1)] - pub cell_identifier: GridCellIdentifierPayloadPB, + pub cell_identifier: GridCellIdPB, #[pb(index = 2, one_of)] pub date: Option, @@ -34,7 +34,7 @@ pub struct DateChangesetPayloadPB { } pub struct DateChangesetParams { - pub cell_identifier: CellIdentifierParams, + pub cell_identifier: GridCellIdParams, pub date: Option, pub time: Option, } @@ -43,7 +43,7 @@ impl TryInto for DateChangesetPayloadPB { type Error = ErrorCode; fn try_into(self) -> Result { - let cell_identifier: CellIdentifierParams = self.cell_identifier.try_into()?; + let cell_identifier: GridCellIdParams = self.cell_identifier.try_into()?; Ok(DateChangesetParams { cell_identifier, date: self.date, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index dbffe79f56..8f441e1755 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -1,4 +1,4 @@ -use crate::entities::{CellChangesetPB, CellIdentifierParams, FieldType, GridCellIdentifierPayloadPB}; +use crate::entities::{CellChangesetPB, GridCellIdParams, FieldType, GridCellIdPB}; use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; use bytes::Bytes; @@ -225,7 +225,7 @@ impl CellBytesParser for SelectOptionCellDataParser { #[derive(Clone, Debug, Default, ProtoBuf)] pub struct SelectOptionCellChangesetPayloadPB { #[pb(index = 1)] - pub cell_identifier: GridCellIdentifierPayloadPB, + pub cell_identifier: GridCellIdPB, #[pb(index = 2, one_of)] pub insert_option_id: Option, @@ -235,7 +235,7 @@ pub struct SelectOptionCellChangesetPayloadPB { } pub struct SelectOptionCellChangesetParams { - pub cell_identifier: CellIdentifierParams, + pub cell_identifier: GridCellIdParams, pub insert_option_id: Option, pub delete_option_id: Option, } @@ -260,7 +260,7 @@ impl TryInto for SelectOptionCellChangesetPaylo type Error = ErrorCode; fn try_into(self) -> Result { - let cell_identifier: CellIdentifierParams = self.cell_identifier.try_into()?; + let cell_identifier: GridCellIdParams = self.cell_identifier.try_into()?; let insert_option_id = match self.insert_option_id { None => None, Some(insert_option_id) => Some( @@ -334,7 +334,7 @@ pub struct SelectOptionCellDataPB { #[derive(Clone, Debug, Default, ProtoBuf)] pub struct SelectOptionChangesetPayloadPB { #[pb(index = 1)] - pub cell_identifier: GridCellIdentifierPayloadPB, + pub cell_identifier: GridCellIdPB, #[pb(index = 2, one_of)] pub insert_option: Option, @@ -347,7 +347,7 @@ pub struct SelectOptionChangesetPayloadPB { } pub struct SelectOptionChangeset { - pub cell_identifier: CellIdentifierParams, + pub cell_identifier: GridCellIdParams, pub insert_option: Option, pub update_option: Option, pub delete_option: Option, 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 572665bd0c..5c7436022e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -1,5 +1,5 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; -use crate::entities::CellIdentifierParams; +use crate::entities::GridCellIdParams; use crate::entities::*; use crate::manager::{GridTaskSchedulerRwLock, GridUser}; use crate::services::block_manager::GridBlockManager; @@ -339,12 +339,12 @@ impl GridRevisionEditor { Ok(()) } - pub async fn get_cell(&self, params: &CellIdentifierParams) -> Option { + pub async fn get_cell(&self, params: &GridCellIdParams) -> Option { let cell_bytes = self.get_cell_bytes(params).await?; Some(GridCellPB::new(¶ms.field_id, cell_bytes.to_vec())) } - pub async fn get_cell_bytes(&self, params: &CellIdentifierParams) -> Option { + pub async fn get_cell_bytes(&self, params: &GridCellIdParams) -> Option { let field_rev = self.get_field_rev(¶ms.field_id).await?; let row_rev = self.block_manager.get_row_rev(¶ms.row_id).await.ok()??; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 33548f97c5..9516fd1d03 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -2,7 +2,7 @@ use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow}; use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; -use flowy_grid::entities::{CellIdentifierParams, FieldType, GridRowPB}; +use flowy_grid::entities::{GridCellIdParams, FieldType, GridRowPB}; use flowy_grid::services::field::*; use flowy_grid_data_model::revision::{ GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, @@ -109,7 +109,7 @@ impl GridRowTest { field_type, expected, } => { - let id = CellIdentifierParams { + let id = GridCellIdParams { grid_id: self.grid_id.clone(), field_id, row_id, @@ -154,7 +154,7 @@ impl GridRowTest { } } - async fn compare_cell_content(&self, cell_id: CellIdentifierParams, field_type: FieldType, expected: String) { + async fn compare_cell_content(&self, cell_id: GridCellIdParams, field_type: FieldType, expected: String) { match field_type { FieldType::RichText => { let cell_data = self From 22398985b616be037b1121500d14670b2858dd09 Mon Sep 17 00:00:00 2001 From: kakzaki Date: Mon, 25 Jul 2022 13:33:50 +0700 Subject: [PATCH 069/112] fix: add indonesian translation --- frontend/app_flowy/lib/startup/tasks/app_widget.dart | 1 + frontend/app_flowy/packages/flowy_infra/lib/language.dart | 2 ++ 2 files changed, 3 insertions(+) diff --git a/frontend/app_flowy/lib/startup/tasks/app_widget.dart b/frontend/app_flowy/lib/startup/tasks/app_widget.dart index c8addc9d6f..b41e9a32d7 100644 --- a/frontend/app_flowy/lib/startup/tasks/app_widget.dart +++ b/frontend/app_flowy/lib/startup/tasks/app_widget.dart @@ -36,6 +36,7 @@ class InitAppWidgetTask extends LaunchTask { Locale('fr', 'FR'), Locale('fr', 'CA'), Locale('hu', 'HU'), + Locale('id', 'ID'), Locale('it', 'IT'), Locale('ja', 'JP'), Locale('pt', 'BR'), diff --git a/frontend/app_flowy/packages/flowy_infra/lib/language.dart b/frontend/app_flowy/packages/flowy_infra/lib/language.dart index 2b98263cfb..b30200141d 100644 --- a/frontend/app_flowy/packages/flowy_infra/lib/language.dart +++ b/frontend/app_flowy/packages/flowy_infra/lib/language.dart @@ -26,6 +26,8 @@ String languageFromLocale(Locale locale) { } case "hu": return "Magyar"; + case "id": + return "Bahasa"; case "it": return "Italiano"; case "ja": From 00785022e850e3057642dead61339a0f5e663745 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 25 Jul 2022 12:45:35 +0800 Subject: [PATCH 070/112] chore: add documentation for flowy_grid crate --- .../flowy-grid/src/entities/block_entities.rs | 13 +++ .../flowy-grid/src/entities/cell_entities.rs | 1 + .../flowy-grid/src/entities/field_entities.rs | 21 +++++ .../flowy-grid/src/entities/grid_entities.rs | 2 + .../src/entities/setting_entities.rs | 2 + frontend/rust-lib/flowy-grid/src/event_map.rs | 89 +++++++++++++++++++ .../selection_type_option/select_option.rs | 11 +++ .../flowy-grid/src/services/grid_editor.rs | 1 - .../src/revision/grid_rev.rs | 7 ++ 9 files changed, 146 insertions(+), 1 deletion(-) diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs index df2192c77d..df09416860 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -4,6 +4,14 @@ use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::RowRevision; use std::sync::Arc; + +/// [GridBlockPB] contains list of rows. The row here does not contain any data, just the id +/// of the row. Check out [GridRowPB] for more details. +/// +/// +/// A grid can have many rows. Rows are therefore grouped into Blocks in order to make +/// things more efficient. +/// | #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridBlockPB { #[pb(index = 1)] @@ -22,6 +30,7 @@ impl GridBlockPB { } } +/// [GridRowPB] describes the row belongs to which block and the metadata of the row. #[derive(Debug, Default, Clone, ProtoBuf)] pub struct GridRowPB { #[pb(index = 1)] @@ -81,6 +90,8 @@ impl std::convert::From> for RepeatedRowPB { Self { items } } } + +/// [RepeatedGridBlockPB] contains list of [GridBlockPB] #[derive(Debug, Default, ProtoBuf)] pub struct RepeatedGridBlockPB { #[pb(index = 1)] @@ -194,6 +205,8 @@ impl GridBlockChangesetPB { } } +/// [QueryGridBlocksPayloadPB] is used to query the data of the block that belongs to the grid whose +/// id is grid_id. #[derive(ProtoBuf, Default)] pub struct QueryGridBlocksPayloadPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs index 30e8d65018..d128c8d76f 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs @@ -121,6 +121,7 @@ impl std::convert::From> for RepeatedCellPB { } } +/// #[derive(Debug, Clone, Default, ProtoBuf)] pub struct CellChangesetPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index 760b820233..f51685798c 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -8,6 +8,8 @@ use std::sync::Arc; use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString}; + +/// [GridFieldPB] defines the field's attributes. Such as the name, field_type, and width. etc. #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridFieldPB { #[pb(index = 1)] @@ -56,6 +58,8 @@ impl std::convert::From> for GridFieldPB { GridFieldPB::from(field_rev) } } + +/// [GridFieldIdPB] id of the [Field] #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridFieldIdPB { #[pb(index = 1)] @@ -262,6 +266,13 @@ impl TryInto for GridFieldTypeOptionIdPB { } } +/// Certain field types have user-defined options such as color, date format, number format, +/// or a list of values for a multi-select list. These options are defined within a specialization +/// of the FieldTypeOption class. +/// +/// You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid#fieldtype) +/// for more information. +/// #[derive(Debug, Default, ProtoBuf)] pub struct FieldTypeOptionDataPB { #[pb(index = 1)] @@ -274,6 +285,8 @@ pub struct FieldTypeOptionDataPB { pub type_option_data: Vec, } + +/// Collection of the [GridFieldPB] #[derive(Debug, Default, ProtoBuf)] pub struct RepeatedGridFieldPB { #[pb(index = 1)] @@ -369,6 +382,7 @@ impl TryInto for InsertFieldPayloadPB { } } +/// [UpdateFieldTypeOptionPayloadPB] is used to update the type option data. #[derive(ProtoBuf, Default)] pub struct UpdateFieldTypeOptionPayloadPB { #[pb(index = 1)] @@ -377,6 +391,7 @@ pub struct UpdateFieldTypeOptionPayloadPB { #[pb(index = 2)] pub field_id: String, + /// Check out the [FieldTypeOptionDataPB] for more details. #[pb(index = 3)] pub type_option_data: Vec, } @@ -429,6 +444,12 @@ impl TryInto for QueryFieldPayloadPB { } } +/// [FieldChangesetPayloadPB] is used to modify the corresponding field. It defines which property of +/// the field can be modified. +/// +/// Pass in None if you don't want to modify a property +/// Pass in Some(Value) if you want to modify a property +/// #[derive(Debug, Clone, Default, ProtoBuf)] pub struct FieldChangesetPayloadPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs index 1be0412503..49278afc54 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs @@ -2,6 +2,8 @@ use crate::entities::{GridBlockPB, GridFieldIdPB}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; + +/// [GridPB] describes how many fields and blocks the grid has #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs index 9272cfe46d..697910ccad 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs @@ -12,6 +12,8 @@ use std::convert::TryInto; use strum::IntoEnumIterator; use strum_macros::EnumIter; + +/// [GridSettingPB] defines the setting options for the grid. Such as the filter, group, and sort. #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct GridSettingPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index 9165d8f7f9..c072355f20 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -42,63 +42,136 @@ pub fn create(grid_manager: Arc) -> Module { module } + +/// [GridEvent] defines events that are used to interact with the Grid. You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/protobuf) +/// out, it includes how to use these annotations: input, output, etc. #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] #[event_err = "FlowyError"] pub enum GridEvent { + /// [GetGrid] event is used to get the [GridPB] + /// + /// The event handler accepts [GridIdPB] and return [GridPB] if there is no errors. + /// #[event(input = "GridIdPB", output = "GridPB")] GetGrid = 0, + /// [GetGridBlocks] event is used to get the grid's block. + /// + /// The event handler accepts [QueryGridBlocksPayloadPB] and return [RepeatedGridBlockPB] + /// if there is no errors. #[event(input = "QueryGridBlocksPayloadPB", output = "RepeatedGridBlockPB")] GetGridBlocks = 1, + /// [GetGridSetting] event is used to get the grid's setting. + /// + /// The event handler accepts [GridIdPB] and return [GridSettingPB] + /// if there is no errors. #[event(input = "GridIdPB", output = "GridSettingPB")] GetGridSetting = 2, + /// [UpdateGridSetting] event is used to update the grid's setting. + /// + /// The event handler accepts [GridIdPB] and return errors if failed to modify the grid's setting. #[event(input = "GridIdPB", input = "GridSettingChangesetPayloadPB")] UpdateGridSetting = 3, + /// [GetFields] event is used to get the grid's setting. + /// + /// The event handler accepts [QueryFieldPayloadPB] and return [RepeatedGridFieldPB] + /// if there is no errors. #[event(input = "QueryFieldPayloadPB", output = "RepeatedGridFieldPB")] GetFields = 10, + /// [UpdateField] event is used to update the field attributes. + /// + /// The event handler accepts [FieldChangesetPayloadPB] and return errors if failed to modify the + /// field. #[event(input = "FieldChangesetPayloadPB")] UpdateField = 11, + + /// [UpdateFieldTypeOption] event is used to update the field's type option data. Certain field + /// types have user-defined options such as color, date format, number format, or a list of values + /// for a multi-select list. These options are defined within a specialization of the + /// FieldTypeOption class. + /// + /// Check out [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid#fieldtype) + /// for more information. + /// + /// The event handler accepts [UpdateFieldTypeOptionPayloadPB] and return errors if failed to modify the + /// field. #[event(input = "UpdateFieldTypeOptionPayloadPB")] UpdateFieldTypeOption = 12, + /// [InsertField] event is used to insert a new field. If the field is already exists, the event + /// handler will replace the value with the new field value. #[event(input = "InsertFieldPayloadPB")] InsertField = 13, + /// [DeleteField] event is used to delete a new field. [DeleteFieldPayloadPB] is the context that + /// is used to delete the field from the Grid. #[event(input = "DeleteFieldPayloadPB")] DeleteField = 14, + /// [SwitchToField] event is used to update the current field's type. + /// It will insert a new FieldTypeOptionData if the new FieldType doesn't exist before, otherwise + /// reuse the existing FieldTypeOptionData. You could check the [GridRevisionPad] for more details. #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")] SwitchToField = 20, + /// [DuplicateField] event is used to duplicate the field. The duplicated field data is kind of + /// deep copy of the target field. The passed in [DuplicateFieldPayloadPB] is the context that is + /// used to duplicate the field. + /// + /// Return errors if failed to duplicate the field. + /// #[event(input = "DuplicateFieldPayloadPB")] DuplicateField = 21, + /// [MoveItem] event is used to move the item. For the moment, the item has two types defined in + /// the [MoveItemTypePB]. #[event(input = "MoveItemPayloadPB")] MoveItem = 22, + /// [GetFieldTypeOption] event is used to get the FieldTypeOption data for the specific field type. + /// + /// Check out the [FieldTypeOptionDataPB] for more details. If the [FieldTypeOptionData] does exist + /// for the target type, the [TypeOptionBuilder] will create the default data for that type. + /// + /// Return the [FieldTypeOptionDataPB] if there is no errors. #[event(input = "GridFieldTypeOptionIdPB", output = "FieldTypeOptionDataPB")] GetFieldTypeOption = 23, + /// [CreateFieldTypeOption] event is used to create a new FieldTypeOptionData. #[event(input = "CreateFieldPayloadPB", output = "FieldTypeOptionDataPB")] CreateFieldTypeOption = 24, + /// [NewSelectOption] event is used to create a new select option. Return the [SelectOptionPB] if + /// there is no errors. #[event(input = "CreateSelectOptionPayloadPB", output = "SelectOptionPB")] NewSelectOption = 30, + /// [GetSelectOptionCellData] event is used to get the select option data for cell editing. + /// [GridCellIdPB] locate which cell data that will be read from. The return value, [SelectOptionCellDataPB] + /// contains the available options and the currently selected options. #[event(input = "GridCellIdPB", output = "SelectOptionCellDataPB")] GetSelectOptionCellData = 31, + /// [UpdateSelectOption] event is used to update the FieldTypeOptionData that its field_type is + /// FieldType::SingleSelect or FieldType::MultiSelect. + /// + /// This event may trigger the GridNotification::DidUpdateCell event. + /// For example, the [SelectOptionChangesetPayloadPB] carries a change that update the name of + /// the option. + /// #[event(input = "SelectOptionChangesetPayloadPB")] UpdateSelectOption = 32, #[event(input = "CreateRowPayloadPB", output = "GridRowPB")] CreateRow = 50, + /// [GetRow] event is used to get the row data,[GridRowPB]. [OptionalRowPB] is a wrapper that enables + /// to return a nullable row data. #[event(input = "GridRowIdPB", output = "OptionalRowPB")] GetRow = 51, @@ -111,12 +184,28 @@ pub enum GridEvent { #[event(input = "GridCellIdPB", output = "GridCellPB")] GetCell = 70, + /// [UpdateCell] event is used to update the cell content. The passed in data, [CellChangesetPB], + /// carries the changes that will be applied to the cell content by calling `update_cell` function. + /// + /// The 'content' property of the [CellChangesetPB] is String type. It can be used directly if the + /// cell use string data. For example, the TextCell or NumberCell. + /// + /// But,it can be treated as a generic type, because we can use [serde] to deserialize the string + /// into a specific data type.For the moment, the 'content' will be deserialized to concrete type + /// when the FieldType is SingleSelect, DateTime, and MultiSelect. We will discuss the details + /// in [UpdateSelectOptionCell] and [UpdateDateCell] event. #[event(input = "CellChangesetPB")] UpdateCell = 71, + /// [UpdateSelectOptionCell] event is used to update the select option cell data. [SelectOptionCellChangesetPayloadPB] + /// contains options that will be deleted or inserted. It can be cast to [CellChangesetPB] that + /// will be used by the `update_cell` function. #[event(input = "SelectOptionCellChangesetPayloadPB")] UpdateSelectOptionCell = 72, + /// [UpdateDateCell] event is used to update the date cell data. [DateChangesetPayloadPB] + /// contains the date and the time string. It can be cast to [CellChangesetPB] that + /// will be used by the `update_cell` function. #[event(input = "DateChangesetPayloadPB")] UpdateDateCell = 80, } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index 8f441e1755..ea57931bb8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -11,6 +11,8 @@ use serde::{Deserialize, Serialize}; pub const SELECTION_IDS_SEPARATOR: &str = ","; + +/// [SelectOptionPB] represents an option for the single select, and multiple select. #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)] pub struct SelectOptionPB { #[pb(index = 1)] @@ -322,15 +324,24 @@ impl SelectOptionCellChangeset { } } + +/// [SelectOptionCellDataPB] contains a list of user's selected options and a list of all the options +/// that the cell can use. #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] pub struct SelectOptionCellDataPB { + + /// The available options that the cell can use. #[pb(index = 1)] pub options: Vec, + /// The selected options for the cell. #[pb(index = 2)] pub select_options: Vec, } + +/// [SelectOptionChangesetPayloadPB] describes the changes of the FieldTypeOptionData. For the moment, +/// it is used by [MultiSelectTypeOptionPB] and [SingleSelectTypeOptionPB]. #[derive(Clone, Debug, Default, ProtoBuf)] pub struct SelectOptionChangesetPayloadPB { #[pb(index = 1)] 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 5c7436022e..a7921041bc 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -103,7 +103,6 @@ impl GridRevisionEditor { .modify(|grid| { let builder = type_option_builder_from_bytes(type_option_data, &field.field_type); let field_rev = FieldBuilder::from_field(field, builder).build(); - Ok(grid.create_field_rev(field_rev, start_field_id)?) }) .await?; 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 2298eb485f..1bc7139d9a 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 @@ -123,7 +123,9 @@ pub struct FieldRevision { /// type_options contains key/value pairs /// key: id of the FieldType /// value: type option data that can be parsed into specified TypeOptionStruct. + /// /// For example, CheckboxTypeOption, MultiSelectTypeOption etc. + /// #[serde(with = "indexmap::serde_seq")] pub type_options: IndexMap, @@ -185,15 +187,20 @@ impl FieldRevision { } } +/// The macro, [impl_type_option] will implement the [TypeOptionDataEntry] for the type that +/// supports serde trait and TryInto trait. pub trait TypeOptionDataEntry { fn json_str(&self) -> String; fn protobuf_bytes(&self) -> Bytes; } +/// The macro, [impl_type_option] will implement the [TypeOptionDataDeserializer] for the type that +/// supports serde trait and TryFrom trait. pub trait TypeOptionDataDeserializer { fn from_json_str(s: &str) -> Self; fn from_protobuf_bytes(bytes: Bytes) -> Self; } + pub type FieldId = String; #[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct RowRevision { From e640cf2890c94584d223330734fbe266c255d009 Mon Sep 17 00:00:00 2001 From: Annie Date: Mon, 25 Jul 2022 20:24:40 +0800 Subject: [PATCH 071/112] chore: Create ROADMAP.md --- ROADMAP.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 ROADMAP.md diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000000..48c6f116be --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,11 @@ +# View the official [AppFlowy public roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) + +## Guide to the roadmap +### Labels +### Item Status +### Milestones +### Views + +## Disclaimer + +## Acknowledgements From 943ce37623a794bcd70ea5355d7e7ab64b20b2a9 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 25 Jul 2022 10:48:24 -0400 Subject: [PATCH 072/112] feat: remove commitlint and node.js dependency --- commitlint.config.js | 24 --------------- frontend/Makefile.toml | 1 - frontend/scripts/makefile/githooks.toml | 39 ------------------------- package.json | 6 ---- 4 files changed, 70 deletions(-) delete mode 100644 commitlint.config.js delete mode 100644 frontend/scripts/makefile/githooks.toml delete mode 100644 package.json diff --git a/commitlint.config.js b/commitlint.config.js deleted file mode 100644 index c59a378e48..0000000000 --- a/commitlint.config.js +++ /dev/null @@ -1,24 +0,0 @@ -// module.exports = {extends: ['@commitlint/config-conventional']} -module.exports = { - rules: { - 'header-max-length': [2, 'always', 100], - - 'type-enum': [2, 'always', ['build', 'chore', 'ci', 'docs', 'feat', 'feature', 'fix', 'refactor', 'style', 'test']], - 'type-empty': [2, 'never'], - 'type-case': [2, 'always', 'lower-case'], - - 'subject-empty': [2, 'never'], - 'subject-case': [ - 0, - 'never', - ['sentence-case', 'start-case', 'pascal-case', 'upper-case'], - ], - - 'body-leading-blank': [2, 'always'], - 'body-max-line-length': [2, 'always', 200], - 'body-case': [0, 'never', []], - - 'footer-leading-blank': [1, 'always'], - 'footer-max-line-length': [2, 'always', 100] - }, -}; diff --git a/frontend/Makefile.toml b/frontend/Makefile.toml index 7449bfeef3..337b9efd76 100644 --- a/frontend/Makefile.toml +++ b/frontend/Makefile.toml @@ -8,7 +8,6 @@ extend = [ { path = "scripts/makefile/env.toml" }, { path = "scripts/makefile/flutter.toml" }, { path = "scripts/makefile/tool.toml" }, - { path = "scripts/makefile/githooks.toml" }, ] [config] diff --git a/frontend/scripts/makefile/githooks.toml b/frontend/scripts/makefile/githooks.toml deleted file mode 100644 index f6b066ec49..0000000000 --- a/frontend/scripts/makefile/githooks.toml +++ /dev/null @@ -1,39 +0,0 @@ -[tasks.install-commitlint.mac] -script = [ - """ - brew install npm - npm install @commitlint/cli @commitlint/config-conventional --save-dev - - git config core.hooksPath .githooks - """, -] -script_runner = "@shell" - -[tasks.install-commitlint.windows] -script = [ - """ - echo "WIP" - - git config core.hooksPath .githooks - """, -] -script_runner = "@duckscript" - -[tasks.install-commitlint.linux] -script = [ - """ - if command -v apt &> /dev/null - then - echo "Installing node.js (sudo apt install nodejs)" - sudo apt install nodejs - else - echo "Installing node.js (sudo pacman -S nodejs)" - sudo pacman -S nodejs - fi - - npm install @commitlint/cli @commitlint/config-conventional --save-dev - - git config core.hooksPath .githooks - """, -] -script_runner = "@shell" diff --git a/package.json b/package.json deleted file mode 100644 index 0f6a7fcafe..0000000000 --- a/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "devDependencies": { - "@commitlint/cli": "^16.1.0", - "@commitlint/config-conventional": "^16.0.0" - } -} From f993e1d076b05f0bed3bc5231eca4aede9e73019 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 25 Jul 2022 12:02:33 -0400 Subject: [PATCH 073/112] feat: add gitlint dependency --- .githooks/commit-msg | 9 ++++++++- .gitignore | 3 +++ frontend/scripts/install_dev_env/install_linux.sh | 12 ++++++++++-- frontend/scripts/install_dev_env/install_macos.sh | 11 +++++++---- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/.githooks/commit-msg b/.githooks/commit-msg index 24cd55c6b6..cf50d88f35 100755 --- a/.githooks/commit-msg +++ b/.githooks/commit-msg @@ -16,7 +16,14 @@ test "" = "$(grep '^Signed-off-by: ' "$1" | exit 1 } -npx --no -- commitlint --edit $1 +.githooks/gitlint \ + --msg-file=$1 \ + --subject-regex="^([bB]uild|[cC]hore|[cC]i|[dD]ocs|[fF]eat|[fF]eature|[fF]ix|[pP]erf|[rR]efactor|[rR]evert|[sS]tyle|[tT]est)(.*)?\s?:\s?.*" \ + --subject-maxlen=100 \ + --subject-minlen=10 \ + --body-regex=".*" \ + --body-maxlen=200 \ + --max-parents=1 if [ $? -ne 0 ] then diff --git a/.gitignore b/.gitignore index c956a0ad13..b4bd54c6be 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ frontend/.vscode/* # Commit the highest level pubspec.lock, but ignore the others pubspec.lock !frontend/app_flowy/pubspec.lock + +# ignore tool used for commit linting +.githooks/gitlint diff --git a/frontend/scripts/install_dev_env/install_linux.sh b/frontend/scripts/install_dev_env/install_linux.sh index a580c22b19..eafc15ae98 100755 --- a/frontend/scripts/install_dev_env/install_linux.sh +++ b/frontend/scripts/install_dev_env/install_linux.sh @@ -50,6 +50,13 @@ flutter doctor printMessage "Setting up githooks." git config core.hooksPath .githooks +# Install go-gitlint +printMessage "Installing go-gitlint." +GOLINT_FILENAME="go-gitlint_1.1.0_linux_x86_64.tar.gz" +wget https://github.com/llorllale/go-gitlint/releases/download/1.1.0/${GOLINT_FILENAME} +tar -zxv --directory .githooks/. -f ${GOLINT_FILENAME} gitlint +rm ${GOLINT_FILENAME} + # Change to the frontend directory cd frontend @@ -62,8 +69,9 @@ printMessage "Installing duckscript." cargo install --force duckscript_cli # Install CommitLint -printMessage "Installing CommitLint." -npm install @commitlint/cli @commitlint/config-conventional --save-dev +printMessage "Installing go-gitlint." +wget https://github.com/llorllale/go-gitlint/releases/download/1.1.0/go-gitlint_1.1.0_linux_x86_64.tar.gz +tar -xf go-gitlint_1.1.0_linux_x86_64.tar.gz - C # Check prerequisites printMessage "Checking prerequisites." diff --git a/frontend/scripts/install_dev_env/install_macos.sh b/frontend/scripts/install_dev_env/install_macos.sh index edc0c40b26..26a2e5da02 100755 --- a/frontend/scripts/install_dev_env/install_macos.sh +++ b/frontend/scripts/install_dev_env/install_macos.sh @@ -50,6 +50,13 @@ flutter doctor printMessage "Setting up githooks." git config core.hooksPath .githooks +# Install go-gitlint +printMessage "Installing go-gitlint." +GOLINT_FILENAME="go-gitlint_1.1.0_osx_x86_64.tar.gz" +wget https://github.com/llorllale/go-gitlint/releases/download/1.1.0/${GOLINT_FILENAME} +tar -zxv --directory .githooks/. -f ${GOLINT_FILENAME} gitlint +rm ${GOLINT_FILENAME} + # Change to the frontend directory cd frontend @@ -61,10 +68,6 @@ cargo install --force cargo-make printMessage "Installing duckscript." cargo install --force duckscript_cli -# Install CommitLint -printMessagae "Installing CommitLint." -npm install @commitlint/cli @commitlint/config-conventional --save-dev - # Check prerequisites printMessage "Checking prerequisites." cargo make flowy_dev From c45e4515bb975fdcc18c2c706c337930dacd2296 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 25 Jul 2022 12:20:55 -0400 Subject: [PATCH 074/112] feat: Improved commit githooks messages --- .githooks/commit-msg | 22 ++++++++++++++++++++-- .githooks/pre-commit | 19 ++++++++++++++++++- .githooks/pre-push | 30 ++++++++++++++++++++++++------ 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/.githooks/commit-msg b/.githooks/commit-msg index cf50d88f35..c2cd09aecf 100755 --- a/.githooks/commit-msg +++ b/.githooks/commit-msg @@ -6,7 +6,24 @@ # status after issuing an appropriate message if it wants to stop the # commit. The hook is allowed to edit the commit message file. -echo "Running the AppFlowy commit-msg hook." +YELLOW="\e[93m" +GREEN="\e[32m" +RED="\e[31m" +ENDCOLOR="\e[0m" + +printMessage() { + printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n" +} + +printSuccess() { + printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n" +} + +printError() { + printf "${RED}AppFlowy : $1${ENDCOLOR}\n" +} + +printMessage "Running the AppFlowy commit-msg hook." # This example catches duplicate Signed-off-by lines. @@ -27,7 +44,8 @@ test "" = "$(grep '^Signed-off-by: ' "$1" | if [ $? -ne 0 ] then - echo "Please fix your commit message to match AppFlowy coding standards" + printError "Please fix your commit message to match AppFlowy coding standards" + printError "https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/software-contributions/submitting-code/style-guides" exit 1 fi diff --git a/.githooks/pre-commit b/.githooks/pre-commit index d27345fe71..be42c93834 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -1,6 +1,23 @@ #!/usr/bin/env bash -echo "Running local AppFlowy pre-commit hook." +YELLOW="\e[93m" +GREEN="\e[32m" +RED="\e[31m" +ENDCOLOR="\e[0m" + +printMessage() { + printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n" +} + +printSuccess() { + printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n" +} + +printError() { + printf "${RED}AppFlowy : $1${ENDCOLOR}\n" +} + +printMessage "Running local AppFlowy pre-commit hook." #flutter format . ##https://gist.github.com/benmccallum/28e4f216d9d72f5965133e6c43aaff6e diff --git a/.githooks/pre-push b/.githooks/pre-push index ad7d19a16e..7b6eeb8bc1 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -1,23 +1,41 @@ #!/usr/bin/env bash -echo "Running local AppFlowy pre-push hook." +YELLOW="\e[93m" +GREEN="\e[32m" +RED="\e[31m" +ENDCOLOR="\e[0m" + +printMessage() { + printf "${YELLOW}AppFlowy : $1${ENDCOLOR}\n" +} + +printSuccess() { + printf "${GREEN}AppFlowy : $1${ENDCOLOR}\n" +} + +printError() { + printf "${RED}AppFlowy : $1${ENDCOLOR}\n" +} + +printMessage "Running local AppFlowy pre-push hook." if [[ `git status --porcelain` ]]; then - printf "\e[31;1m%s\e[0m\n" 'This script needs to run against committed code only. Please commit or stash you changes.' + printError "This script needs to run against committed code only. Please commit or stash you changes." exit 1 fi -printf "\e[33;1m%s\e[0m\n" 'Running the Flutter analyzer' +printMessage "Running the Flutter analyzer" flutter analyze if [ $? -ne 0 ]; then - printf "\e[31;1m%s\e[0m\n" 'Flutter analyzer error' + printError "Flutter analyzer error" exit 1 fi -printf "\e[33;1m%s\e[0m\n" 'Finished running the Flutter analyzer' -printf "\e[33;1m%s\e[0m\n" 'Running unit tests' +printMessage "Finished running the Flutter analyzer" + +#printMessage "Running unit tests" #flutter test #if [ $? -ne 0 ]; then # printf "\e[31;1m%s\e[0m\n" 'Unit tests error' From db2a27384505e5f9f414f98f38ab70d07e0a0352 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 25 Jul 2022 12:44:54 -0400 Subject: [PATCH 075/112] fix: put back commintlint config because the server will need it --- commitlint.config.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 commitlint.config.js diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000000..1e1af55752 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,25 @@ +// module.exports = {extends: ['@commitlint/config-conventional']} +module.exports = { + rules: { + 'header-max-length': [2, 'always', 100], + + 'type-enum': [2, 'always', ['build', 'chore', 'ci', 'docs', 'feat', 'feature', 'fix', 'refactor', 'style', 'test']], + 'type-empty': [2, 'never'], + 'type-case': [2, 'always', 'lower-case'], + + 'subject-empty': [2, 'never'], + 'subject-case': [ + 0, + 'never', + ['sentence-case', 'start-case', 'pascal-case', 'upper-case'], + ], + + 'body-leading-blank': [2, 'always'], + 'body-max-line-length': [2, 'always', 200], + 'body-case': [0, 'never', []], + + 'footer-leading-blank': [1, 'always'], + 'footer-max-line-length': [2, 'always', 100] + }, +}; + From 30db03f3dfb4942218f9b695e01170bfc3e28feb Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 25 Jul 2022 12:48:51 -0400 Subject: [PATCH 076/112] fix: made the regex match commitlint more closely --- .githooks/commit-msg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.githooks/commit-msg b/.githooks/commit-msg index c2cd09aecf..48a347456b 100755 --- a/.githooks/commit-msg +++ b/.githooks/commit-msg @@ -35,7 +35,7 @@ test "" = "$(grep '^Signed-off-by: ' "$1" | .githooks/gitlint \ --msg-file=$1 \ - --subject-regex="^([bB]uild|[cC]hore|[cC]i|[dD]ocs|[fF]eat|[fF]eature|[fF]ix|[pP]erf|[rR]efactor|[rR]evert|[sS]tyle|[tT]est)(.*)?\s?:\s?.*" \ + --subject-regex="^(build|chore|ci|docs|feat|feature|fix|perf|refactor|revert|style|test)(.*)?:\s?.*" \ --subject-maxlen=100 \ --subject-minlen=10 \ --body-regex=".*" \ From 02e3e7c49adce11959df93aac58aed35901ecb46 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 25 Jul 2022 13:58:03 -0300 Subject: [PATCH 077/112] feat: implement new toggle --- .../widgets/settings_appearance_view.dart | 6 ++- .../presentation/widgets/toggle/toggle.dart | 52 +++++++++++++++++++ .../widgets/toggle/toggle_style.dart | 35 +++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart create mode 100644 frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle_style.dart diff --git a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart index e03f1fbc3b..85b78ae3b0 100644 --- a/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart +++ b/frontend/app_flowy/lib/workspace/presentation/settings/widgets/settings_appearance_view.dart @@ -1,10 +1,13 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/workspace/application/appearance.dart'; +import 'package:app_flowy/workspace/presentation/widgets/toggle/toggle_style.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import '../../widgets/toggle/toggle.dart'; + class SettingsAppearanceView extends StatelessWidget { const SettingsAppearanceView({Key? key}) : super(key: key); @@ -25,11 +28,12 @@ class SettingsAppearanceView extends StatelessWidget { fontWeight: FontWeight.w500, ), ), - Switch( + Toggle( value: theme.isDark, onChanged: (val) { context.read().swapTheme(); }, + style: ToggleStyle.big(theme), ), Text( LocaleKeys.settings_appearance_darkLabel.tr(), diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart new file mode 100644 index 0000000000..9b0d8de891 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart @@ -0,0 +1,52 @@ +import 'package:app_flowy/workspace/presentation/widgets/toggle/toggle_style.dart'; +import 'package:flutter/widgets.dart'; + +class Toggle extends StatelessWidget { + final ToggleStyle style; + final bool value; + final void Function(bool) onChanged; + final EdgeInsets padding; + + const Toggle({ + Key? key, + required this.value, + required this.onChanged, + required this.style, + this.padding = const EdgeInsets.all(8.0), + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: (() => onChanged(value)), + child: Padding( + padding: padding, + child: Stack( + children: [ + Container( + height: style.height, + width: style.width, + decoration: BoxDecoration( + color: style.backgroundColor, + borderRadius: BorderRadius.circular(style.height / 2), + ), + ), + AnimatedPositioned( + duration: const Duration(milliseconds: 150), + top: (style.height - style.thumbRadius) / 2, + left: value ? 1 : style.width - style.thumbRadius - 1, + child: Container( + height: style.thumbRadius, + width: style.thumbRadius, + decoration: BoxDecoration( + color: style.thumbColor, + borderRadius: BorderRadius.circular(style.thumbRadius / 2), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle_style.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle_style.dart new file mode 100644 index 0000000000..f20344ccf8 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle_style.dart @@ -0,0 +1,35 @@ +import 'package:flowy_infra/theme.dart'; +import 'package:flutter/painting.dart'; +import 'package:flutter/widgets.dart'; + +class ToggleStyle { + final double height; + final double width; + + final double thumbRadius; + + final Color backgroundColor; + final Color thumbColor; + + ToggleStyle({ + required this.height, + required this.width, + required this.thumbRadius, + required this.backgroundColor, + required this.thumbColor, + }); + + ToggleStyle.big(AppTheme theme) + : height = 16, + width = 27, + thumbRadius = 14, + backgroundColor = theme.main1, + thumbColor = theme.surface; + + ToggleStyle.small(AppTheme theme) + : height = 10, + width = 16, + thumbRadius = 8, + backgroundColor = theme.main1, + thumbColor = theme.surface; +} From 07f300f0327f51145fd1354a91075735f6dd5bac Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 25 Jul 2022 14:20:32 -0300 Subject: [PATCH 078/112] fix: change the animation logic --- .../lib/workspace/presentation/widgets/toggle/toggle.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart index 9b0d8de891..1d76083485 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart @@ -34,7 +34,7 @@ class Toggle extends StatelessWidget { AnimatedPositioned( duration: const Duration(milliseconds: 150), top: (style.height - style.thumbRadius) / 2, - left: value ? 1 : style.width - style.thumbRadius - 1, + left: value ? style.width - style.thumbRadius - 1 : 1, child: Container( height: style.thumbRadius, width: style.thumbRadius, From 244549b1672f6642d9f6cf6095a3d4d86c0830cd Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 25 Jul 2022 13:37:58 -0400 Subject: [PATCH 079/112] fix: bah! removing duplicate code. --- frontend/scripts/install_dev_env/install_linux.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontend/scripts/install_dev_env/install_linux.sh b/frontend/scripts/install_dev_env/install_linux.sh index eafc15ae98..396a66cd63 100755 --- a/frontend/scripts/install_dev_env/install_linux.sh +++ b/frontend/scripts/install_dev_env/install_linux.sh @@ -68,11 +68,6 @@ cargo install --force cargo-make printMessage "Installing duckscript." cargo install --force duckscript_cli -# Install CommitLint -printMessage "Installing go-gitlint." -wget https://github.com/llorllale/go-gitlint/releases/download/1.1.0/go-gitlint_1.1.0_linux_x86_64.tar.gz -tar -xf go-gitlint_1.1.0_linux_x86_64.tar.gz - C - # Check prerequisites printMessage "Checking prerequisites." cargo make flowy_dev From 729555435538f5fe75bc65af949f51cb5f50f25b Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62367544+tilucasoli@users.noreply.github.com> Date: Mon, 25 Jul 2022 14:45:37 -0300 Subject: [PATCH 080/112] fix: inative background color --- .../presentation/widgets/toggle/toggle.dart | 2 +- .../presentation/widgets/toggle/toggle_style.dart | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart index 1d76083485..4de1c7d376 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle.dart @@ -27,7 +27,7 @@ class Toggle extends StatelessWidget { height: style.height, width: style.width, decoration: BoxDecoration( - color: style.backgroundColor, + color: value ? style.activeBackgroundColor : style.inactiveBackgroundColor, borderRadius: BorderRadius.circular(style.height / 2), ), ), diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle_style.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle_style.dart index f20344ccf8..683abfab5f 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle_style.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/toggle/toggle_style.dart @@ -7,29 +7,32 @@ class ToggleStyle { final double width; final double thumbRadius; - - final Color backgroundColor; final Color thumbColor; + final Color activeBackgroundColor; + final Color inactiveBackgroundColor; ToggleStyle({ required this.height, required this.width, required this.thumbRadius, - required this.backgroundColor, required this.thumbColor, + required this.activeBackgroundColor, + required this.inactiveBackgroundColor, }); ToggleStyle.big(AppTheme theme) : height = 16, width = 27, thumbRadius = 14, - backgroundColor = theme.main1, + activeBackgroundColor = theme.main1, + inactiveBackgroundColor = theme.shader5, thumbColor = theme.surface; ToggleStyle.small(AppTheme theme) : height = 10, width = 16, thumbRadius = 8, - backgroundColor = theme.main1, + activeBackgroundColor = theme.main1, + inactiveBackgroundColor = theme.shader5, thumbColor = theme.surface; } From 51617d9eb9f67044291b5bb96dd8e0a95fd61242 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 25 Jul 2022 17:17:11 -0400 Subject: [PATCH 081/112] docs: made small changes to grammar --- .../flowy-grid/src/entities/block_entities.rs | 4 +- .../flowy-grid/src/entities/field_entities.rs | 6 +- frontend/rust-lib/flowy-grid/src/event_map.rs | 68 +++++++++---------- .../selection_type_option/select_option.rs | 4 +- .../src/revision/grid_rev.rs | 9 ++- 5 files changed, 44 insertions(+), 47 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs index df09416860..8637e35aed 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -5,7 +5,7 @@ use flowy_grid_data_model::revision::RowRevision; use std::sync::Arc; -/// [GridBlockPB] contains list of rows. The row here does not contain any data, just the id +/// [GridBlockPB] contains list of row ids. The rows here does not contain any data, just the id /// of the row. Check out [GridRowPB] for more details. /// /// @@ -30,7 +30,7 @@ impl GridBlockPB { } } -/// [GridRowPB] describes the row belongs to which block and the metadata of the row. +/// [GridRowPB] Describes a row. Has the id of the parent Block. Has the metadata of the row. #[derive(Debug, Default, Clone, ProtoBuf)] pub struct GridRowPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index f51685798c..f22998c0f9 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -9,7 +9,7 @@ use std::sync::Arc; use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString}; -/// [GridFieldPB] defines the field's attributes. Such as the name, field_type, and width. etc. +/// [GridFieldPB] defines a Field's attributes. Such as the name, field_type, and width. etc. #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridFieldPB { #[pb(index = 1)] @@ -391,7 +391,7 @@ pub struct UpdateFieldTypeOptionPayloadPB { #[pb(index = 2)] pub field_id: String, - /// Check out the [FieldTypeOptionDataPB] for more details. + /// Check out [FieldTypeOptionDataPB] for more details. #[pb(index = 3)] pub type_option_data: Vec, } @@ -444,7 +444,7 @@ impl TryInto for QueryFieldPayloadPB { } } -/// [FieldChangesetPayloadPB] is used to modify the corresponding field. It defines which property of +/// [FieldChangesetPayloadPB] is used to modify the corresponding field. It defines which properties of /// the field can be modified. /// /// Pass in None if you don't want to modify a property diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index c072355f20..f8b3c36d33 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -50,41 +50,40 @@ pub fn create(grid_manager: Arc) -> Module { pub enum GridEvent { /// [GetGrid] event is used to get the [GridPB] /// - /// The event handler accepts [GridIdPB] and return [GridPB] if there is no errors. - /// + /// The event handler accepts a [GridIdPB] and returns a [GridPB] if there are no errors. #[event(input = "GridIdPB", output = "GridPB")] GetGrid = 0, /// [GetGridBlocks] event is used to get the grid's block. /// - /// The event handler accepts [QueryGridBlocksPayloadPB] and return [RepeatedGridBlockPB] - /// if there is no errors. + /// The event handler accepts a [QueryGridBlocksPayloadPB] and returns a [RepeatedGridBlockPB] + /// if there are no errors. #[event(input = "QueryGridBlocksPayloadPB", output = "RepeatedGridBlockPB")] GetGridBlocks = 1, - /// [GetGridSetting] event is used to get the grid's setting. + /// [GetGridSetting] event is used to get the grid's settings. /// /// The event handler accepts [GridIdPB] and return [GridSettingPB] /// if there is no errors. #[event(input = "GridIdPB", output = "GridSettingPB")] GetGridSetting = 2, - /// [UpdateGridSetting] event is used to update the grid's setting. + /// [UpdateGridSetting] event is used to update the grid's settings. /// - /// The event handler accepts [GridIdPB] and return errors if failed to modify the grid's setting. + /// The event handler accepts [GridIdPB] and return errors if failed to modify the grid's settings. #[event(input = "GridIdPB", input = "GridSettingChangesetPayloadPB")] UpdateGridSetting = 3, - /// [GetFields] event is used to get the grid's setting. + /// [GetFields] event is used to get the grid's settings. /// - /// The event handler accepts [QueryFieldPayloadPB] and return [RepeatedGridFieldPB] - /// if there is no errors. + /// The event handler accepts a [QueryFieldPayloadPB] and returns a [RepeatedGridFieldPB] + /// if there are no errors. #[event(input = "QueryFieldPayloadPB", output = "RepeatedGridFieldPB")] GetFields = 10, - /// [UpdateField] event is used to update the field attributes. + /// [UpdateField] event is used to update a field's attributes. /// - /// The event handler accepts [FieldChangesetPayloadPB] and return errors if failed to modify the + /// The event handler accepts a [FieldChangesetPayloadPB] and returns errors if failed to modify the /// field. #[event(input = "FieldChangesetPayloadPB")] UpdateField = 11, @@ -98,28 +97,28 @@ pub enum GridEvent { /// Check out [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid#fieldtype) /// for more information. /// - /// The event handler accepts [UpdateFieldTypeOptionPayloadPB] and return errors if failed to modify the + /// The event handler accepts a [UpdateFieldTypeOptionPayloadPB] and returns errors if failed to modify the /// field. #[event(input = "UpdateFieldTypeOptionPayloadPB")] UpdateFieldTypeOption = 12, - /// [InsertField] event is used to insert a new field. If the field is already exists, the event - /// handler will replace the value with the new field value. + /// [InsertField] event is used to insert a new Field. If the Field already exists, the event + /// handler will replace the value with the new Field value. #[event(input = "InsertFieldPayloadPB")] InsertField = 13, - /// [DeleteField] event is used to delete a new field. [DeleteFieldPayloadPB] is the context that + /// [DeleteField] event is used to delete a Field. [DeleteFieldPayloadPB] is the context that /// is used to delete the field from the Grid. #[event(input = "DeleteFieldPayloadPB")] DeleteField = 14, - /// [SwitchToField] event is used to update the current field's type. + /// [SwitchToField] event is used to update the current Field's type. /// It will insert a new FieldTypeOptionData if the new FieldType doesn't exist before, otherwise /// reuse the existing FieldTypeOptionData. You could check the [GridRevisionPad] for more details. #[event(input = "EditFieldPayloadPB", output = "FieldTypeOptionDataPB")] SwitchToField = 20, - /// [DuplicateField] event is used to duplicate the field. The duplicated field data is kind of + /// [DuplicateField] event is used to duplicate a Field. The duplicated field data is kind of /// deep copy of the target field. The passed in [DuplicateFieldPayloadPB] is the context that is /// used to duplicate the field. /// @@ -128,17 +127,17 @@ pub enum GridEvent { #[event(input = "DuplicateFieldPayloadPB")] DuplicateField = 21, - /// [MoveItem] event is used to move the item. For the moment, the item has two types defined in - /// the [MoveItemTypePB]. + /// [MoveItem] event is used to move an item. For the moment, Item has two types defined in + /// [MoveItemTypePB]. #[event(input = "MoveItemPayloadPB")] MoveItem = 22, - /// [GetFieldTypeOption] event is used to get the FieldTypeOption data for the specific field type. + /// [GetFieldTypeOption] event is used to get the FieldTypeOption data for a specific field type. /// /// Check out the [FieldTypeOptionDataPB] for more details. If the [FieldTypeOptionData] does exist /// for the target type, the [TypeOptionBuilder] will create the default data for that type. /// - /// Return the [FieldTypeOptionDataPB] if there is no errors. + /// Return the [FieldTypeOptionDataPB] if there are no errors. #[event(input = "GridFieldTypeOptionIdPB", output = "FieldTypeOptionDataPB")] GetFieldTypeOption = 23, @@ -146,8 +145,8 @@ pub enum GridEvent { #[event(input = "CreateFieldPayloadPB", output = "FieldTypeOptionDataPB")] CreateFieldTypeOption = 24, - /// [NewSelectOption] event is used to create a new select option. Return the [SelectOptionPB] if - /// there is no errors. + /// [NewSelectOption] event is used to create a new select option. Returns a [SelectOptionPB] if + /// there are no errors. #[event(input = "CreateSelectOptionPayloadPB", output = "SelectOptionPB")] NewSelectOption = 30, @@ -157,13 +156,12 @@ pub enum GridEvent { #[event(input = "GridCellIdPB", output = "SelectOptionCellDataPB")] GetSelectOptionCellData = 31, - /// [UpdateSelectOption] event is used to update the FieldTypeOptionData that its field_type is + /// [UpdateSelectOption] event is used to update a FieldTypeOptionData whose field_type is /// FieldType::SingleSelect or FieldType::MultiSelect. /// /// This event may trigger the GridNotification::DidUpdateCell event. - /// For example, the [SelectOptionChangesetPayloadPB] carries a change that update the name of - /// the option. - /// + /// For example, GridNotification::DidUpdateCell will be triggered if the [SelectOptionChangesetPayloadPB] + /// carries a change that updates the name of the option. #[event(input = "SelectOptionChangesetPayloadPB")] UpdateSelectOption = 32, @@ -187,23 +185,23 @@ pub enum GridEvent { /// [UpdateCell] event is used to update the cell content. The passed in data, [CellChangesetPB], /// carries the changes that will be applied to the cell content by calling `update_cell` function. /// - /// The 'content' property of the [CellChangesetPB] is String type. It can be used directly if the - /// cell use string data. For example, the TextCell or NumberCell. + /// The 'content' property of the [CellChangesetPB] is a String type. It can be used directly if the + /// cell uses string data. For example, the TextCell or NumberCell. /// /// But,it can be treated as a generic type, because we can use [serde] to deserialize the string - /// into a specific data type.For the moment, the 'content' will be deserialized to concrete type - /// when the FieldType is SingleSelect, DateTime, and MultiSelect. We will discuss the details - /// in [UpdateSelectOptionCell] and [UpdateDateCell] event. + /// into a specific data type. For the moment, the 'content' will be deserialized to a concrete type + /// when the FieldType is SingleSelect, DateTime, and MultiSelect. Please see + /// the [UpdateSelectOptionCell] and [UpdateDateCell] events for more details. #[event(input = "CellChangesetPB")] UpdateCell = 71, - /// [UpdateSelectOptionCell] event is used to update the select option cell data. [SelectOptionCellChangesetPayloadPB] + /// [UpdateSelectOptionCell] event is used to update a select option cell's data. [SelectOptionCellChangesetPayloadPB] /// contains options that will be deleted or inserted. It can be cast to [CellChangesetPB] that /// will be used by the `update_cell` function. #[event(input = "SelectOptionCellChangesetPayloadPB")] UpdateSelectOptionCell = 72, - /// [UpdateDateCell] event is used to update the date cell data. [DateChangesetPayloadPB] + /// [UpdateDateCell] event is used to update a date cell's data. [DateChangesetPayloadPB] /// contains the date and the time string. It can be cast to [CellChangesetPB] that /// will be used by the `update_cell` function. #[event(input = "DateChangesetPayloadPB")] diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index ea57931bb8..e9b0b1ed41 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; pub const SELECTION_IDS_SEPARATOR: &str = ","; -/// [SelectOptionPB] represents an option for the single select, and multiple select. +/// [SelectOptionPB] represents an option for a single select, and multiple select. #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)] pub struct SelectOptionPB { #[pb(index = 1)] @@ -340,7 +340,7 @@ pub struct SelectOptionCellDataPB { } -/// [SelectOptionChangesetPayloadPB] describes the changes of the FieldTypeOptionData. For the moment, +/// [SelectOptionChangesetPayloadPB] describes the changes of a FieldTypeOptionData. For the moment, /// it is used by [MultiSelectTypeOptionPB] and [SingleSelectTypeOptionPB]. #[derive(Clone, Debug, Default, ProtoBuf)] pub struct SelectOptionChangesetPayloadPB { 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 1bc7139d9a..09056f827d 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 @@ -125,7 +125,6 @@ pub struct FieldRevision { /// value: type option data that can be parsed into specified TypeOptionStruct. /// /// For example, CheckboxTypeOption, MultiSelectTypeOption etc. - /// #[serde(with = "indexmap::serde_seq")] pub type_options: IndexMap, @@ -187,15 +186,15 @@ impl FieldRevision { } } -/// The macro, [impl_type_option] will implement the [TypeOptionDataEntry] for the type that -/// supports serde trait and TryInto trait. +/// The macro [impl_type_option] will implement the [TypeOptionDataEntry] for the type that +/// supports the serde trait and the TryInto trait. pub trait TypeOptionDataEntry { fn json_str(&self) -> String; fn protobuf_bytes(&self) -> Bytes; } -/// The macro, [impl_type_option] will implement the [TypeOptionDataDeserializer] for the type that -/// supports serde trait and TryFrom trait. +/// The macro [impl_type_option] will implement the [TypeOptionDataDeserializer] for the type that +/// supports the serde trait and the TryFrom trait. pub trait TypeOptionDataDeserializer { fn from_json_str(s: &str) -> Self; fn from_protobuf_bytes(bytes: Bytes) -> Self; From 7436f7de3ea7fe3779fc036676d75235482ac2d5 Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Mon, 25 Jul 2022 18:34:26 -0400 Subject: [PATCH 082/112] docs: made minor changes to grammar --- shared-lib/lib-ot/src/core/delta/builder.rs | 2 +- shared-lib/lib-ot/src/core/delta/cursor.rs | 10 +++++----- shared-lib/lib-ot/src/core/operation/operation.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/shared-lib/lib-ot/src/core/delta/builder.rs b/shared-lib/lib-ot/src/core/delta/builder.rs index 9e67495da0..44e4d4dbac 100644 --- a/shared-lib/lib-ot/src/core/delta/builder.rs +++ b/shared-lib/lib-ot/src/core/delta/builder.rs @@ -46,7 +46,7 @@ where self } - /// Insert the string with attributes. Use 'insert' instead if you don't + /// Inserts the string with attributes. Use 'insert' instead if you don't /// need any attributes. pub fn insert_with_attributes(mut self, s: &str, attrs: T) -> Self { self.delta.insert(s, attrs); diff --git a/shared-lib/lib-ot/src/core/delta/cursor.rs b/shared-lib/lib-ot/src/core/delta/cursor.rs index a465d62dea..2243adb7b3 100644 --- a/shared-lib/lib-ot/src/core/delta/cursor.rs +++ b/shared-lib/lib-ot/src/core/delta/cursor.rs @@ -53,17 +53,17 @@ where cursor } - /// Return the next operation interval + /// Returns the next operation interval pub fn next_iv(&self) -> Interval { self.next_iv_with_len(None).unwrap_or_else(|| Interval::new(0, 0)) } - /// Return the next operation + /// Returns the next operation pub fn get_next_op(&mut self) -> Option> { self.next_with_len(None) } - /// Return the reference of the next operation + /// Returns the reference of the next operation pub fn next_op(&self) -> Option<&Operation> { let mut next_op = self.next_op.as_ref(); if next_op.is_none() { @@ -138,8 +138,8 @@ where self.next_op().is_some() } - /// Find the op within the current offset. - /// This function sets the start of the consume_iv to the offset, update the consume_count + /// Finds the op within the current offset. + /// This function sets the start of the consume_iv to the offset, updates the consume_count /// and the next_op reference. /// /// # Arguments diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index ac56025621..26ac7650ec 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -41,7 +41,7 @@ pub trait OperationTransformable { where Self: Sized; - /// Return the invert delta from the other. It can be used to do the undo operation. + /// Returns the invert delta from the other. It can be used to do the undo operation. /// /// # Arguments /// From e89e40d652cc75c853031c13ad949a5cbd7ab05a Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Tue, 26 Jul 2022 11:58:21 +0800 Subject: [PATCH 083/112] fix: update faccess version from 0.2.3 to 0.2.4 for fixing linux-arm64 building (https://github.com/Freaky/faccess/pull/1) --- frontend/rust-lib/Cargo.lock | 4 ++-- shared-lib/Cargo.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/rust-lib/Cargo.lock b/frontend/rust-lib/Cargo.lock index d452c1a025..643237bfe6 100644 --- a/frontend/rust-lib/Cargo.lock +++ b/frontend/rust-lib/Cargo.lock @@ -754,9 +754,9 @@ dependencies = [ [[package]] name = "faccess" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e039175679baf763ddddf4f76900b92d4dae9411ee88cf42d2f11b976b09e07c" +checksum = "59ae66425802d6a903e268ae1a08b8c38ba143520f227a205edf4e9c7e3e26d5" dependencies = [ "bitflags", "libc", diff --git a/shared-lib/Cargo.lock b/shared-lib/Cargo.lock index 62d70be943..9b8e5f6081 100644 --- a/shared-lib/Cargo.lock +++ b/shared-lib/Cargo.lock @@ -332,9 +332,9 @@ dependencies = [ [[package]] name = "faccess" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e039175679baf763ddddf4f76900b92d4dae9411ee88cf42d2f11b976b09e07c" +checksum = "59ae66425802d6a903e268ae1a08b8c38ba143520f227a205edf4e9c7e3e26d5" dependencies = [ "bitflags", "libc", From 274033afd339ed8cc3e7bbc64931557f84eb1d8a Mon Sep 17 00:00:00 2001 From: Annie Date: Tue, 26 Jul 2022 14:23:41 +0800 Subject: [PATCH 084/112] chore: update ROADMAP.md v1 --- ROADMAP.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/ROADMAP.md b/ROADMAP.md index 48c6f116be..ab58383acd 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,11 +1,56 @@ # View the official [AppFlowy public roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) +Our [roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) is where you can learn about the features we’re working on, their status, and when we expect to release them. Have any questions or comments about items on the roadmap? Or feedback about the roadmap itself, such as how issues are presented? Share your feedback via the [discussions](https://github.com/AppFlowy-IO/AppFlowy/discussions). + ## Guide to the roadmap + ### Labels +Every item on the roadmap is an issue, with labels that indicate each of the following: +- bug: something needs fixing +- new feature: this is something new for the end user +- improvements: an improvement on an existing feature +- documentation: this is a documentation task +- needs design: this requires a design spec +- grid: features related to Flowy Grid +- editor: features related to Flowy Editor +- help-wanted: for the community members to claim +- first time issue for devs: for the community members to claim +- first time issue for experienced devs: for the experienced community developers to claim + ### Item Status +“Status” indicates the stages that the feature goes through, from “Need triage” to “Done”. Most of the options are self explanatory.: +- Need triage +- Need test for Windows / Linux / macOS +- Wait for reporter +- Ready for assess +- Planned: included in our plan +- Not Planned: decided against it +- ToDo: in the queue of the upcoming development (next two releases) +- In progress: currently in development +- Blocked: have started but can’t proceed as it is blocked by something +- Done: the development is finished and merged into the main branch + + ### Milestones +The roadmap is arranged on a project board to give a sense of how far out each item is on the horizon. If a feature is planned, it is already or will be added to a particular milestone, aka release. For example, “Implement FlowyEditor’s RichText component” is added to v0.0.7. You will also find issues that are not planned for which no milestone is yet available. In addition, you can see a list of milestones that are already planned and track their progress [here](https://github.com/AppFlowy-IO/AppFlowy/milestones). + ### Views +To easily track the project based on your interest, we organize issues into different views as follows: +- [Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) +- [v0.0.x](https://github.com/orgs/AppFlowy-IO/projects/5/views/1) +- [Upcoming](https://github.com/orgs/AppFlowy-IO/projects/5/views/3) +- [Help Wanted](https://github.com/orgs/AppFlowy-IO/projects/5/views/4) +- [Editor](https://github.com/orgs/AppFlowy-IO/projects/5/views/5) +- [Grid](https://github.com/orgs/AppFlowy-IO/projects/5/views/6) +- [Bug Tracker](https://github.com/orgs/AppFlowy-IO/projects/5/views/9) + +If you are interested in contributing to AppFlowy, please have a look at the “[Help Wanted](https://github.com/orgs/AppFlowy-IO/projects/5/views/4)” tab where we maintain a list of issues open to the community. +Flowy Editor and Flowy Grid are two key components AppFlowy offers. Flowy Editor is a rich-text editor. Flowy Grid is a database component that can be inserted into Flowy Editor. Both components are developed by AppFlowy’s team from the ground up. You can use the “Editor” and the “Grid” tab to track the development progress of these two components. ## Disclaimer +The roadmap is subject to change, especially further out on the timeline. Any statement in this repository that is not purely historical is considered a forward-looking statement. The forward-looking roadmap does not represent a commitment, guarantee, obligation or promise to deliver any product or feature, or the deliver any product and feature by any particular date, and is intended to outline the general development plans. + ## Acknowledgements +This article is adapted from GitHub public roadmap’s [README.md](https://github.com/github/roadmap) + From 6c937f3bafdea113e9c3c98d1490321740004a4f Mon Sep 17 00:00:00 2001 From: Annie Date: Tue, 26 Jul 2022 14:27:01 +0800 Subject: [PATCH 085/112] chore: update README.md update AppFlowy roadmap links --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9aa15e40ae..09538537dd 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,8 @@ Please view the [documentation](https://appflowy.gitbook.io/docs/essential-docum ## Roadmap -[AppFlowy Roadmap](https://trello.com/b/NCyXCXXh/appflowy-roadmap) +- [AppFlowy Roadmap ReadMe](https://github.com/AppFlowy-IO/AppFlowy/blob/main/ROADMAP.md) +- [AppFlowy Public Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) If you'd like to propose a feature, submit an issue [here](https://github.com/AppFlowy-IO/appflowy/issues). From 3f71613a84ace5a15b157d7bce29139c74bae5f1 Mon Sep 17 00:00:00 2001 From: Annie Date: Tue, 26 Jul 2022 14:33:35 +0800 Subject: [PATCH 086/112] chore: update ROADMAP.md v1.1 --- ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ROADMAP.md b/ROADMAP.md index ab58383acd..d7c893f809 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,5 +1,5 @@ # View the official [AppFlowy public roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) -Our [roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) is where you can learn about the features we’re working on, their status, and when we expect to release them. Have any questions or comments about items on the roadmap? Or feedback about the roadmap itself, such as how issues are presented? Share your feedback via the [discussions](https://github.com/AppFlowy-IO/AppFlowy/discussions). +Our [roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) is where you can learn about the features we’re working on, their status, when we expect to release them, and how you can help us. Have any questions or comments about items on the roadmap? Or feedback about the roadmap itself, such as how issues are presented? Share your feedback via the [discussions](https://github.com/AppFlowy-IO/AppFlowy/discussions). ## Guide to the roadmap From 0c20a7b092cbc1e40a33f64ddb4391d322cec85e Mon Sep 17 00:00:00 2001 From: Poly-Pixel <79737178+Poly-Pixel@users.noreply.github.com> Date: Tue, 26 Jul 2022 22:25:44 -0400 Subject: [PATCH 087/112] fix: fix yaml syntax in rust_lint github workflow --- .github/workflows/rust_lint.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust_lint.yml b/.github/workflows/rust_lint.yml index 4f364a616a..3401b5b9bb 100644 --- a/.github/workflows/rust_lint.yml +++ b/.github/workflows/rust_lint.yml @@ -17,9 +17,9 @@ jobs: steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 - with: - toolchain: 'stable-2022-01-20' - override: true + with: + toolchain: 'stable-2022-01-20' + override: true - name: Rust Deps working-directory: frontend @@ -40,7 +40,7 @@ jobs: - run: rustup component add clippy - working-directory: frontend/rust-lib + working-directory: frontend/rust-lib - name: clippy run: cargo clippy --no-default-features working-directory: frontend/rust-lib From 16fdad83c2e210959e1a070d16d12c586ae8fdcf Mon Sep 17 00:00:00 2001 From: MikeWallaceDev Date: Tue, 26 Jul 2022 22:42:58 -0400 Subject: [PATCH 088/112] fix: moved the roadmap to gitbook --- ROADMAP.md | 58 ++---------------------------------------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index d7c893f809..8cd26e20d2 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,56 +1,2 @@ -# View the official [AppFlowy public roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) -Our [roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) is where you can learn about the features we’re working on, their status, when we expect to release them, and how you can help us. Have any questions or comments about items on the roadmap? Or feedback about the roadmap itself, such as how issues are presented? Share your feedback via the [discussions](https://github.com/AppFlowy-IO/AppFlowy/discussions). - - -## Guide to the roadmap - -### Labels -Every item on the roadmap is an issue, with labels that indicate each of the following: -- bug: something needs fixing -- new feature: this is something new for the end user -- improvements: an improvement on an existing feature -- documentation: this is a documentation task -- needs design: this requires a design spec -- grid: features related to Flowy Grid -- editor: features related to Flowy Editor -- help-wanted: for the community members to claim -- first time issue for devs: for the community members to claim -- first time issue for experienced devs: for the experienced community developers to claim - -### Item Status -“Status” indicates the stages that the feature goes through, from “Need triage” to “Done”. Most of the options are self explanatory.: -- Need triage -- Need test for Windows / Linux / macOS -- Wait for reporter -- Ready for assess -- Planned: included in our plan -- Not Planned: decided against it -- ToDo: in the queue of the upcoming development (next two releases) -- In progress: currently in development -- Blocked: have started but can’t proceed as it is blocked by something -- Done: the development is finished and merged into the main branch - - -### Milestones -The roadmap is arranged on a project board to give a sense of how far out each item is on the horizon. If a feature is planned, it is already or will be added to a particular milestone, aka release. For example, “Implement FlowyEditor’s RichText component” is added to v0.0.7. You will also find issues that are not planned for which no milestone is yet available. In addition, you can see a list of milestones that are already planned and track their progress [here](https://github.com/AppFlowy-IO/AppFlowy/milestones). - -### Views -To easily track the project based on your interest, we organize issues into different views as follows: -- [Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) -- [v0.0.x](https://github.com/orgs/AppFlowy-IO/projects/5/views/1) -- [Upcoming](https://github.com/orgs/AppFlowy-IO/projects/5/views/3) -- [Help Wanted](https://github.com/orgs/AppFlowy-IO/projects/5/views/4) -- [Editor](https://github.com/orgs/AppFlowy-IO/projects/5/views/5) -- [Grid](https://github.com/orgs/AppFlowy-IO/projects/5/views/6) -- [Bug Tracker](https://github.com/orgs/AppFlowy-IO/projects/5/views/9) - -If you are interested in contributing to AppFlowy, please have a look at the “[Help Wanted](https://github.com/orgs/AppFlowy-IO/projects/5/views/4)” tab where we maintain a list of issues open to the community. -Flowy Editor and Flowy Grid are two key components AppFlowy offers. Flowy Editor is a rich-text editor. Flowy Grid is a database component that can be inserted into Flowy Editor. Both components are developed by AppFlowy’s team from the ground up. You can use the “Editor” and the “Grid” tab to track the development progress of these two components. - -## Disclaimer -The roadmap is subject to change, especially further out on the timeline. Any statement in this repository that is not purely historical is considered a forward-looking statement. The forward-looking roadmap does not represent a commitment, guarantee, obligation or promise to deliver any product or feature, or the deliver any product and feature by any particular date, and is intended to outline the general development plans. - - -## Acknowledgements -This article is adapted from GitHub public roadmap’s [README.md](https://github.com/github/roadmap) - +# Find information about our official [AppFlowy public roadmap](https://appflowy.gitbook.io/docs/essential-documentation/roadmap) on Gitbook. +Our [roadmap](https://appflowy.gitbook.io/docs/essential-documentation/roadmap) is where you can learn about the features we’re working on, their status, when we expect to release them, and how you can help us. \ No newline at end of file From 1e813524ebf60353b7b9579425770b94ac85f1aa Mon Sep 17 00:00:00 2001 From: Annie Date: Wed, 27 Jul 2022 17:29:47 +0800 Subject: [PATCH 089/112] chore: update ROADMAP.md update links and reorder the contents --- ROADMAP.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 8cd26e20d2..53ac484771 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,2 +1,3 @@ -# Find information about our official [AppFlowy public roadmap](https://appflowy.gitbook.io/docs/essential-documentation/roadmap) on Gitbook. -Our [roadmap](https://appflowy.gitbook.io/docs/essential-documentation/roadmap) is where you can learn about the features we’re working on, their status, when we expect to release them, and how you can help us. \ No newline at end of file +## Our [roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) is where you can learn about the features we’re working on, their status, when we expect to release them, and how you can help us. + +## Find more information about how to use our official AppFlowy public roadmap on [Gitbook](https://appflowy.gitbook.io/docs/essential-documentation/roadmap). From 17409213a340500bbd751082116d7b3ecb368f25 Mon Sep 17 00:00:00 2001 From: Annie Date: Wed, 27 Jul 2022 17:32:57 +0800 Subject: [PATCH 090/112] chore: update README.md Update the roadmap readme linking to GitBook --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 09538537dd..2a2ae6f8af 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Please view the [documentation](https://appflowy.gitbook.io/docs/essential-docum ## Roadmap -- [AppFlowy Roadmap ReadMe](https://github.com/AppFlowy-IO/AppFlowy/blob/main/ROADMAP.md) +- [AppFlowy Roadmap ReadMe](https://appflowy.gitbook.io/docs/essential-documentation/roadmap) - [AppFlowy Public Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) If you'd like to propose a feature, submit an issue [here](https://github.com/AppFlowy-IO/appflowy/issues). From 5eb8a60f911c480915c6a50466cadfed9fd374ac Mon Sep 17 00:00:00 2001 From: Poly-Pixel <79737178+Poly-Pixel@users.noreply.github.com> Date: Wed, 27 Jul 2022 10:02:22 -0400 Subject: [PATCH 091/112] fix: add flutter action for access to dart --- .github/workflows/rust_lint.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/rust_lint.yml b/.github/workflows/rust_lint.yml index 3401b5b9bb..83ecd62280 100644 --- a/.github/workflows/rust_lint.yml +++ b/.github/workflows/rust_lint.yml @@ -20,6 +20,10 @@ jobs: with: toolchain: 'stable-2022-01-20' override: true + - uses: subosito/flutter-action@v1 + with: + flutter-version: '3.0.0' + channel: "stable" - name: Rust Deps working-directory: frontend From 5309b2a7574fcf6c81ffbe614b22591200e31f81 Mon Sep 17 00:00:00 2001 From: Poly-Pixel <79737178+Poly-Pixel@users.noreply.github.com> Date: Wed, 27 Jul 2022 10:42:33 -0400 Subject: [PATCH 092/112] style: run cargo fmt --- .../rust-lib/flowy-grid/src/entities/cell_entities.rs | 2 -- .../rust-lib/flowy-grid/src/entities/field_entities.rs | 8 -------- frontend/rust-lib/flowy-grid/src/entities/row_entities.rs | 1 - .../date_type_option/date_type_option_entities.rs | 2 +- .../type_options/selection_type_option/select_option.rs | 2 +- .../rust-lib/flowy-grid/tests/grid/block_test/script.rs | 2 +- 6 files changed, 3 insertions(+), 14 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs index 30e8d65018..6c5402b340 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/cell_entities.rs @@ -1,4 +1,3 @@ - use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; @@ -21,7 +20,6 @@ pub struct CreateSelectOptionParams { pub field_id: String, pub grid_id: String, pub option_name: String, - } impl TryInto for CreateSelectOptionPayloadPB { diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index 760b820233..695dd0e326 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -155,8 +155,6 @@ pub struct GetEditFieldContextPayloadPB { pub field_type: FieldType, } - - #[derive(Debug, Default, ProtoBuf)] pub struct CreateFieldPayloadPB { #[pb(index = 1)] @@ -192,8 +190,6 @@ impl TryInto for CreateFieldPayloadPB { } } - - #[derive(Debug, Default, ProtoBuf)] pub struct EditFieldPayloadPB { #[pb(index = 1)] @@ -241,7 +237,6 @@ pub struct GridFieldTypeOptionIdPB { pub field_type: FieldType, } - pub struct GridFieldTypeOptionIdParams { pub grid_id: String, pub field_id: String, @@ -619,7 +614,6 @@ pub struct DuplicateFieldPayloadPB { pub grid_id: String, } - #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridFieldIdentifierPayloadPB { #[pb(index = 1)] @@ -668,5 +662,3 @@ pub struct GridFieldIdParams { pub field_id: String, pub grid_id: String, } - - diff --git a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs index d8ae0eba7a..745a5dc368 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/row_entities.rs @@ -2,7 +2,6 @@ use flowy_derive::ProtoBuf; use flowy_error::ErrorCode; use flowy_grid_data_model::parser::NotEmptyStr; - #[derive(Debug, Default, Clone, ProtoBuf)] pub struct GridRowIdPB { #[pb(index = 1)] diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs index d5da516bf1..1c54606f75 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs @@ -1,5 +1,5 @@ use crate::entities::CellChangesetPB; -use crate::entities::{GridCellIdParams, GridCellIdPB}; +use crate::entities::{GridCellIdPB, GridCellIdParams}; use crate::services::cell::{CellBytesParser, FromCellChangeset, FromCellString}; use bytes::Bytes; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index 8f441e1755..b945be430a 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -1,4 +1,4 @@ -use crate::entities::{CellChangesetPB, GridCellIdParams, FieldType, GridCellIdPB}; +use crate::entities::{CellChangesetPB, FieldType, GridCellIdPB, GridCellIdParams}; use crate::services::cell::{CellBytes, CellBytesParser, CellData, CellDisplayable, FromCellChangeset, FromCellString}; use crate::services::field::{MultiSelectTypeOption, SingleSelectTypeOptionPB}; use bytes::Bytes; diff --git a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs index 9516fd1d03..14671c2eb2 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/block_test/script.rs @@ -2,7 +2,7 @@ use crate::grid::block_test::script::RowScript::{AssertCell, CreateRow}; use crate::grid::block_test::util::GridRowTestBuilder; use crate::grid::grid_editor::GridEditorTest; -use flowy_grid::entities::{GridCellIdParams, FieldType, GridRowPB}; +use flowy_grid::entities::{FieldType, GridCellIdParams, GridRowPB}; use flowy_grid::services::field::*; use flowy_grid_data_model::revision::{ GridBlockMetaRevision, GridBlockMetaRevisionChangeset, RowMetaChangeset, RowRevision, From 62b968bdfa06aa40d9c3b41745cb5e3341fc1475 Mon Sep 17 00:00:00 2001 From: Annie Date: Thu, 28 Jul 2022 19:44:35 +0800 Subject: [PATCH 093/112] chore: update roadmap.md --- doc/roadmap.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/roadmap.md b/doc/roadmap.md index b5d7e368c9..54bef7f99b 100644 --- a/doc/roadmap.md +++ b/doc/roadmap.md @@ -1 +1,3 @@ -https://trello.com/b/NCyXCXXh/appflowy-roadmap +[AppFlowy Roadmap ReadMe](https://appflowy.gitbook.io/docs/essential-documentation/roadmap) + +[AppFlowy Public Roadmap](https://github.com/orgs/AppFlowy-IO/projects/5/views/12) From 7a197df57ce05ff953acd59e67f3b8ffe10f434c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=82=D0=BDomas?= Date: Thu, 20 Jan 2022 22:09:33 +0200 Subject: [PATCH 094/112] fix: Fixes docker-compose up error and warning --- frontend/scripts/docker-buildfiles/docker-compose.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/scripts/docker-buildfiles/docker-compose.yml b/frontend/scripts/docker-buildfiles/docker-compose.yml index 67fb26ab9f..b1be260e62 100755 --- a/frontend/scripts/docker-buildfiles/docker-compose.yml +++ b/frontend/scripts/docker-buildfiles/docker-compose.yml @@ -5,8 +5,11 @@ services: build: . stdin_open: true # tty: true + devices: + - "/dev/dri:/dev/dri" # fixes MESA-LOADER error environment: - DISPLAY=${DISPLAY} + - NO_AT_BRIDGE=1 # fixes dbind-WARNING volumes: - $HOME/.Xauthority:/root/.Xauthority:rw - network_mode: host \ No newline at end of file + network_mode: host From 32ee068c73a6b07ee6c5a1df0b74fc4910cbf439 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Mon, 18 Jul 2022 17:58:15 +0800 Subject: [PATCH 095/112] chore: resolve docker-compose.yml conflicts --- .../scripts/docker-buildfiles/docker-compose.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/frontend/scripts/docker-buildfiles/docker-compose.yml b/frontend/scripts/docker-buildfiles/docker-compose.yml index b1be260e62..ac1cc29339 100755 --- a/frontend/scripts/docker-buildfiles/docker-compose.yml +++ b/frontend/scripts/docker-buildfiles/docker-compose.yml @@ -3,13 +3,21 @@ version: "3" services: app: build: . - stdin_open: true + image: appflowy/appflowy:latest + stdin_open: true # tty: true devices: - - "/dev/dri:/dev/dri" # fixes MESA-LOADER error + - "/dev/dri:/dev/dri" # fixes MESA-LOADER error environment: - DISPLAY=${DISPLAY} - - NO_AT_BRIDGE=1 # fixes dbind-WARNING + - NO_AT_BRIDGE=1 # fixes dbind-WARNING volumes: - $HOME/.Xauthority:/root/.Xauthority:rw + - /tmp/.X11-unix:/tmp/.X11-unix + - /dev/dri:/dev/dri + - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket + - appflowy-data:/home/makepkg network_mode: host + +volumes: + appflowy-data: From 781d62002f7acda1d9e50d0d0486c682ca779071 Mon Sep 17 00:00:00 2001 From: Dennis Ziolkowski Date: Wed, 20 Jul 2022 22:27:32 +0200 Subject: [PATCH 096/112] fix: Update README.md Changed appearance of the "howtostar.gif". It was width="1000", which leads to a messy layout. Also changed the alt text for the image to a better suiting one. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a2ae6f8af..e441496c96 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Please view the [documentation](https://appflowy.gitbook.io/docs/essential-docum ## Stay Up-to-Date -

AppFlowy Github

+

AppFlowy Github - how to star the repo

## Getting Started with development Please view the [documentation](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy) for OS specific development instructions From 8360dcdc822849c91993c6485279467ae13f6b87 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 15 Mar 2022 21:08:31 +0000 Subject: [PATCH 097/112] feat: Add pl-PL translation Add pl-PL.json including the new translation. Updated app_widget.dart with the new language entry Updated language.dart with the new language entry --- .../app_flowy/assets/translations/pl-PL.json | 145 ++++++++++++++++++ .../lib/startup/tasks/app_widget.dart | 1 + .../packages/flowy_infra/lib/language.dart | 2 + 3 files changed, 148 insertions(+) create mode 100644 frontend/app_flowy/assets/translations/pl-PL.json diff --git a/frontend/app_flowy/assets/translations/pl-PL.json b/frontend/app_flowy/assets/translations/pl-PL.json new file mode 100644 index 0000000000..0105e7aec7 --- /dev/null +++ b/frontend/app_flowy/assets/translations/pl-PL.json @@ -0,0 +1,145 @@ +{ + "appName": "AppFlowy", + "defaultUsername": "Ja", + "welcomeText": "Witaj w @:appName", + "githubStarText": "Gwiazdka na GitHub-ie", + "subscribeNewsletterText": "Zapisz się do naszego Newslettera", + "letsGoButtonText": "Start!", + "title": "Tytuł", + "signUp": { + "buttonText": "Zarejestruj", + "title": "Zarejestruj się w @:appName", + "getStartedText": "Zaczynamy", + "emptyPasswordError": "Hasło nie moze być puste", + "repeatPasswordEmptyError": "Powtórzone hasło nie moze być puste", + "unmatchedPasswordError": "Hasła nie są takie same", + "alreadyHaveAnAccount": "Masz juz konto?", + "emailHint": "Email", + "passwordHint": "Hasło", + "repeatPasswordHint": "Powtórz hasło" + }, + "signIn": { + "loginTitle": "Zaloguj do @:appName", + "loginButtonText": "Logowanie", + "buttonText": "Zaloguj", + "forgotPassword": "Zapomniałem hasła?", + "emailHint": "Email", + "passwordHint": "Password", + "dontHaveAnAccount": "Nie masz konta?", + "repeatPasswordEmptyError": "Powtórzone hasło nie moze być puste", + "unmatchedPasswordError": "Hasła nie są takie same" + }, + "workspace": { + "create": "Utwórz przestrzeń", + "hint": "przestrzeń robocza", + "notFoundError": "Przestrzeni nie znaleziono" + }, + "shareAction": { + "buttonText": "Udostępnij", + "workInProgress": "Wkrótce", + "markdown": "Markdown", + "copyLink": "Skopiuj link" + }, + "disclosureAction": { + "rename": "Zmień nazwę", + "delete": "Usuń", + "duplicate": "Duplikuj" + }, + "blankPageTitle": "Pusta strona", + "newPageText": "Nowa strona", + "trash": { + "text": "Kosz", + "restoreAll": "Przywróć Wszystko", + "deleteAll": "Usuń Wszystko", + "pageHeader": { + "fileName": "Nazwa Pliku", + "lastModified": "Ostatnio Zmodyfikowano", + "created": "Utworzono" + } + }, + "deletePagePrompt": { + "text": "Ta strona jest w Koszu", + "restore": "Przywróć strone", + "deletePermanent": "Usuń bezpowrotnie" + }, + "dialogCreatePageNameHint": "Nazwa Strony", + "questionBubble": { + "whatsNew": "What's new?", + "help": "Pomoc & Wsparcie", + "debug": { + "name": "Informacje Debugowania", + "success": "Skopiowano informacje debugowania do schowka!", + "fail": "Nie mozna skopiować informacji debugowania do schowka" + } + }, + "menuAppHeader": { + "addPageTooltip": "Szybko dodaj stronę do środka", + "defaultNewPageName": "Brak tytułu", + "renameDialog": "Zmień nazwę" + }, + "toolbar": { + "undo": "Cofnij", + "redo": "Powtórz", + "bold": "Pogrubiony", + "italic": "Kursywa", + "underline": "Podkreśl", + "strike": "Przekreśl", + "numList": "Lista Numerowana", + "bulletList": "Lista Punktowana", + "checkList": "Lista Kontrolna", + "inlineCode": "Kod Wbudowany", + "quote": "Blok cytat", + "header": "Nagłówek", + "highlight": "Podświetl" + }, + "tooltip": { + "lightMode": "Przełącz w Tryb Jasny", + "darkMode": "Przełącz w Tryb Ciemny" + }, + "contactsPage": { + "title": "Kontakty", + "whatsHappening": "Co się dzieje w tym tygodniu?", + "addContact": "Dodaj Kontakt", + "editContact": "Edytuj Kontakt" + }, + "button": { + "OK": "OK", + "Cancel": "Anuluj", + "signIn": "Zaloguj", + "signOut": "Wyloguj", + "complete": "Zakończono", + "save": "Zapisz" + }, + "label": { + "welcome": "Witaj!", + "firstName": "Imię Pierwsze", + "middleName": "Imię Drugie", + "lastName": "Nazwisko", + "stepX": "Krok {X}" + }, + "oAuth": { + "err": { + "failedTitle": "Nie można połączyć się z Twoim kontem.", + "failedMsg": "Upewnij się, że zakończyłeś proces logowania w przeglądarce." + }, + "google": { + "title": "LOGOWANIE GOOGLE", + "instruction1": "Aby zaimportować Kontakty Google, musisz autoryzować tę aplikację za pomocą przeglądarki internetowej.", + "instruction2": "Skopiuj ten kod do schowka, klikając ikonę lub zaznaczając tekst:", + "instruction3": "Przejdź do następującego linku w przeglądarce internetowej i wprowadź powyższy kod:", + "instruction4": "Naciśnij poniższy przycisk po zakończeniu rejestracji:" + } + }, + "settings": { + "title": "Ustawienia", + "menu": { + "appearance": "Wygląd", + "language": "Język", + "open": "Otwórz Ustawienia" + }, + "appearance": { + "lightLabel": "Tryb Jasny", + "darkLabel": "Tryb Ciemny" + } + } +} diff --git a/frontend/app_flowy/lib/startup/tasks/app_widget.dart b/frontend/app_flowy/lib/startup/tasks/app_widget.dart index b41e9a32d7..6dae04a1c0 100644 --- a/frontend/app_flowy/lib/startup/tasks/app_widget.dart +++ b/frontend/app_flowy/lib/startup/tasks/app_widget.dart @@ -39,6 +39,7 @@ class InitAppWidgetTask extends LaunchTask { Locale('id', 'ID'), Locale('it', 'IT'), Locale('ja', 'JP'), + Locale('pl', 'PL'), Locale('pt', 'BR'), Locale('ru', 'RU'), Locale('tr', 'TR'), diff --git a/frontend/app_flowy/packages/flowy_infra/lib/language.dart b/frontend/app_flowy/packages/flowy_infra/lib/language.dart index b30200141d..752956b33e 100644 --- a/frontend/app_flowy/packages/flowy_infra/lib/language.dart +++ b/frontend/app_flowy/packages/flowy_infra/lib/language.dart @@ -32,6 +32,8 @@ String languageFromLocale(Locale locale) { return "Italiano"; case "ja": return "日本語"; + case "pl": + return "Polski"; case "pt": return "Português"; case "ru": From 3caa5656108f5f13e865e72096f2e8644f807a75 Mon Sep 17 00:00:00 2001 From: Poly-Pixel <79737178+Poly-Pixel@users.noreply.github.com> Date: Thu, 28 Jul 2022 20:04:46 -0700 Subject: [PATCH 098/112] fix: fix remaining PATH issues --- frontend/scripts/install_dev_env/install_windows.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/scripts/install_dev_env/install_windows.sh b/frontend/scripts/install_dev_env/install_windows.sh index bf6498b587..2e2392f300 100644 --- a/frontend/scripts/install_dev_env/install_windows.sh +++ b/frontend/scripts/install_dev_env/install_windows.sh @@ -50,8 +50,9 @@ fi printMessage "Setting up Flutter" flutter channel stable -# Add pub cache to PATH +# Add pub cache and cargo to PATH powershell '[Environment]::SetEnvironmentVariable("PATH", $Env:PATH + ";" + $Env:LOCALAPPDATA + "\Pub\Cache\Bin", [EnvironmentVariableTarget]::User)' +powershell '[Environment]::SetEnvironmentVariable("PATH", $Env:PATH + ";" + $Env:USERPROFILE + "\.cargo\bin", [EnvironmentVariableTarget]::User)' # Enable linux desktop flutter config --enable-windows-desktop @@ -91,4 +92,4 @@ vcpkg integrate install # Check prerequisites printMessage "Checking prerequisites." -$USERPROFILE/.cargo/bin/cargo make flowy_dev +PATH="$PATH;$LOCALAPPDATA/Pub/Cache/Bin" $USERPROFILE/.cargo/bin/cargo make flowy_dev From 86799bbb965e172d88d60e239e7e72de79fa9413 Mon Sep 17 00:00:00 2001 From: Poly-Pixel <79737178+Poly-Pixel@users.noreply.github.com> Date: Sun, 24 Jul 2022 13:18:56 -0700 Subject: [PATCH 099/112] fix: fix last command issue --- frontend/scripts/install_dev_env/install_windows.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/scripts/install_dev_env/install_windows.sh b/frontend/scripts/install_dev_env/install_windows.sh index 2e2392f300..bbba4cf2d5 100644 --- a/frontend/scripts/install_dev_env/install_windows.sh +++ b/frontend/scripts/install_dev_env/install_windows.sh @@ -92,4 +92,4 @@ vcpkg integrate install # Check prerequisites printMessage "Checking prerequisites." -PATH="$PATH;$LOCALAPPDATA/Pub/Cache/Bin" $USERPROFILE/.cargo/bin/cargo make flowy_dev +PATH="$PATH;$LOCALAPPDATA\Pub\Cache\bin" bash -c '$USERPROFILE/.cargo/bin/cargo make flowy_dev' From d955b6ef7ee9e30d32839b3fa5b55e95840fa9a2 Mon Sep 17 00:00:00 2001 From: Aman Kumar Date: Fri, 29 Jul 2022 22:14:53 +0530 Subject: [PATCH 100/112] feat: row count widget added --- frontend/app_flowy/.gitignore | 3 +- .../plugins/grid/src/grid_page.dart | 30 ++++++++++++++++++- .../plugins/grid/src/layout/sizes.dart | 2 +- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/frontend/app_flowy/.gitignore b/frontend/app_flowy/.gitignore index 505fd9136b..e43862d70e 100644 --- a/frontend/app_flowy/.gitignore +++ b/frontend/app_flowy/.gitignore @@ -64,4 +64,5 @@ windows/flutter/dart_ffi/ **/**/*.dll **/**/*.so **/**/Brewfile.lock.json -**/.sandbox \ No newline at end of file +**/.sandbox +**/.vscode/ \ No newline at end of file diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index 82b13867a4..c2466602b6 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -1,14 +1,18 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:flowy_infra/size.dart'; +import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scrollview.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/material.dart'; import 'package:linked_scroll_controller/linked_scroll_controller.dart'; +import 'package:provider/provider.dart'; import 'controller/grid_scroll.dart'; import 'layout/layout.dart'; import 'layout/sizes.dart'; @@ -250,6 +254,8 @@ class _GridFooter extends StatelessWidget { @override Widget build(BuildContext context) { + final rowCount = context.watch().state.rowInfos.length; + final theme = context.watch(); return SliverPadding( padding: const EdgeInsets.only(bottom: 200), sliver: SliverToBoxAdapter( @@ -260,7 +266,14 @@ class _GridFooter extends StatelessWidget { child: Row( children: [ SizedBox(width: GridSize.leadingHeaderPadding), - const SizedBox(width: 120, child: GridAddRowButton()), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(width: 120, child: GridAddRowButton()), + const SizedBox(height: 30), + _rowCountTextWidget(theme: theme,count: rowCount) + ], + ), ], ), ), @@ -268,4 +281,19 @@ class _GridFooter extends StatelessWidget { ), ); } + + Widget _rowCountTextWidget({required AppTheme theme, required int count}){ + return Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + FlowyText.regular('Count : ', + fontSize: 13, + color: theme.shader3, + ), + FlowyText.regular(count.toString(), + fontSize: 13, + ), + ], + ); + } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart index 61e8e0151c..0a137b6d46 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/layout/sizes.dart @@ -5,7 +5,7 @@ class GridSize { static double get scrollBarSize => 12 * scale; static double get headerHeight => 40 * scale; - static double get footerHeight => 40 * scale; + static double get footerHeight => 100 * scale; static double get leadingHeaderPadding => 50 * scale; static double get trailHeaderPadding => 140 * scale; static double get headerContainerPadding => 0 * scale; From 35351eba62a746b97136dd27a849e460e6412c3b Mon Sep 17 00:00:00 2001 From: Aman Kumar Date: Fri, 29 Jul 2022 22:16:26 +0530 Subject: [PATCH 101/112] fix: removed unused imports --- .../lib/workspace/presentation/plugins/grid/src/grid_page.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index c2466602b6..4aae99acbe 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -1,7 +1,6 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; -import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; @@ -12,7 +11,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/material.dart'; import 'package:linked_scroll_controller/linked_scroll_controller.dart'; -import 'package:provider/provider.dart'; import 'controller/grid_scroll.dart'; import 'layout/layout.dart'; import 'layout/sizes.dart'; From fecc1ec31b0be4c8dbc7418b6b810073faf57963 Mon Sep 17 00:00:00 2001 From: sky1095 Date: Sun, 31 Jul 2022 13:36:52 +0530 Subject: [PATCH 102/112] fix: ProviderNotFound exception in overlay demo example --- .../lib/src/flowy_overlay/list_overlay.dart | 28 ++++++++++--------- .../src/flowy_overlay/overlay_container.dart | 2 +- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart index 16d3b55f47..0b247267eb 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/list_overlay.dart @@ -41,20 +41,22 @@ class ListOverlay extends StatelessWidget { return OverlayContainer( constraints: BoxConstraints.tight(Size(width, totalHeight)), padding: padding, - child: Column( - children: [ - ListView.builder( - shrinkWrap: true, - itemBuilder: itemBuilder, - itemCount: itemCount, - controller: controller, - ), - if (footer != null) - Padding( - padding: footer!.padding, - child: footer!.widget, + child: SingleChildScrollView( + child: Column( + children: [ + ListView.builder( + shrinkWrap: true, + itemBuilder: itemBuilder, + itemCount: itemCount, + controller: controller, ), - ], + if (footer != null) + Padding( + padding: footer!.padding, + child: footer!.widget, + ), + ], + ), ), ); } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_container.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_container.dart index 85de2c71a7..96b566b308 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_container.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/src/flowy_overlay/overlay_container.dart @@ -18,7 +18,7 @@ class OverlayContainer extends StatelessWidget { @override Widget build(BuildContext context) { - final theme = context.watch(); + final theme = context.watch() ?? AppTheme.fromType(ThemeType.light); return Material( type: MaterialType.transparency, child: Container( From af61cae182554151a7291c157e2537b341851948 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 31 Jul 2022 19:43:52 +0800 Subject: [PATCH 103/112] ci: fix docker builder --- frontend/rust-lib/flowy-grid/src/entities/block_entities.rs | 1 - frontend/rust-lib/flowy-grid/src/entities/field_entities.rs | 2 -- frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs | 1 - frontend/rust-lib/flowy-grid/src/event_map.rs | 4 +--- .../field/type_options/selection_type_option/select_option.rs | 4 ---- frontend/scripts/docker-buildfiles/Dockerfile | 2 +- 6 files changed, 2 insertions(+), 12 deletions(-) diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs index 8637e35aed..f778186903 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -4,7 +4,6 @@ use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::revision::RowRevision; use std::sync::Arc; - /// [GridBlockPB] contains list of row ids. The rows here does not contain any data, just the id /// of the row. Check out [GridRowPB] for more details. /// diff --git a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs index f3ef1738b1..dce77787c3 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/field_entities.rs @@ -8,7 +8,6 @@ use std::sync::Arc; use strum_macros::{Display, EnumCount as EnumCountMacro, EnumIter, EnumString}; - /// [GridFieldPB] defines a Field's attributes. Such as the name, field_type, and width. etc. #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridFieldPB { @@ -280,7 +279,6 @@ pub struct FieldTypeOptionDataPB { pub type_option_data: Vec, } - /// Collection of the [GridFieldPB] #[derive(Debug, Default, ProtoBuf)] pub struct RepeatedGridFieldPB { diff --git a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs index 697910ccad..3564886c4a 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/setting_entities.rs @@ -12,7 +12,6 @@ use std::convert::TryInto; use strum::IntoEnumIterator; use strum_macros::EnumIter; - /// [GridSettingPB] defines the setting options for the grid. Such as the filter, group, and sort. #[derive(Eq, PartialEq, ProtoBuf, Debug, Default, Clone)] pub struct GridSettingPB { diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index f8b3c36d33..0855ef0032 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -42,7 +42,6 @@ pub fn create(grid_manager: Arc) -> Module { module } - /// [GridEvent] defines events that are used to interact with the Grid. You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/protobuf) /// out, it includes how to use these annotations: input, output, etc. #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)] @@ -88,7 +87,6 @@ pub enum GridEvent { #[event(input = "FieldChangesetPayloadPB")] UpdateField = 11, - /// [UpdateFieldTypeOption] event is used to update the field's type option data. Certain field /// types have user-defined options such as color, date format, number format, or a list of values /// for a multi-select list. These options are defined within a specialization of the @@ -160,7 +158,7 @@ pub enum GridEvent { /// FieldType::SingleSelect or FieldType::MultiSelect. /// /// This event may trigger the GridNotification::DidUpdateCell event. - /// For example, GridNotification::DidUpdateCell will be triggered if the [SelectOptionChangesetPayloadPB] + /// For example, GridNotification::DidUpdateCell will be triggered if the [SelectOptionChangesetPayloadPB] /// carries a change that updates the name of the option. #[event(input = "SelectOptionChangesetPayloadPB")] UpdateSelectOption = 32, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs index 11adb945dc..d426844427 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option/select_option.rs @@ -11,7 +11,6 @@ use serde::{Deserialize, Serialize}; pub const SELECTION_IDS_SEPARATOR: &str = ","; - /// [SelectOptionPB] represents an option for a single select, and multiple select. #[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)] pub struct SelectOptionPB { @@ -324,12 +323,10 @@ impl SelectOptionCellChangeset { } } - /// [SelectOptionCellDataPB] contains a list of user's selected options and a list of all the options /// that the cell can use. #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] pub struct SelectOptionCellDataPB { - /// The available options that the cell can use. #[pb(index = 1)] pub options: Vec, @@ -339,7 +336,6 @@ pub struct SelectOptionCellDataPB { pub select_options: Vec, } - /// [SelectOptionChangesetPayloadPB] describes the changes of a FieldTypeOptionData. For the moment, /// it is used by [MultiSelectTypeOptionPB] and [SingleSelectTypeOptionPB]. #[derive(Clone, Debug, Default, ProtoBuf)] diff --git a/frontend/scripts/docker-buildfiles/Dockerfile b/frontend/scripts/docker-buildfiles/Dockerfile index 54b79173bc..f050087977 100644 --- a/frontend/scripts/docker-buildfiles/Dockerfile +++ b/frontend/scripts/docker-buildfiles/Dockerfile @@ -33,7 +33,7 @@ source $HOME/.cargo/env && \ cargo install --force cargo-make && \ cargo install --force duckscript_cli && \ cargo make flowy_dev && \ -cargo make -p production-linux-x86 appflowy-linux +cargo make -p production-linux-x86_64 appflowy-linux CMD ["/home/makepkg/appflowy/frontend/app_flowy/build/linux/x64/release/bundle/app_flowy"] From 67f027bf3b5b83b31791c7f8dbc488ca50d9ecce Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 31 Jul 2022 20:09:41 +0800 Subject: [PATCH 104/112] chore: fix instal_macos.sh download glint error --- frontend/scripts/install_dev_env/install_macos.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/scripts/install_dev_env/install_macos.sh b/frontend/scripts/install_dev_env/install_macos.sh index 26a2e5da02..1e746d954d 100755 --- a/frontend/scripts/install_dev_env/install_macos.sh +++ b/frontend/scripts/install_dev_env/install_macos.sh @@ -53,7 +53,7 @@ git config core.hooksPath .githooks # Install go-gitlint printMessage "Installing go-gitlint." GOLINT_FILENAME="go-gitlint_1.1.0_osx_x86_64.tar.gz" -wget https://github.com/llorllale/go-gitlint/releases/download/1.1.0/${GOLINT_FILENAME} +curl -L https://github.com/llorllale/go-gitlint/releases/download/1.1.0/${GOLINT_FILENAME} --output ${GOLINT_FILENAME} tar -zxv --directory .githooks/. -f ${GOLINT_FILENAME} gitlint rm ${GOLINT_FILENAME} From 8511829c421292abdd8caf913b74f9c381f7b9d3 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 31 Jul 2022 20:13:03 +0800 Subject: [PATCH 105/112] chore: disable flutter analyze when push --- .githooks/pre-push | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/.githooks/pre-push b/.githooks/pre-push index 7b6eeb8bc1..ee7c8cb79c 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -24,21 +24,13 @@ if [[ `git status --porcelain` ]]; then exit 1 fi -printMessage "Running the Flutter analyzer" -flutter analyze - -if [ $? -ne 0 ]; then - printError "Flutter analyzer error" - exit 1 -fi - -printMessage "Finished running the Flutter analyzer" - - -#printMessage "Running unit tests" -#flutter test +# +#printMessage "Running the Flutter analyzer" +#flutter analyze +# #if [ $? -ne 0 ]; then -# printf "\e[31;1m%s\e[0m\n" 'Unit tests error' +# printError "Flutter analyzer error" # exit 1 #fi -#printf "\e[33;1m%s\e[0m\n" 'Finished running unit tests' +# +#printMessage "Finished running the Flutter analyzer" From 798e16d3aa7589dbc05a9475139f75f6bfab0851 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 1 Aug 2022 09:31:40 +0800 Subject: [PATCH 106/112] chore: update lib ot tests --- .../flowy-folder/src/services/web_socket.rs | 2 +- .../rust-lib/flowy-text-block/src/queue.rs | 2 +- .../tests/editor/attribute_test.rs | 4 +- .../flowy-text-block/tests/editor/mod.rs | 2 +- .../flowy-text-block/tests/editor/op_test.rs | 15 ++--- .../src/client_folder/folder_pad.rs | 2 +- .../src/client_grid/grid_block_revsion_pad.rs | 2 +- .../src/client_grid/grid_revision_pad.rs | 2 +- .../src/server_folder/folder_pad.rs | 2 +- shared-lib/flowy-sync/src/util.rs | 6 +- shared-lib/lib-ot/src/core/delta/builder.rs | 66 +++++++++++++++++++ shared-lib/lib-ot/src/core/delta/delta.rs | 21 ++++-- shared-lib/lib-ot/src/core/delta/iterator.rs | 12 ++++ shared-lib/lib-ot/src/core/flowy_str.rs | 28 ++++++-- .../lib-ot/src/core/operation/builder.rs | 50 +++++++------- .../lib-ot/src/core/operation/operation.rs | 12 ++-- shared-lib/lib-ot/src/rich_text/attributes.rs | 4 +- 17 files changed, 170 insertions(+), 62 deletions(-) diff --git a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs index eac429dc1f..4b5481c9a0 100644 --- a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs +++ b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs @@ -10,7 +10,7 @@ use flowy_sync::{ }, }; use lib_infra::future::{BoxResultFuture, FutureResult}; -use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta}; +use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta}; use parking_lot::RwLock; use std::{sync::Arc, time::Duration}; diff --git a/frontend/rust-lib/flowy-text-block/src/queue.rs b/frontend/rust-lib/flowy-text-block/src/queue.rs index 072c810d9d..8756a50a00 100644 --- a/frontend/rust-lib/flowy-text-block/src/queue.rs +++ b/frontend/rust-lib/flowy-text-block/src/queue.rs @@ -12,7 +12,7 @@ use flowy_sync::{ }; use futures::stream::StreamExt; use lib_ot::{ - core::{Interval, OperationTransformable}, + core::{Interval, OperationTransform}, rich_text::{RichTextAttribute, RichTextAttributes, RichTextDelta}, }; use std::sync::Arc; diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs index 6dcd372d47..bdeb1601b9 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs @@ -1,7 +1,7 @@ #![cfg_attr(rustfmt, rustfmt::skip)] use crate::editor::{TestBuilder, TestOp::*}; use flowy_sync::client_document::{NewlineDoc, PlainDoc}; -use lib_ot::core::{Interval, OperationTransformable, NEW_LINE, WHITESPACE, FlowyStr}; +use lib_ot::core::{Interval, OperationTransform, NEW_LINE, WHITESPACE, FlowyStr}; use unicode_segmentation::UnicodeSegmentation; use lib_ot::rich_text::RichTextDelta; @@ -724,7 +724,7 @@ fn attributes_preserve_header_format_on_merge() { fn attributes_format_emoji() { let emoji_s = "👋 "; let s: FlowyStr = emoji_s.into(); - let len = s.utf16_size(); + let len = s.utf16_len(); assert_eq!(3, len); assert_eq!(2, s.graphemes(true).count()); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs index a6b58ab39b..64f432a1e7 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs @@ -302,7 +302,7 @@ impl Rng { let mut delta = RichTextDelta::default(); let s = FlowyStr::from(s); loop { - let left = s.utf16_size() - delta.utf16_base_len; + let left = s.utf16_len() - delta.utf16_base_len; if left == 0 { break; } diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index f32e70942f..20bb14c063 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -1,6 +1,7 @@ #![allow(clippy::all)] use crate::editor::{Rng, TestBuilder, TestOp::*}; use flowy_sync::client_document::{NewlineDoc, PlainDoc}; +use lib_ot::rich_text::RichTextDeltaBuilder; use lib_ot::{ core::Interval, core::*, @@ -39,12 +40,8 @@ fn attributes_insert_text_at_middle() { #[test] fn delta_get_ops_in_interval_1() { - let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("123").build(); - let insert_b = OperationBuilder::insert("4").build(); - - delta.add(insert_a.clone()); - delta.add(insert_b.clone()); + let operations = OperationBuilder::new().insert("123", None).insert("4", None).build(); + let delta = RichTextDeltaBuilder::from_operations(operations); let mut iterator = DeltaIterator::from_interval(&delta, Interval::new(0, 4)); assert_eq!(iterator.ops(), delta.ops); @@ -365,7 +362,7 @@ fn apply_1000() { let mut rng = Rng::default(); let s: FlowyStr = rng.gen_string(50).into(); let delta = rng.gen_delta(&s); - assert_eq!(s.utf16_size(), delta.utf16_base_len); + assert_eq!(s.utf16_len(), delta.utf16_base_len); } } @@ -489,11 +486,11 @@ fn compose() { let s = rng.gen_string(20); let a = rng.gen_delta(&s); let after_a: FlowyStr = a.apply(&s).unwrap().into(); - assert_eq!(a.utf16_target_len, after_a.utf16_size()); + assert_eq!(a.utf16_target_len, after_a.utf16_len()); let b = rng.gen_delta(&after_a); let after_b: FlowyStr = b.apply(&after_a).unwrap().into(); - assert_eq!(b.utf16_target_len, after_b.utf16_size()); + assert_eq!(b.utf16_target_len, after_b.utf16_len()); let ab = a.compose(&b).unwrap(); assert_eq!(ab.utf16_target_len, b.utf16_target_len); diff --git a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs index 0cbc33598e..632aa7f29b 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs @@ -434,7 +434,7 @@ mod tests { use chrono::Utc; use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision}; - use lib_ot::core::{OperationTransformable, PlainTextDelta, PlainTextDeltaBuilder}; + use lib_ot::core::{OperationTransform, PlainTextDelta, PlainTextDeltaBuilder}; #[test] fn folder_add_workspace() { diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs index cea6d7fd03..82fb19cb8b 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs @@ -4,7 +4,7 @@ use crate::util::{cal_diff, make_delta_from_revisions}; use flowy_grid_data_model::revision::{ gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision, }; -use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index d1232a261d..9aee7cfedd 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -9,7 +9,7 @@ use flowy_grid_data_model::revision::{ GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision, }; use lib_infra::util::move_vec_element; -use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use std::collections::HashMap; use std::sync::Arc; diff --git a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs index 29457eb65e..2ff3d0e479 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs @@ -1,5 +1,5 @@ use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject}; -use lib_ot::core::{OperationTransformable, PhantomAttributes, PlainTextDelta}; +use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta}; pub struct ServerFolder { folder_id: String, diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index b845550137..92728af8b1 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -9,7 +9,7 @@ use crate::{ use dissimilar::Chunk; use lib_ot::core::{DeltaBuilder, FlowyStr}; use lib_ot::{ - core::{Attributes, Delta, OperationTransformable, NEW_LINE, WHITESPACE}, + core::{Attributes, Delta, OperationTransform, NEW_LINE, WHITESPACE}, rich_text::RichTextDelta, }; use serde::de::DeserializeOwned; @@ -208,10 +208,10 @@ pub fn cal_diff(old: String, new: String) -> Option> { for chunk in &chunks { match chunk { Chunk::Equal(s) => { - delta_builder = delta_builder.retain(FlowyStr::from(*s).utf16_size()); + delta_builder = delta_builder.retain(FlowyStr::from(*s).utf16_len()); } Chunk::Delete(s) => { - delta_builder = delta_builder.delete(FlowyStr::from(*s).utf16_size()); + delta_builder = delta_builder.delete(FlowyStr::from(*s).utf16_len()); } Chunk::Insert(s) => { delta_builder = delta_builder.insert(*s); diff --git a/shared-lib/lib-ot/src/core/delta/builder.rs b/shared-lib/lib-ot/src/core/delta/builder.rs index 44e4d4dbac..a8bb0459c1 100644 --- a/shared-lib/lib-ot/src/core/delta/builder.rs +++ b/shared-lib/lib-ot/src/core/delta/builder.rs @@ -1,5 +1,6 @@ use crate::core::delta::{trim, Delta}; use crate::core::operation::{Attributes, PhantomAttributes}; +use crate::core::Operation; pub type PlainTextDeltaBuilder = DeltaBuilder; @@ -7,6 +8,16 @@ pub type PlainTextDeltaBuilder = DeltaBuilder; /// /// Note that all edit operations must be sorted; the start point of each /// interval must be no less than the end point of the previous one. +/// +/// # Examples +/// +/// ``` +/// use lib_ot::core::PlainTextDeltaBuilder; +/// let delta = PlainTextDeltaBuilder::new() +/// .insert("AppFlowy") +/// .build(); +/// assert_eq!(delta.content_str().unwrap(), "AppFlowy"); +/// ``` pub struct DeltaBuilder { delta: Delta, } @@ -28,8 +39,26 @@ where DeltaBuilder::default() } + pub fn from_operations(operations: Vec>) -> Delta { + let mut delta = DeltaBuilder::default().build(); + operations.into_iter().for_each(|operation| { + delta.add(operation); + }); + delta + } + /// Retain the 'n' characters with the attributes. Use 'retain' instead if you don't /// need any attributes. + /// # Examples + /// + /// ``` + /// use lib_ot::rich_text::{RichTextAttribute, RichTextDelta, RichTextDeltaBuilder}; + /// + /// let mut attribute = RichTextAttribute::Bold(true); + /// let delta = RichTextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); + /// + /// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#); + /// ``` pub fn retain_with_attributes(mut self, n: usize, attrs: T) -> Self { self.delta.retain(n, attrs); self @@ -41,6 +70,24 @@ where } /// Deletes the given interval. Panics if interval is not properly sorted. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder}; + /// + /// let delta = PlainTextDeltaBuilder::new() + /// .insert("AppFlowy...") + /// .build(); + /// + /// let changeset = PlainTextDeltaBuilder::new() + /// .retain(8) + /// .delete(3) + /// .build(); + /// + /// let new_delta = delta.compose(&changeset).unwrap(); + /// assert_eq!(new_delta.content_str().unwrap(), "AppFlowy"); + /// ``` pub fn delete(mut self, n: usize) -> Self { self.delta.delete(n); self @@ -58,6 +105,25 @@ where self } + /// Removes trailing retain operation with empty attributes + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder}; + /// use lib_ot::rich_text::{RichTextAttribute, RichTextDeltaBuilder}; + /// let delta = PlainTextDeltaBuilder::new() + /// .retain(3) + /// .trim() + /// .build(); + /// assert_eq!(delta.ops.len(), 0); + /// + /// let delta = RichTextDeltaBuilder::new() + /// .retain_with_attributes(3, RichTextAttribute::Bold(true).into()) + /// .trim() + /// .build(); + /// assert_eq!(delta.ops.len(), 1); + /// ``` pub fn trim(mut self) -> Self { trim(&mut self.delta); self diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 2bff1a3edc..495d26a8e8 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -3,7 +3,7 @@ use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::core::delta::{DeltaIterator, MAX_IV_LEN}; use crate::core::flowy_str::FlowyStr; use crate::core::interval::Interval; -use crate::core::operation::{Attributes, Operation, OperationBuilder, OperationTransformable, PhantomAttributes}; +use crate::core::operation::{Attributes, Operation, OperationBuilder, OperationTransform, PhantomAttributes}; use bytes::Bytes; use serde::de::DeserializeOwned; use std::{ @@ -123,7 +123,7 @@ where return; } - self.utf16_target_len += s.utf16_size(); + self.utf16_target_len += s.utf16_len(); let new_last = match self.ops.as_mut_slice() { [.., Operation::::Insert(insert)] => { // @@ -191,12 +191,12 @@ where /// ``` pub fn apply(&self, applied_str: &str) -> Result { let applied_str: FlowyStr = applied_str.into(); - if applied_str.utf16_size() != self.utf16_base_len { + if applied_str.utf16_len() != self.utf16_base_len { return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength) .msg(format!( "Expected: {}, but received: {}", self.utf16_base_len, - applied_str.utf16_size() + applied_str.utf16_len() )) .build()); } @@ -289,7 +289,7 @@ where } } -impl OperationTransformable for Delta +impl OperationTransform for Delta where T: Attributes, { @@ -568,6 +568,17 @@ impl Delta where T: Attributes + DeserializeOwned, { + /// # Examples + /// + /// ``` + /// use lib_ot::core::DeltaBuilder; + /// use lib_ot::rich_text::{RichTextDelta}; + /// let json = r#"[ + /// {"retain":7,"attributes":{"bold":null}} + /// ]"#; + /// let delta = RichTextDelta::from_json_str(json).unwrap(); + /// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); + /// ``` pub fn from_json_str(json: &str) -> Result { let delta = serde_json::from_str(json).map_err(|e| { tracing::trace!("Deserialize failed: {:?}", e); diff --git a/shared-lib/lib-ot/src/core/delta/iterator.rs b/shared-lib/lib-ot/src/core/delta/iterator.rs index ba9db58428..d1ab80885f 100644 --- a/shared-lib/lib-ot/src/core/delta/iterator.rs +++ b/shared-lib/lib-ot/src/core/delta/iterator.rs @@ -7,6 +7,18 @@ use std::ops::{Deref, DerefMut}; pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize; +/// Retain the 'n' characters with the attributes. Use 'retain' instead if you don't +/// need any attributes. +/// # Examples +/// +/// ``` +/// use lib_ot::rich_text::{RichTextAttribute, RichTextDelta, RichTextDeltaBuilder}; +/// +/// let mut attribute = RichTextAttribute::Bold(true); +/// let delta = RichTextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); +/// +/// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#); +/// ``` pub struct DeltaIterator<'a, T: Attributes> { cursor: DeltaCursor<'a, T>, } diff --git a/shared-lib/lib-ot/src/core/flowy_str.rs b/shared-lib/lib-ot/src/core/flowy_str.rs index 9e503672eb..2f5ee9b853 100644 --- a/shared-lib/lib-ot/src/core/flowy_str.rs +++ b/shared-lib/lib-ot/src/core/flowy_str.rs @@ -5,8 +5,24 @@ use std::{fmt, fmt::Formatter}; pub struct FlowyStr(pub String); impl FlowyStr { - // https://stackoverflow.com/questions/2241348/what-is-unicode-utf-8-utf-16 - pub fn utf16_size(&self) -> usize { + /// + /// # Arguments + /// + /// * `delta`: The delta you want to iterate over. + /// * `interval`: The range for the cursor movement. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::FlowyStr; + /// let utf16_len = FlowyStr::from("👋").utf16_len(); + /// assert_eq!(utf16_len, 2); + /// let bytes_len = String::from("👋").len(); + /// assert_eq!(bytes_len, 4); + /// + /// ``` + /// https://stackoverflow.com/questions/2241348/what-is-unicode-utf-8-utf-16 + pub fn utf16_len(&self) -> usize { count_utf16_code_units(&self.0) } @@ -231,7 +247,7 @@ mod tests { #[test] fn flowy_str_code_unit() { - let size = FlowyStr::from("👋").utf16_size(); + let size = FlowyStr::from("👋").utf16_len(); assert_eq!(size, 2); let s: FlowyStr = "👋 \n👋".into(); @@ -251,7 +267,7 @@ mod tests { #[test] fn flowy_str_sub_str_in_chinese() { let s: FlowyStr = "你好\n😁".into(); - let size = s.utf16_size(); + let size = s.utf16_len(); assert_eq!(size, 5); let output1 = s.sub_str(Interval::new(0, 2)).unwrap(); @@ -265,7 +281,7 @@ mod tests { #[test] fn flowy_str_sub_str_in_chinese2() { let s: FlowyStr = "😁 \n".into(); - let size = s.utf16_size(); + let size = s.utf16_len(); assert_eq!(size, 4); let output1 = s.sub_str(Interval::new(0, 3)).unwrap(); @@ -277,7 +293,7 @@ mod tests { #[test] fn flowy_str_sub_str_in_english() { let s: FlowyStr = "ab".into(); - let size = s.utf16_size(); + let size = s.utf16_len(); assert_eq!(size, 2); let output = s.sub_str(Interval::new(0, 2)).unwrap(); diff --git a/shared-lib/lib-ot/src/core/operation/builder.rs b/shared-lib/lib-ot/src/core/operation/builder.rs index c2cf774617..d1803a8e21 100644 --- a/shared-lib/lib-ot/src/core/operation/builder.rs +++ b/shared-lib/lib-ot/src/core/operation/builder.rs @@ -5,31 +5,43 @@ pub type RichTextOpBuilder = OperationBuilder; pub type PlainTextOpBuilder = OperationBuilder; pub struct OperationBuilder { - ty: Operation, - attrs: T, + operations: Vec>, } impl OperationBuilder where T: Attributes, { - pub fn new(ty: Operation) -> OperationBuilder { - OperationBuilder { - ty, - attrs: T::default(), + pub fn new() -> OperationBuilder { + OperationBuilder { operations: vec![] } + } + + pub fn retain(mut self, n: usize) -> OperationBuilder { + let mut retain = Operation::Retain(n.into()); + + if let Some(attributes) = attributes { + if let Operation::Retain(r) = &mut retain { + r.attributes = attributes; + } } + self.operations.push(retain); + self } - pub fn retain(n: usize) -> OperationBuilder { - OperationBuilder::new(Operation::Retain(n.into())) + pub fn delete(mut self, n: usize) -> OperationBuilder { + self.operations.push(Operation::Delete(n)); + self } - pub fn delete(n: usize) -> OperationBuilder { - OperationBuilder::new(Operation::Delete(n)) - } - - pub fn insert(s: &str) -> OperationBuilder { - OperationBuilder::new(Operation::Insert(s.into())) + pub fn insert(mut self, s: &str, attributes: Option) -> OperationBuilder { + let mut insert = Operation::Insert(s.into()); + if let Some(attributes) = attributes { + if let Operation::Retain(i) = &mut insert { + i.attributes = attributes; + } + } + self.operations.push(insert); + self } pub fn attributes(mut self, attrs: T) -> OperationBuilder { @@ -37,13 +49,7 @@ where self } - pub fn build(self) -> Operation { - let mut operation = self.ty; - match &mut operation { - Operation::Delete(_) => {} - Operation::Retain(retain) => retain.attributes = self.attrs, - Operation::Insert(insert) => insert.attributes = self.attrs, - } - operation + pub fn build(self) -> Vec> { + self.operations } } diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 26ac7650ec..9464f91784 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -11,7 +11,7 @@ use std::{ ops::{Deref, DerefMut}, }; -pub trait OperationTransformable { +pub trait OperationTransform { /// Merges the operation with `other` into one operation while preserving /// the changes of both. /// @@ -22,7 +22,7 @@ pub trait OperationTransformable { /// # Examples /// /// ``` - /// use lib_ot::core::{OperationTransformable, PlainTextDeltaBuilder}; + /// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder}; /// let document = PlainTextDeltaBuilder::new().build(); /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); /// let new_document = document.compose(&delta).unwrap(); @@ -51,7 +51,7 @@ pub trait OperationTransformable { /// # Examples /// /// ``` - /// use lib_ot::core::{OperationTransformable, PlainTextDeltaBuilder}; + /// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder}; /// let original_document = PlainTextDeltaBuilder::new().build(); /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); /// @@ -71,7 +71,7 @@ pub trait OperationTransformable { /// Because [Operation] is generic over the T, so you must specify the T. For example, the [PlainTextDelta]. It use /// use [PhantomAttributes] as the T. [PhantomAttributes] does nothing, just a phantom. /// -pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransformable { +pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransform { fn is_empty(&self) -> bool { true } @@ -360,7 +360,7 @@ where T: Attributes, { pub fn utf16_size(&self) -> usize { - self.s.utf16_size() + self.s.utf16_len() } pub fn merge_or_new_op(&mut self, s: &str, attributes: T) -> Option> { @@ -420,7 +420,7 @@ impl fmt::Display for PhantomAttributes { impl Attributes for PhantomAttributes {} -impl OperationTransformable for PhantomAttributes { +impl OperationTransform for PhantomAttributes { fn compose(&self, _other: &Self) -> Result { Ok(self.clone()) } diff --git a/shared-lib/lib-ot/src/rich_text/attributes.rs b/shared-lib/lib-ot/src/rich_text/attributes.rs index 05d37317d2..54826c49a0 100644 --- a/shared-lib/lib-ot/src/rich_text/attributes.rs +++ b/shared-lib/lib-ot/src/rich_text/attributes.rs @@ -1,5 +1,5 @@ #![allow(non_snake_case)] -use crate::core::{Attributes, Operation, OperationTransformable}; +use crate::core::{Attributes, Operation, OperationTransform}; use crate::{block_attribute, errors::OTError, ignore_attribute, inline_attribute, list_attribute}; use lazy_static::lazy_static; use std::{ @@ -122,7 +122,7 @@ impl Attributes for RichTextAttributes { } } -impl OperationTransformable for RichTextAttributes { +impl OperationTransform for RichTextAttributes { fn compose(&self, other: &Self) -> Result where Self: Sized, From f8c071e13d272d85ecd0f5e9ab3b2d80c96a762a Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 1 Aug 2022 11:18:42 +0800 Subject: [PATCH 107/112] chore: update documentation about how the iterator/FlowyStr/Operation work --- .../flowy-text-block/tests/editor/op_test.rs | 149 +++++++----------- .../tests/editor/serde_test.rs | 6 +- shared-lib/lib-ot/src/core/delta/cursor.rs | 6 +- shared-lib/lib-ot/src/core/delta/delta.rs | 39 ++--- shared-lib/lib-ot/src/core/flowy_str.rs | 62 +++++--- .../lib-ot/src/core/operation/builder.rs | 44 +++--- .../lib-ot/src/core/operation/operation.rs | 96 ++++++++--- 7 files changed, 212 insertions(+), 190 deletions(-) diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index 20bb14c063..cb7bb0a728 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -40,7 +40,7 @@ fn attributes_insert_text_at_middle() { #[test] fn delta_get_ops_in_interval_1() { - let operations = OperationBuilder::new().insert("123", None).insert("4", None).build(); + let operations = OperationsBuilder::new().insert("123").insert("4").build(); let delta = RichTextDeltaBuilder::from_operations(operations); let mut iterator = DeltaIterator::from_interval(&delta, Interval::new(0, 4)); @@ -50,10 +50,10 @@ fn delta_get_ops_in_interval_1() { #[test] fn delta_get_ops_in_interval_2() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("123").build(); - let insert_b = OperationBuilder::insert("4").build(); - let insert_c = OperationBuilder::insert("5").build(); - let retain_a = OperationBuilder::retain(3).build(); + let insert_a = Operation::insert("123"); + let insert_b = Operation::insert("4"); + let insert_c = Operation::insert("5"); + let retain_a = Operation::retain(3); delta.add(insert_a.clone()); delta.add(retain_a.clone()); @@ -62,12 +62,12 @@ fn delta_get_ops_in_interval_2() { assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), - vec![OperationBuilder::insert("12").build()] + vec![Operation::insert("12")] ); assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(), - vec![OperationBuilder::insert("23").build()] + vec![Operation::insert("23")] ); assert_eq!( @@ -77,7 +77,7 @@ fn delta_get_ops_in_interval_2() { assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(0, 4)).ops(), - vec![insert_a.clone(), OperationBuilder::retain(1).build()] + vec![insert_a.clone(), Operation::retain(1)] ); assert_eq!( @@ -94,20 +94,20 @@ fn delta_get_ops_in_interval_2() { #[test] fn delta_get_ops_in_interval_3() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("123456").build(); + let insert_a = Operation::insert("123456"); delta.add(insert_a.clone()); assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(3, 5)).ops(), - vec![OperationBuilder::insert("45").build()] + vec![Operation::insert("45")] ); } #[test] fn delta_get_ops_in_interval_4() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("12").build(); - let insert_b = OperationBuilder::insert("34").build(); - let insert_c = OperationBuilder::insert("56").build(); + let insert_a = Operation::insert("12"); + let insert_b = Operation::insert("34"); + let insert_c = Operation::insert("56"); delta.ops.push(insert_a.clone()); delta.ops.push(insert_b.clone()); @@ -128,73 +128,64 @@ fn delta_get_ops_in_interval_4() { assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(2, 5)).ops(), - vec![ - OperationBuilder::insert("34").build(), - OperationBuilder::insert("5").build() - ] + vec![Operation::insert("34"), Operation::insert("5")] ); } #[test] fn delta_get_ops_in_interval_5() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("123456").build(); - let insert_b = OperationBuilder::insert("789").build(); + let insert_a = Operation::insert("123456"); + let insert_b = Operation::insert("789"); delta.ops.push(insert_a.clone()); delta.ops.push(insert_b.clone()); assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(4, 8)).ops(), - vec![ - OperationBuilder::insert("56").build(), - OperationBuilder::insert("78").build() - ] + vec![Operation::insert("56"), Operation::insert("78")] ); // assert_eq!( // DeltaIter::from_interval(&delta, Interval::new(8, 9)).ops(), - // vec![Builder::insert("9").build()] + // vec![Builder::insert("9")] // ); } #[test] fn delta_get_ops_in_interval_6() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("12345678").build(); + let insert_a = Operation::insert("12345678"); delta.add(insert_a.clone()); assert_eq!( DeltaIterator::from_interval(&delta, Interval::new(4, 6)).ops(), - vec![OperationBuilder::insert("56").build()] + vec![Operation::insert("56")] ); } #[test] fn delta_get_ops_in_interval_7() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("12345").build(); - let retain_a = OperationBuilder::retain(3).build(); + let insert_a = Operation::insert("12345"); + let retain_a = Operation::retain(3); delta.add(insert_a.clone()); delta.add(retain_a.clone()); let mut iter_1 = DeltaIterator::from_offset(&delta, 2); - assert_eq!(iter_1.next_op().unwrap(), OperationBuilder::insert("345").build()); - assert_eq!(iter_1.next_op().unwrap(), OperationBuilder::retain(3).build()); + assert_eq!(iter_1.next_op().unwrap(), Operation::insert("345")); + assert_eq!(iter_1.next_op().unwrap(), Operation::retain(3)); let mut iter_2 = DeltaIterator::new(&delta); - assert_eq!( - iter_2.next_op_with_len(2).unwrap(), - OperationBuilder::insert("12").build() - ); - assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::insert("345").build()); + assert_eq!(iter_2.next_op_with_len(2).unwrap(), Operation::insert("12")); + assert_eq!(iter_2.next_op().unwrap(), Operation::insert("345")); - assert_eq!(iter_2.next_op().unwrap(), OperationBuilder::retain(3).build()); + assert_eq!(iter_2.next_op().unwrap(), Operation::retain(3)); } #[test] fn delta_op_seek() { let mut delta = RichTextDelta::default(); - let insert_a = OperationBuilder::insert("12345").build(); - let retain_a = OperationBuilder::retain(3).build(); + let insert_a = Operation::insert("12345"); + let retain_a = Operation::retain(3); delta.add(insert_a.clone()); delta.add(retain_a.clone()); let mut iter = DeltaIterator::new(&delta); @@ -205,14 +196,11 @@ fn delta_op_seek() { #[test] fn delta_utf16_code_unit_seek() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); iter.seek::(3); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("45").build() - ); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("45")); } #[test] @@ -223,91 +211,76 @@ fn delta_utf16_code_unit_seek_with_attributes() { .add_attr(RichTextAttribute::Italic(true)) .build(); - delta.add(OperationBuilder::insert("1234").attributes(attributes.clone()).build()); - delta.add(OperationBuilder::insert("\n").build()); + delta.add(Operation::insert_with_attributes("1234", attributes.clone())); + delta.add(Operation::insert("\n")); let mut iter = DeltaIterator::new(&delta); iter.seek::(0); assert_eq!( iter.next_op_with_len(4).unwrap(), - OperationBuilder::insert("1234").attributes(attributes).build(), + Operation::insert_with_attributes("1234", attributes), ); } #[test] fn delta_next_op_len() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("12").build() - ); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("34").build() - ); - assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::insert("5").build()); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("12")); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("34")); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("5")); assert_eq!(iter.next_op_with_len(1), None); } #[test] fn delta_next_op_len_with_chinese() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("你好").build()); + delta.add(Operation::insert("你好")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("你好").build() - ); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("你好")); } #[test] fn delta_next_op_len_with_english() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("ab").build()); + delta.add(Operation::insert("ab")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!( - iter.next_op_with_len(2).unwrap(), - OperationBuilder::insert("ab").build() - ); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::insert("ab")); } #[test] fn delta_next_op_len_after_seek() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 5); iter.seek::(3); assert_eq!(iter.next_op_len().unwrap(), 2); - assert_eq!(iter.next_op_with_len(1).unwrap(), OperationBuilder::insert("4").build()); + assert_eq!(iter.next_op_with_len(1).unwrap(), Operation::insert("4")); assert_eq!(iter.next_op_len().unwrap(), 1); - assert_eq!(iter.next_op().unwrap(), OperationBuilder::insert("5").build()); + assert_eq!(iter.next_op().unwrap(), Operation::insert("5")); } #[test] fn delta_next_op_len_none() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_len().unwrap(), 5); - assert_eq!( - iter.next_op_with_len(5).unwrap(), - OperationBuilder::insert("12345").build() - ); + assert_eq!(iter.next_op_with_len(5).unwrap(), Operation::insert("12345")); assert_eq!(iter.next_op_len(), None); } #[test] fn delta_next_op_with_len_zero() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); + delta.add(Operation::insert("12345")); let mut iter = DeltaIterator::new(&delta); assert_eq!(iter.next_op_with_len(0), None,); assert_eq!(iter.next_op_len().unwrap(), 5); @@ -316,14 +289,14 @@ fn delta_next_op_with_len_zero() { #[test] fn delta_next_op_with_len_cross_op_return_last() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("12345").build()); - delta.add(OperationBuilder::retain(1).build()); - delta.add(OperationBuilder::insert("678").build()); + delta.add(Operation::insert("12345")); + delta.add(Operation::retain(1)); + delta.add(Operation::insert("678")); let mut iter = DeltaIterator::new(&delta); iter.seek::(4); assert_eq!(iter.next_op_len().unwrap(), 1); - assert_eq!(iter.next_op_with_len(2).unwrap(), OperationBuilder::retain(1).build()); + assert_eq!(iter.next_op_with_len(2).unwrap(), Operation::retain(1)); } #[test] @@ -450,22 +423,22 @@ fn ops_merging() { assert_eq!(delta.ops.len(), 0); delta.retain(2, RichTextAttributes::default()); assert_eq!(delta.ops.len(), 1); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(2).build())); + assert_eq!(delta.ops.last(), Some(&Operation::retain(2))); delta.retain(3, RichTextAttributes::default()); assert_eq!(delta.ops.len(), 1); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::retain(5).build())); + assert_eq!(delta.ops.last(), Some(&Operation::retain(5))); delta.insert("abc", RichTextAttributes::default()); assert_eq!(delta.ops.len(), 2); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abc").build())); + assert_eq!(delta.ops.last(), Some(&Operation::insert("abc"))); delta.insert("xyz", RichTextAttributes::default()); assert_eq!(delta.ops.len(), 2); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::insert("abcxyz").build())); + assert_eq!(delta.ops.last(), Some(&Operation::insert("abcxyz"))); delta.delete(1); assert_eq!(delta.ops.len(), 3); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(1).build())); + assert_eq!(delta.ops.last(), Some(&Operation::delete(1))); delta.delete(1); assert_eq!(delta.ops.len(), 3); - assert_eq!(delta.ops.last(), Some(&OperationBuilder::delete(2).build())); + assert_eq!(delta.ops.last(), Some(&Operation::delete(2))); } #[test] @@ -618,11 +591,11 @@ fn transform_two_conflict_non_seq_delta() { #[test] fn delta_invert_no_attribute_delta() { let mut delta = RichTextDelta::default(); - delta.add(OperationBuilder::insert("123").build()); + delta.add(Operation::insert("123")); let mut change = RichTextDelta::default(); - change.add(OperationBuilder::retain(3).build()); - change.add(OperationBuilder::insert("456").build()); + change.add(Operation::retain(3)); + change.add(Operation::insert("456")); let undo = change.invert(&delta); let new_delta = delta.compose(&change).unwrap(); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs index 6c578be6c3..469431c478 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs @@ -11,7 +11,7 @@ fn operation_insert_serialize_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let operation = OperationBuilder::insert("123").attributes(attributes).build(); + let operation = Operation::insert_with_attributes("123", attributes); let json = serde_json::to_string(&operation).unwrap(); eprintln!("{}", json); @@ -42,7 +42,7 @@ fn attributes_serialize_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let retain = OperationBuilder::insert("123").attributes(attributes).build(); + let retain = Operation::insert_with_attributes("123", attributes); let json = serde_json::to_string(&retain).unwrap(); eprintln!("{}", json); @@ -56,7 +56,7 @@ fn delta_serialize_multi_attribute_test() { .add_attr(RichTextAttribute::Bold(true)) .add_attr(RichTextAttribute::Italic(true)) .build(); - let retain = OperationBuilder::insert("123").attributes(attributes).build(); + let retain = Operation::insert_with_attributes("123", attributes); delta.add(retain); delta.add(Operation::Retain(5.into())); diff --git a/shared-lib/lib-ot/src/core/delta/cursor.rs b/shared-lib/lib-ot/src/core/delta/cursor.rs index 2243adb7b3..4c223dfd50 100644 --- a/shared-lib/lib-ot/src/core/delta/cursor.rs +++ b/shared-lib/lib-ot/src/core/delta/cursor.rs @@ -29,11 +29,11 @@ where /// # Examples /// /// ``` - /// use lib_ot::core::{DeltaIterator, Interval, OperationBuilder}; + /// use lib_ot::core::{DeltaIterator, Interval, Operation}; /// use lib_ot::rich_text::RichTextDelta; /// let mut delta = RichTextDelta::default(); - /// let op_1 = OperationBuilder::insert("123").build(); - /// let op_2 = OperationBuilder::insert("4").build(); + /// let op_1 = Operation::insert("123"); + /// let op_2 = Operation::insert("4"); /// delta.add(op_1.clone()); /// delta.add(op_2.clone()); /// assert_eq!(DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), vec![op_1.clone()]); diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 495d26a8e8..53cdcaac54 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -3,7 +3,7 @@ use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::core::delta::{DeltaIterator, MAX_IV_LEN}; use crate::core::flowy_str::FlowyStr; use crate::core::interval::Interval; -use crate::core::operation::{Attributes, Operation, OperationBuilder, OperationTransform, PhantomAttributes}; +use crate::core::operation::{Attributes, Operation, OperationTransform, PhantomAttributes}; use bytes::Bytes; use serde::de::DeserializeOwned; use std::{ @@ -112,7 +112,7 @@ where if let Some(Operation::Delete(n_last)) = self.ops.last_mut() { *n_last += n; } else { - self.ops.push(OperationBuilder::delete(n).build()); + self.ops.push(Operation::delete(n)); } } @@ -135,10 +135,10 @@ where } [.., op_last @ Operation::::Delete(_)] => { let new_last = op_last.clone(); - *op_last = OperationBuilder::::insert(&s).attributes(attributes).build(); + *op_last = Operation::::insert_with_attributes(&s, attributes); Some(new_last) } - _ => Some(OperationBuilder::::insert(&s).attributes(attributes).build()), + _ => Some(Operation::::insert_with_attributes(&s, attributes)), }; match new_last { @@ -160,8 +160,7 @@ where self.ops.push(new_op); } } else { - self.ops - .push(OperationBuilder::::retain(n).attributes(attributes).build()); + self.ops.push(Operation::::retain_with_attributes(n, attributes)); } } @@ -319,10 +318,10 @@ where let op = iter .next_op_with_len(length) - .unwrap_or_else(|| OperationBuilder::retain(length).build()); + .unwrap_or_else(|| Operation::retain(length)); let other_op = other_iter .next_op_with_len(length) - .unwrap_or_else(|| OperationBuilder::retain(length).build()); + .unwrap_or_else(|| Operation::retain(length)); // debug_assert_eq!(op.len(), other_op.len(), "Composing delta failed,"); @@ -330,16 +329,12 @@ where (Operation::Retain(retain), Operation::Retain(other_retain)) => { let composed_attrs = retain.attributes.compose(&other_retain.attributes)?; - new_delta.add(OperationBuilder::retain(retain.n).attributes(composed_attrs).build()) + new_delta.add(Operation::retain_with_attributes(retain.n, composed_attrs)) } (Operation::Insert(insert), Operation::Retain(other_retain)) => { let mut composed_attrs = insert.attributes.compose(&other_retain.attributes)?; composed_attrs.remove_empty(); - new_delta.add( - OperationBuilder::insert(op.get_data()) - .attributes(composed_attrs) - .build(), - ) + new_delta.add(Operation::insert_with_attributes(op.get_data(), composed_attrs)) } (Operation::Retain(_), Operation::Delete(_)) => { new_delta.add(other_op); @@ -402,7 +397,7 @@ where Ordering::Less => { a_prime.retain(retain.n, composed_attrs.clone()); b_prime.retain(retain.n, composed_attrs.clone()); - next_op2 = Some(OperationBuilder::retain(o_retain.n - retain.n).build()); + next_op2 = Some(Operation::retain(o_retain.n - retain.n)); next_op1 = ops1.next(); } Ordering::Equal => { @@ -414,14 +409,14 @@ where Ordering::Greater => { a_prime.retain(o_retain.n, composed_attrs.clone()); b_prime.retain(o_retain.n, composed_attrs.clone()); - next_op1 = Some(OperationBuilder::retain(retain.n - o_retain.n).build()); + next_op1 = Some(Operation::retain(retain.n - o_retain.n)); next_op2 = ops2.next(); } }; } (Some(Operation::Delete(i)), Some(Operation::Delete(j))) => match i.cmp(j) { Ordering::Less => { - next_op2 = Some(OperationBuilder::delete(*j - *i).build()); + next_op2 = Some(Operation::delete(*j - *i)); next_op1 = ops1.next(); } Ordering::Equal => { @@ -429,7 +424,7 @@ where next_op2 = ops2.next(); } Ordering::Greater => { - next_op1 = Some(OperationBuilder::delete(*i - *j).build()); + next_op1 = Some(Operation::delete(*i - *j)); next_op2 = ops2.next(); } }, @@ -437,7 +432,7 @@ where match i.cmp(o_retain) { Ordering::Less => { a_prime.delete(*i); - next_op2 = Some(OperationBuilder::retain(o_retain.n - *i).build()); + next_op2 = Some(Operation::retain(o_retain.n - *i)); next_op1 = ops1.next(); } Ordering::Equal => { @@ -447,7 +442,7 @@ where } Ordering::Greater => { a_prime.delete(o_retain.n); - next_op1 = Some(OperationBuilder::delete(*i - o_retain.n).build()); + next_op1 = Some(Operation::delete(*i - o_retain.n)); next_op2 = ops2.next(); } }; @@ -456,7 +451,7 @@ where match retain.cmp(j) { Ordering::Less => { b_prime.delete(retain.n); - next_op2 = Some(OperationBuilder::delete(*j - retain.n).build()); + next_op2 = Some(Operation::delete(*j - retain.n)); next_op1 = ops1.next(); } Ordering::Equal => { @@ -466,7 +461,7 @@ where } Ordering::Greater => { b_prime.delete(*j); - next_op1 = Some(OperationBuilder::retain(retain.n - *j).build()); + next_op1 = Some(Operation::retain(retain.n - *j)); next_op2 = ops2.next(); } }; diff --git a/shared-lib/lib-ot/src/core/flowy_str.rs b/shared-lib/lib-ot/src/core/flowy_str.rs index 2f5ee9b853..162557f5f3 100644 --- a/shared-lib/lib-ot/src/core/flowy_str.rs +++ b/shared-lib/lib-ot/src/core/flowy_str.rs @@ -30,6 +30,22 @@ impl FlowyStr { Utf16CodeUnitIterator::new(self) } + /// Return a new string with the given [Interval] + /// # Examples + /// + /// ``` + /// use lib_ot::core::{FlowyStr, Interval}; + /// let s: FlowyStr = "你好\n😁".into(); + /// assert_eq!(s.utf16_len(), 5); + /// let output1 = s.sub_str(Interval::new(0, 2)).unwrap(); + /// assert_eq!(output1, "你好"); + /// + /// let output2 = s.sub_str(Interval::new(2, 3)).unwrap(); + /// assert_eq!(output2, "\n"); + /// + /// let output3 = s.sub_str(Interval::new(3, 5)).unwrap(); + /// assert_eq!(output3, "😁"); + /// ``` pub fn sub_str(&self, interval: Interval) -> Option { let mut iter = Utf16CodeUnitIterator::new(self); let mut buf = vec![]; @@ -49,8 +65,28 @@ impl FlowyStr { } } + /// Return a new string with the given [Interval] + /// # Examples + /// + /// ``` + /// use lib_ot::core::FlowyStr; + /// let s: FlowyStr = "👋😁👋".into(); /// + /// let mut iter = s.utf16_code_point_iter(); + /// assert_eq!(iter.next().unwrap(), "👋".to_string()); + /// assert_eq!(iter.next().unwrap(), "😁".to_string()); + /// assert_eq!(iter.next().unwrap(), "👋".to_string()); + /// assert_eq!(iter.next(), None); + /// + /// let s: FlowyStr = "👋12ab一二👋".into(); /// + /// let mut iter = s.utf16_code_point_iter(); + /// assert_eq!(iter.next().unwrap(), "👋".to_string()); + /// assert_eq!(iter.next().unwrap(), "1".to_string()); + /// assert_eq!(iter.next().unwrap(), "2".to_string()); + /// + /// assert_eq!(iter.skip(FlowyStr::from("ab一二").utf16_len()).next().unwrap(), "👋".to_string()); + /// ``` #[allow(dead_code)] - fn utf16_code_point_iter(&self) -> FlowyUtf16CodePointIterator { + pub fn utf16_code_point_iter(&self) -> FlowyUtf16CodePointIterator { FlowyUtf16CodePointIterator::new(self, 0) } } @@ -264,20 +300,6 @@ mod tests { assert_eq!(output, "👋"); } - #[test] - fn flowy_str_sub_str_in_chinese() { - let s: FlowyStr = "你好\n😁".into(); - let size = s.utf16_len(); - assert_eq!(size, 5); - - let output1 = s.sub_str(Interval::new(0, 2)).unwrap(); - let output2 = s.sub_str(Interval::new(2, 3)).unwrap(); - let output3 = s.sub_str(Interval::new(3, 5)).unwrap(); - assert_eq!(output1, "你好"); - assert_eq!(output2, "\n"); - assert_eq!(output3, "😁"); - } - #[test] fn flowy_str_sub_str_in_chinese2() { let s: FlowyStr = "😁 \n".into(); @@ -300,16 +322,6 @@ mod tests { assert_eq!(output, "ab"); } - #[test] - fn flowy_str_utf16_code_point_iter_test1() { - let s: FlowyStr = "👋😁👋".into(); - let mut iter = s.utf16_code_point_iter(); - assert_eq!(iter.next().unwrap(), "👋".to_string()); - assert_eq!(iter.next().unwrap(), "😁".to_string()); - assert_eq!(iter.next().unwrap(), "👋".to_string()); - assert_eq!(iter.next(), None); - } - #[test] fn flowy_str_utf16_code_point_iter_test2() { let s: FlowyStr = "👋😁👋".into(); diff --git a/shared-lib/lib-ot/src/core/operation/builder.rs b/shared-lib/lib-ot/src/core/operation/builder.rs index d1803a8e21..9483d4cae7 100644 --- a/shared-lib/lib-ot/src/core/operation/builder.rs +++ b/shared-lib/lib-ot/src/core/operation/builder.rs @@ -1,51 +1,47 @@ use crate::core::operation::{Attributes, Operation, PhantomAttributes}; use crate::rich_text::RichTextAttributes; -pub type RichTextOpBuilder = OperationBuilder; -pub type PlainTextOpBuilder = OperationBuilder; +pub type RichTextOpBuilder = OperationsBuilder; +pub type PlainTextOpBuilder = OperationsBuilder; -pub struct OperationBuilder { +pub struct OperationsBuilder { operations: Vec>, } -impl OperationBuilder +impl OperationsBuilder where T: Attributes, { - pub fn new() -> OperationBuilder { - OperationBuilder { operations: vec![] } + pub fn new() -> OperationsBuilder { + OperationsBuilder { operations: vec![] } } - pub fn retain(mut self, n: usize) -> OperationBuilder { - let mut retain = Operation::Retain(n.into()); - - if let Some(attributes) = attributes { - if let Operation::Retain(r) = &mut retain { - r.attributes = attributes; - } - } + pub fn retain_with_attributes(mut self, n: usize, attributes: T) -> OperationsBuilder { + let retain = Operation::retain_with_attributes(n.into(), attributes); self.operations.push(retain); self } - pub fn delete(mut self, n: usize) -> OperationBuilder { + pub fn retain(mut self, n: usize) -> OperationsBuilder { + let retain = Operation::retain(n.into()); + self.operations.push(retain); + self + } + + pub fn delete(mut self, n: usize) -> OperationsBuilder { self.operations.push(Operation::Delete(n)); self } - pub fn insert(mut self, s: &str, attributes: Option) -> OperationBuilder { - let mut insert = Operation::Insert(s.into()); - if let Some(attributes) = attributes { - if let Operation::Retain(i) = &mut insert { - i.attributes = attributes; - } - } + pub fn insert_with_attributes(mut self, s: &str, attributes: T) -> OperationsBuilder { + let insert = Operation::insert_with_attributes(s.into(), attributes); self.operations.push(insert); self } - pub fn attributes(mut self, attrs: T) -> OperationBuilder { - self.attrs = attrs; + pub fn insert(mut self, s: &str) -> OperationsBuilder { + let insert = Operation::insert(s.into()); + self.operations.push(insert); self } diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 9464f91784..7198c38615 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -1,6 +1,5 @@ use crate::core::flowy_str::FlowyStr; use crate::core::interval::Interval; -use crate::core::operation::OperationBuilder; use crate::errors::OTError; use serde::{Deserialize, Serialize, __private::Formatter}; use std::fmt::Display; @@ -105,6 +104,40 @@ impl Operation where T: Attributes, { + pub fn delete(n: usize) -> Self { + Self::Delete(n) + } + + /// Create a [Retain] operation with the given attributes + pub fn retain_with_attributes(n: usize, attributes: T) -> Self { + Self::Retain(Retain { n, attributes }) + } + + /// Create a [Retain] operation without attributes + pub fn retain(n: usize) -> Self { + Self::Retain(Retain { + n, + attributes: T::default(), + }) + } + + /// Create a [Insert] operation with the given attributes + pub fn insert_with_attributes(s: &str, attributes: T) -> Self { + Self::Insert(Insert { + s: FlowyStr::from(s), + attributes, + }) + } + + /// Create a [Insert] operation without attributes + pub fn insert(s: &str) -> Self { + Self::Insert(Insert { + s: FlowyStr::from(s), + attributes: T::default(), + }) + } + + /// Return the String if the operation is [Insert] operation, otherwise return the empty string. pub fn get_data(&self) -> &str { match self { Operation::Delete(_) => "", @@ -152,45 +185,58 @@ where let right; match self { Operation::Delete(n) => { - left = Some(OperationBuilder::::delete(index).build()); - right = Some(OperationBuilder::::delete(*n - index).build()); + left = Some(Operation::::delete(index)); + right = Some(Operation::::delete(*n - index)); } Operation::Retain(retain) => { - left = Some(OperationBuilder::::delete(index).build()); - right = Some(OperationBuilder::::delete(retain.n - index).build()); + left = Some(Operation::::delete(index)); + right = Some(Operation::::delete(retain.n - index)); } Operation::Insert(insert) => { let attributes = self.get_attributes(); - left = Some( - OperationBuilder::::insert(&insert.s[0..index]) - .attributes(attributes.clone()) - .build(), - ); - right = Some( - OperationBuilder::::insert(&insert.s[index..insert.utf16_size()]) - .attributes(attributes) - .build(), - ); + left = Some(Operation::::insert_with_attributes( + &insert.s[0..index], + attributes.clone(), + )); + right = Some(Operation::::insert_with_attributes( + &insert.s[index..insert.utf16_size()], + attributes, + )); } } (left, right) } + /// Returns an operation with the specified width. + /// # Arguments + /// + /// * `interval`: Specify the shrink width of the operation. + /// + /// # Examples + /// + /// ``` + /// use lib_ot::core::{Interval, Operation, PhantomAttributes}; + /// let operation = Operation::::insert("1234"); + /// + /// let op1 = operation.shrink(Interval::new(0,3)).unwrap(); + /// assert_eq!(op1 , Operation::insert("123")); + /// + /// let op2= operation.shrink(Interval::new(3,4)).unwrap(); + /// assert_eq!(op2, Operation::insert("4")); + /// ``` pub fn shrink(&self, interval: Interval) -> Option> { let op = match self { - Operation::Delete(n) => OperationBuilder::delete(min(*n, interval.size())).build(), - Operation::Retain(retain) => OperationBuilder::retain(min(retain.n, interval.size())) - .attributes(retain.attributes.clone()) - .build(), + Operation::Delete(n) => Operation::delete(min(*n, interval.size())), + Operation::Retain(retain) => { + Operation::retain_with_attributes(min(retain.n, interval.size()), retain.attributes.clone()) + } Operation::Insert(insert) => { if interval.start > insert.utf16_size() { - OperationBuilder::insert("").build() + Operation::insert("") } else { let s = insert.s.sub_str(interval).unwrap_or_else(|| "".to_owned()); - OperationBuilder::insert(&s) - .attributes(insert.attributes.clone()) - .build() + Operation::insert_with_attributes(&s, insert.attributes.clone()) } } }; @@ -287,7 +333,7 @@ where self.n += n; None } else { - Some(OperationBuilder::retain(n).attributes(attributes).build()) + Some(Operation::retain_with_attributes(n, attributes)) } } @@ -368,7 +414,7 @@ where self.s += s; None } else { - Some(OperationBuilder::::insert(s).attributes(attributes).build()) + Some(Operation::::insert_with_attributes(s, attributes)) } } From 57a95825d9b5f0f1934146a479f9298c245a29ca Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 1 Aug 2022 11:32:25 +0800 Subject: [PATCH 108/112] chore: rename flowyStr to OTString --- .../tests/editor/attribute_test.rs | 4 +- .../flowy-text-block/tests/editor/mod.rs | 2 +- .../flowy-text-block/tests/editor/op_test.rs | 8 +- shared-lib/flowy-sync/src/util.rs | 6 +- shared-lib/lib-ot/src/core/delta/delta.rs | 12 +-- shared-lib/lib-ot/src/core/flowy_str.rs | 88 +++++++++---------- .../lib-ot/src/core/operation/operation.rs | 12 +-- .../src/core/operation/operation_serde.rs | 6 +- 8 files changed, 69 insertions(+), 69 deletions(-) diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs index bdeb1601b9..c59d85e025 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs @@ -1,7 +1,7 @@ #![cfg_attr(rustfmt, rustfmt::skip)] use crate::editor::{TestBuilder, TestOp::*}; use flowy_sync::client_document::{NewlineDoc, PlainDoc}; -use lib_ot::core::{Interval, OperationTransform, NEW_LINE, WHITESPACE, FlowyStr}; +use lib_ot::core::{Interval, OperationTransform, NEW_LINE, WHITESPACE, OTString}; use unicode_segmentation::UnicodeSegmentation; use lib_ot::rich_text::RichTextDelta; @@ -723,7 +723,7 @@ fn attributes_preserve_header_format_on_merge() { #[test] fn attributes_format_emoji() { let emoji_s = "👋 "; - let s: FlowyStr = emoji_s.into(); + let s: OTString = emoji_s.into(); let len = s.utf16_len(); assert_eq!(3, len); assert_eq!(2, s.graphemes(true).count()); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs index 64f432a1e7..46442a6336 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs @@ -300,7 +300,7 @@ impl Rng { pub fn gen_delta(&mut self, s: &str) -> RichTextDelta { let mut delta = RichTextDelta::default(); - let s = FlowyStr::from(s); + let s = OTString::from(s); loop { let left = s.utf16_len() - delta.utf16_base_len; if left == 0 { diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index cb7bb0a728..ac091398b5 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -333,7 +333,7 @@ fn sequence() { fn apply_1000() { for _ in 0..1 { let mut rng = Rng::default(); - let s: FlowyStr = rng.gen_string(50).into(); + let s: OTString = rng.gen_string(50).into(); let delta = rng.gen_delta(&s); assert_eq!(s.utf16_len(), delta.utf16_base_len); } @@ -458,16 +458,16 @@ fn compose() { let mut rng = Rng::default(); let s = rng.gen_string(20); let a = rng.gen_delta(&s); - let after_a: FlowyStr = a.apply(&s).unwrap().into(); + let after_a: OTString = a.apply(&s).unwrap().into(); assert_eq!(a.utf16_target_len, after_a.utf16_len()); let b = rng.gen_delta(&after_a); - let after_b: FlowyStr = b.apply(&after_a).unwrap().into(); + let after_b: OTString = b.apply(&after_a).unwrap().into(); assert_eq!(b.utf16_target_len, after_b.utf16_len()); let ab = a.compose(&b).unwrap(); assert_eq!(ab.utf16_target_len, b.utf16_target_len); - let after_ab: FlowyStr = ab.apply(&s).unwrap().into(); + let after_ab: OTString = ab.apply(&s).unwrap().into(); assert_eq!(after_b, after_ab); } } diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index 92728af8b1..9c0ab822c8 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -7,7 +7,7 @@ use crate::{ errors::{CollaborateError, CollaborateResult}, }; use dissimilar::Chunk; -use lib_ot::core::{DeltaBuilder, FlowyStr}; +use lib_ot::core::{DeltaBuilder, OTString}; use lib_ot::{ core::{Attributes, Delta, OperationTransform, NEW_LINE, WHITESPACE}, rich_text::RichTextDelta, @@ -208,10 +208,10 @@ pub fn cal_diff(old: String, new: String) -> Option> { for chunk in &chunks { match chunk { Chunk::Equal(s) => { - delta_builder = delta_builder.retain(FlowyStr::from(*s).utf16_len()); + delta_builder = delta_builder.retain(OTString::from(*s).utf16_len()); } Chunk::Delete(s) => { - delta_builder = delta_builder.delete(FlowyStr::from(*s).utf16_len()); + delta_builder = delta_builder.delete(OTString::from(*s).utf16_len()); } Chunk::Insert(s) => { delta_builder = delta_builder.insert(*s); diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 53cdcaac54..b047091815 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -1,7 +1,7 @@ use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::core::delta::{DeltaIterator, MAX_IV_LEN}; -use crate::core::flowy_str::FlowyStr; +use crate::core::flowy_str::OTString; use crate::core::interval::Interval; use crate::core::operation::{Attributes, Operation, OperationTransform, PhantomAttributes}; use bytes::Bytes; @@ -118,7 +118,7 @@ where /// Creating a [Insert] operation with string, [s]. pub fn insert(&mut self, s: &str, attributes: T) { - let s: FlowyStr = s.into(); + let s: OTString = s.into(); if s.is_empty() { return; } @@ -189,7 +189,7 @@ where /// assert_eq!("hello, AppFlowy", &after_b); /// ``` pub fn apply(&self, applied_str: &str) -> Result { - let applied_str: FlowyStr = applied_str.into(); + let applied_str: OTString = applied_str.into(); if applied_str.utf16_len() != self.utf16_base_len { return Err(ErrorBuilder::new(OTErrorCode::IncompatibleLength) .msg(format!( @@ -200,7 +200,7 @@ where .build()); } let mut new_s = String::new(); - let code_point_iter = &mut applied_str.utf16_code_unit_iter(); + let code_point_iter = &mut applied_str.utf16_iter(); for op in &self.ops { match &op { Operation::Retain(retain) => { @@ -246,8 +246,8 @@ where /// pub fn invert_str(&self, inverted_s: &str) -> Self { let mut inverted = Delta::default(); - let inverted_s: FlowyStr = inverted_s.into(); - let code_point_iter = &mut inverted_s.utf16_code_unit_iter(); + let inverted_s: OTString = inverted_s.into(); + let code_point_iter = &mut inverted_s.utf16_iter(); for op in &self.ops { match &op { diff --git a/shared-lib/lib-ot/src/core/flowy_str.rs b/shared-lib/lib-ot/src/core/flowy_str.rs index 162557f5f3..e6811f190c 100644 --- a/shared-lib/lib-ot/src/core/flowy_str.rs +++ b/shared-lib/lib-ot/src/core/flowy_str.rs @@ -1,41 +1,41 @@ use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use std::{fmt, fmt::Formatter}; +/// [OTString] uses [String] as its inner container. #[derive(Clone, Debug, Eq, PartialEq)] -pub struct FlowyStr(pub String); +pub struct OTString(pub String); -impl FlowyStr { +impl OTString { + /// Returns the number of UTF-16 code units in this string. /// - /// # Arguments - /// - /// * `delta`: The delta you want to iterate over. - /// * `interval`: The range for the cursor movement. + /// The length of strings behaves differently in different languages. For example: [Dart] string's + /// length is calculated with UTF-16 code units. The method [utf16_len] returns the length of a + /// String in UTF-16 code units. /// /// # Examples /// /// ``` - /// use lib_ot::core::FlowyStr; - /// let utf16_len = FlowyStr::from("👋").utf16_len(); + /// use lib_ot::core::OTString; + /// let utf16_len = OTString::from("👋").utf16_len(); /// assert_eq!(utf16_len, 2); /// let bytes_len = String::from("👋").len(); /// assert_eq!(bytes_len, 4); /// /// ``` - /// https://stackoverflow.com/questions/2241348/what-is-unicode-utf-8-utf-16 pub fn utf16_len(&self) -> usize { count_utf16_code_units(&self.0) } - pub fn utf16_code_unit_iter(&self) -> Utf16CodeUnitIterator { + pub fn utf16_iter(&self) -> Utf16CodeUnitIterator { Utf16CodeUnitIterator::new(self) } - /// Return a new string with the given [Interval] + /// Returns a new string with the given [Interval] /// # Examples /// /// ``` - /// use lib_ot::core::{FlowyStr, Interval}; - /// let s: FlowyStr = "你好\n😁".into(); + /// use lib_ot::core::{OTString, Interval}; + /// let s: OTString = "你好\n😁".into(); /// assert_eq!(s.utf16_len(), 5); /// let output1 = s.sub_str(Interval::new(0, 2)).unwrap(); /// assert_eq!(output1, "你好"); @@ -69,21 +69,21 @@ impl FlowyStr { /// # Examples /// /// ``` - /// use lib_ot::core::FlowyStr; - /// let s: FlowyStr = "👋😁👋".into(); /// + /// use lib_ot::core::OTString; + /// let s: OTString = "👋😁👋".into(); /// /// let mut iter = s.utf16_code_point_iter(); /// assert_eq!(iter.next().unwrap(), "👋".to_string()); /// assert_eq!(iter.next().unwrap(), "😁".to_string()); /// assert_eq!(iter.next().unwrap(), "👋".to_string()); /// assert_eq!(iter.next(), None); /// - /// let s: FlowyStr = "👋12ab一二👋".into(); /// + /// let s: OTString = "👋12ab一二👋".into(); /// /// let mut iter = s.utf16_code_point_iter(); /// assert_eq!(iter.next().unwrap(), "👋".to_string()); /// assert_eq!(iter.next().unwrap(), "1".to_string()); /// assert_eq!(iter.next().unwrap(), "2".to_string()); /// - /// assert_eq!(iter.skip(FlowyStr::from("ab一二").utf16_len()).next().unwrap(), "👋".to_string()); + /// assert_eq!(iter.skip(OTString::from("ab一二").utf16_len()).next().unwrap(), "👋".to_string()); /// ``` #[allow(dead_code)] pub fn utf16_code_point_iter(&self) -> FlowyUtf16CodePointIterator { @@ -91,7 +91,7 @@ impl FlowyStr { } } -impl std::ops::Deref for FlowyStr { +impl std::ops::Deref for OTString { type Target = String; fn deref(&self) -> &Self::Target { @@ -99,46 +99,46 @@ impl std::ops::Deref for FlowyStr { } } -impl std::ops::DerefMut for FlowyStr { +impl std::ops::DerefMut for OTString { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -impl std::convert::From for FlowyStr { +impl std::convert::From for OTString { fn from(s: String) -> Self { - FlowyStr(s) + OTString(s) } } -impl std::convert::From<&str> for FlowyStr { +impl std::convert::From<&str> for OTString { fn from(s: &str) -> Self { s.to_owned().into() } } -impl std::fmt::Display for FlowyStr { +impl std::fmt::Display for OTString { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.write_str(&self.0) } } -impl std::ops::Add<&str> for FlowyStr { - type Output = FlowyStr; +impl std::ops::Add<&str> for OTString { + type Output = OTString; - fn add(self, rhs: &str) -> FlowyStr { + fn add(self, rhs: &str) -> OTString { let new_value = self.0 + rhs; new_value.into() } } -impl std::ops::AddAssign<&str> for FlowyStr { +impl std::ops::AddAssign<&str> for OTString { fn add_assign(&mut self, rhs: &str) { self.0 += rhs; } } -impl Serialize for FlowyStr { +impl Serialize for OTString { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -147,15 +147,15 @@ impl Serialize for FlowyStr { } } -impl<'de> Deserialize<'de> for FlowyStr { - fn deserialize(deserializer: D) -> Result +impl<'de> Deserialize<'de> for OTString { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { - struct FlowyStrVisitor; + struct OTStringVisitor; - impl<'de> Visitor<'de> for FlowyStrVisitor { - type Value = FlowyStr; + impl<'de> Visitor<'de> for OTStringVisitor { + type Value = OTString; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a str") @@ -168,19 +168,19 @@ impl<'de> Deserialize<'de> for FlowyStr { Ok(s.into()) } } - deserializer.deserialize_str(FlowyStrVisitor) + deserializer.deserialize_str(OTStringVisitor) } } pub struct Utf16CodeUnitIterator<'a> { - s: &'a FlowyStr, + s: &'a OTString, byte_offset: usize, utf16_offset: usize, utf16_count: usize, } impl<'a> Utf16CodeUnitIterator<'a> { - pub fn new(s: &'a FlowyStr) -> Self { + pub fn new(s: &'a OTString) -> Self { Utf16CodeUnitIterator { s, byte_offset: 0, @@ -219,12 +219,12 @@ impl<'a> Iterator for Utf16CodeUnitIterator<'a> { } pub struct FlowyUtf16CodePointIterator<'a> { - s: &'a FlowyStr, + s: &'a OTString, offset: usize, } impl<'a> FlowyUtf16CodePointIterator<'a> { - pub fn new(s: &'a FlowyStr, offset: usize) -> Self { + pub fn new(s: &'a OTString, offset: usize) -> Self { FlowyUtf16CodePointIterator { s, offset } } } @@ -278,15 +278,15 @@ pub fn len_utf8_from_first_byte(b: u8) -> usize { #[cfg(test)] mod tests { - use crate::core::flowy_str::FlowyStr; + use crate::core::flowy_str::OTString; use crate::core::interval::Interval; #[test] fn flowy_str_code_unit() { - let size = FlowyStr::from("👋").utf16_len(); + let size = OTString::from("👋").utf16_len(); assert_eq!(size, 2); - let s: FlowyStr = "👋 \n👋".into(); + let s: OTString = "👋 \n👋".into(); let output = s.sub_str(Interval::new(0, size)).unwrap(); assert_eq!(output, "👋"); @@ -302,7 +302,7 @@ mod tests { #[test] fn flowy_str_sub_str_in_chinese2() { - let s: FlowyStr = "😁 \n".into(); + let s: OTString = "😁 \n".into(); let size = s.utf16_len(); assert_eq!(size, 4); @@ -314,7 +314,7 @@ mod tests { #[test] fn flowy_str_sub_str_in_english() { - let s: FlowyStr = "ab".into(); + let s: OTString = "ab".into(); let size = s.utf16_len(); assert_eq!(size, 2); @@ -324,7 +324,7 @@ mod tests { #[test] fn flowy_str_utf16_code_point_iter_test2() { - let s: FlowyStr = "👋😁👋".into(); + let s: OTString = "👋😁👋".into(); let iter = s.utf16_code_point_iter(); let result = iter.skip(1).take(1).collect::(); assert_eq!(result, "😁".to_string()); diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 7198c38615..482a5739ad 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -1,4 +1,4 @@ -use crate::core::flowy_str::FlowyStr; +use crate::core::flowy_str::OTString; use crate::core::interval::Interval; use crate::errors::OTError; use serde::{Deserialize, Serialize, __private::Formatter}; @@ -124,7 +124,7 @@ where /// Create a [Insert] operation with the given attributes pub fn insert_with_attributes(s: &str, attributes: T) -> Self { Self::Insert(Insert { - s: FlowyStr::from(s), + s: OTString::from(s), attributes, }) } @@ -132,7 +132,7 @@ where /// Create a [Insert] operation without attributes pub fn insert(s: &str) -> Self { Self::Insert(Insert { - s: FlowyStr::from(s), + s: OTString::from(s), attributes: T::default(), }) } @@ -376,7 +376,7 @@ where #[derive(Clone, Debug, Eq, PartialEq)] pub struct Insert { - pub s: FlowyStr, + pub s: OTString, pub attributes: T, } @@ -444,11 +444,11 @@ where } } -impl std::convert::From for Insert +impl std::convert::From for Insert where T: Attributes, { - fn from(s: FlowyStr) -> Self { + fn from(s: OTString) -> Self { Insert { s, attributes: T::default(), diff --git a/shared-lib/lib-ot/src/core/operation/operation_serde.rs b/shared-lib/lib-ot/src/core/operation/operation_serde.rs index d029fb0e16..40386235da 100644 --- a/shared-lib/lib-ot/src/core/operation/operation_serde.rs +++ b/shared-lib/lib-ot/src/core/operation/operation_serde.rs @@ -1,4 +1,4 @@ -use crate::core::flowy_str::FlowyStr; +use crate::core::flowy_str::OTString; use crate::core::operation::{Attributes, Insert, Operation, Retain}; use serde::{ de, @@ -249,7 +249,7 @@ where where A: SeqAccess<'de>, { - let s = match serde::de::SeqAccess::next_element::(&mut seq)? { + let s = match serde::de::SeqAccess::next_element::(&mut seq)? { Some(val) => val, None => { return Err(de::Error::invalid_length(0, &"struct Insert with 2 elements")); @@ -271,7 +271,7 @@ where where V: MapAccess<'de>, { - let mut s: Option = None; + let mut s: Option = None; let mut attributes: Option = None; while let Some(key) = map.next_key()? { match key { From 00d81a329f6a01cb4c22c2350a0013221f2896f5 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 2 Aug 2022 08:55:33 +0800 Subject: [PATCH 109/112] chore: update lib-ot documentation again and rename some structs --- .../src/services/persistence/mod.rs | 4 ++-- .../flowy-folder/src/services/web_socket.rs | 15 +++++------- .../src/services/persistence/migration.rs | 4 ++-- .../flowy-text-block/tests/editor/op_test.rs | 9 +++----- .../flowy-sync/src/client_folder/builder.rs | 6 ++--- .../src/client_folder/folder_pad.rs | 12 +++++----- .../src/client_grid/grid_block_revsion_pad.rs | 8 +++---- .../src/client_grid/grid_revision_pad.rs | 8 +++---- shared-lib/flowy-sync/src/entities/folder.rs | 4 ++-- .../src/server_folder/folder_pad.rs | 8 +++---- shared-lib/lib-ot/src/core/delta/builder.rs | 18 +++++++-------- shared-lib/lib-ot/src/core/delta/cursor.rs | 15 +++++++----- shared-lib/lib-ot/src/core/delta/delta.rs | 18 +++++++++------ shared-lib/lib-ot/src/core/delta/iterator.rs | 23 +++++++++++++------ shared-lib/lib-ot/src/core/mod.rs | 4 ++-- .../lib-ot/src/core/operation/operation.rs | 20 ++++++++-------- .../src/core/operation/operation_serde.rs | 2 +- .../src/core/{flowy_str.rs => ot_str.rs} | 14 +++++------ 18 files changed, 101 insertions(+), 91 deletions(-) rename shared-lib/lib-ot/src/core/{flowy_str.rs => ot_str.rs} (96%) diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs index ee930bd6ff..468785802c 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs @@ -13,7 +13,7 @@ use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision use flowy_revision::disk::{RevisionRecord, RevisionState}; use flowy_revision::mk_text_block_revision_disk_cache; use flowy_sync::{client_folder::FolderPad, entities::revision::Revision}; -use lib_ot::core::PlainTextDeltaBuilder; +use lib_ot::core::TextDeltaBuilder; use std::sync::Arc; use tokio::sync::RwLock; pub use version_1::{app_sql::*, trash_sql::*, v1_impl::V1Transaction, view_sql::*, workspace_sql::*}; @@ -110,7 +110,7 @@ impl FolderPersistence { pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> { let pool = self.database.db_pool()?; let json = folder.to_json()?; - let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_json_bytes(); + let delta_data = TextDeltaBuilder::new().insert(&json).build().to_json_bytes(); let revision = Revision::initial_revision(user_id, folder_id.as_ref(), delta_data); let record = RevisionRecord { revision, diff --git a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs index 4b5481c9a0..993e556f8a 100644 --- a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs +++ b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs @@ -10,7 +10,7 @@ use flowy_sync::{ }, }; use lib_infra::future::{BoxResultFuture, FutureResult}; -use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta}; +use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta}; use parking_lot::RwLock; use std::{sync::Arc, time::Duration}; @@ -56,7 +56,7 @@ struct FolderConflictResolver { } impl ConflictResolver for FolderConflictResolver { - fn compose_delta(&self, delta: PlainTextDelta) -> BoxResultFuture { + fn compose_delta(&self, delta: TextDelta) -> BoxResultFuture { let folder_pad = self.folder_pad.clone(); Box::pin(async move { let md5 = folder_pad.write().compose_remote_delta(delta)?; @@ -64,15 +64,12 @@ impl ConflictResolver for FolderConflictResolver { }) } - fn transform_delta( - &self, - delta: PlainTextDelta, - ) -> BoxResultFuture, FlowyError> { + fn transform_delta(&self, delta: TextDelta) -> BoxResultFuture, FlowyError> { let folder_pad = self.folder_pad.clone(); Box::pin(async move { let read_guard = folder_pad.read(); - let mut server_prime: Option = None; - let client_prime: PlainTextDelta; + let mut server_prime: Option = None; + let client_prime: TextDelta; if read_guard.is_empty() { // Do nothing client_prime = delta; @@ -89,7 +86,7 @@ impl ConflictResolver for FolderConflictResolver { }) } - fn reset_delta(&self, delta: PlainTextDelta) -> BoxResultFuture { + fn reset_delta(&self, delta: TextDelta) -> BoxResultFuture { let folder_pad = self.folder_pad.clone(); Box::pin(async move { let md5 = folder_pad.write().reset_folder(delta)?; diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs index 9b24d03fda..0fb49a197b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs @@ -9,7 +9,7 @@ use flowy_revision::{mk_grid_block_revision_disk_cache, RevisionLoader, Revision use flowy_sync::client_grid::{make_grid_rev_json_str, GridRevisionPad}; use flowy_sync::entities::revision::Revision; -use lib_ot::core::PlainTextDeltaBuilder; +use lib_ot::core::TextDeltaBuilder; use serde::{Deserialize, Serialize}; use std::str::FromStr; use std::sync::Arc; @@ -48,7 +48,7 @@ impl GridMigration { let pool = self.database.db_pool()?; let grid_rev_pad = self.get_grid_revision_pad(grid_id).await?; let json = grid_rev_pad.json_str()?; - let delta_data = PlainTextDeltaBuilder::new().insert(&json).build().to_json_bytes(); + let delta_data = TextDeltaBuilder::new().insert(&json).build().to_json_bytes(); let revision = Revision::initial_revision(&user_id, grid_id, delta_data); let record = RevisionRecord::new(revision); // diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index ac091398b5..cbb4fe3e3f 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -342,11 +342,8 @@ fn apply_1000() { #[test] fn apply_test() { let s = "hello"; - let delta_a = PlainTextDeltaBuilder::new().insert(s).build(); - let delta_b = PlainTextDeltaBuilder::new() - .retain(s.len()) - .insert(", AppFlowy") - .build(); + let delta_a = TextDeltaBuilder::new().insert(s).build(); + let delta_b = TextDeltaBuilder::new().retain(s.len()).insert(", AppFlowy").build(); let after_a = delta_a.content_str().unwrap(); let after_b = delta_b.apply(&after_a).unwrap(); @@ -384,7 +381,7 @@ fn invert() { #[test] fn invert_test() { let s = "hello world"; - let delta = PlainTextDeltaBuilder::new().insert(s).build(); + let delta = TextDeltaBuilder::new().insert(s).build(); let invert_delta = delta.invert_str(""); assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len); assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len); diff --git a/shared-lib/flowy-sync/src/client_folder/builder.rs b/shared-lib/flowy-sync/src/client_folder/builder.rs index b055f91fb8..848b6f5127 100644 --- a/shared-lib/flowy-sync/src/client_folder/builder.rs +++ b/shared-lib/flowy-sync/src/client_folder/builder.rs @@ -7,7 +7,7 @@ use crate::{ }; use flowy_folder_data_model::revision::{TrashRevision, WorkspaceRevision}; -use lib_ot::core::{PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{PhantomAttributes, TextDelta, TextDeltaBuilder}; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -35,7 +35,7 @@ impl FolderPadBuilder { self } - pub(crate) fn build_with_delta(self, mut delta: PlainTextDelta) -> CollaborateResult { + pub(crate) fn build_with_delta(self, mut delta: TextDelta) -> CollaborateResult { if delta.is_empty() { delta = default_folder_delta(); } @@ -61,7 +61,7 @@ impl FolderPadBuilder { Ok(FolderPad { workspaces: self.workspaces, trash: self.trash, - delta: PlainTextDeltaBuilder::new().insert(&json).build(), + delta: TextDeltaBuilder::new().insert(&json).build(), }) } } diff --git a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs index 632aa7f29b..52d479f6d4 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs @@ -400,14 +400,14 @@ impl FolderPad { } pub fn default_folder_delta() -> FolderDelta { - PlainTextDeltaBuilder::new() + TextDeltaBuilder::new() .insert(r#"{"workspaces":[],"trash":[]}"#) .build() } pub fn initial_folder_delta(folder_pad: &FolderPad) -> CollaborateResult { let json = folder_pad.to_json()?; - let delta = PlainTextDeltaBuilder::new().insert(&json).build(); + let delta = TextDeltaBuilder::new().insert(&json).build(); Ok(delta) } @@ -434,7 +434,7 @@ mod tests { use chrono::Utc; use flowy_folder_data_model::revision::{AppRevision, TrashRevision, ViewRevision, WorkspaceRevision}; - use lib_ot::core::{OperationTransform, PlainTextDelta, PlainTextDeltaBuilder}; + use lib_ot::core::{OperationTransform, TextDelta, TextDeltaBuilder}; #[test] fn folder_add_workspace() { @@ -749,7 +749,7 @@ mod tests { fn test_folder() -> (FolderPad, FolderDelta, WorkspaceRevision) { let mut folder = FolderPad::default(); let folder_json = serde_json::to_string(&folder).unwrap(); - let mut delta = PlainTextDeltaBuilder::new().insert(&folder_json).build(); + let mut delta = TextDeltaBuilder::new().insert(&folder_json).build(); let mut workspace_rev = WorkspaceRevision::default(); workspace_rev.name = "😁 my first workspace".to_owned(); @@ -791,7 +791,7 @@ mod tests { fn test_trash() -> (FolderPad, FolderDelta, TrashRevision) { let mut folder = FolderPad::default(); let folder_json = serde_json::to_string(&folder).unwrap(); - let mut delta = PlainTextDeltaBuilder::new().insert(&folder_json).build(); + let mut delta = TextDeltaBuilder::new().insert(&folder_json).build(); let mut trash_rev = TrashRevision::default(); trash_rev.name = "🚽 my first trash".to_owned(); @@ -810,7 +810,7 @@ mod tests { (folder, delta, trash_rev) } - fn make_folder_from_delta(mut initial_delta: FolderDelta, deltas: Vec) -> FolderPad { + fn make_folder_from_delta(mut initial_delta: FolderDelta, deltas: Vec) -> FolderPad { for delta in deltas { initial_delta = initial_delta.compose(&delta).unwrap(); } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs index 82fb19cb8b..35fb7743fc 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs @@ -4,13 +4,13 @@ use crate::util::{cal_diff, make_delta_from_revisions}; use flowy_grid_data_model::revision::{ gen_block_id, gen_row_id, CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision, }; -use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder}; use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; -pub type GridBlockRevisionDelta = PlainTextDelta; -pub type GridBlockRevisionDeltaBuilder = PlainTextDeltaBuilder; +pub type GridBlockRevisionDelta = TextDelta; +pub type GridBlockRevisionDeltaBuilder = TextDeltaBuilder; #[derive(Debug, Clone)] pub struct GridBlockRevisionPad { @@ -247,7 +247,7 @@ pub struct GridBlockMetaChange { pub fn make_grid_block_delta(block_rev: &GridBlockRevision) -> GridBlockRevisionDelta { let json = serde_json::to_string(&block_rev).unwrap(); - PlainTextDeltaBuilder::new().insert(&json).build() + TextDeltaBuilder::new().insert(&json).build() } pub fn make_grid_block_revisions(user_id: &str, grid_block_meta_data: &GridBlockRevision) -> RepeatedRevision { diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index 9aee7cfedd..59ae462e8d 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -9,12 +9,12 @@ use flowy_grid_data_model::revision::{ GridLayoutRevision, GridRevision, GridSettingRevision, GridSortRevision, }; use lib_infra::util::move_vec_element; -use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta, PlainTextDeltaBuilder}; +use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta, TextDeltaBuilder}; use std::collections::HashMap; use std::sync::Arc; -pub type GridRevisionDelta = PlainTextDelta; -pub type GridRevisionDeltaBuilder = PlainTextDeltaBuilder; +pub type GridRevisionDelta = TextDelta; +pub type GridRevisionDeltaBuilder = TextDeltaBuilder; pub struct GridRevisionPad { grid_rev: Arc, @@ -548,7 +548,7 @@ pub struct GridChangeset { pub fn make_grid_delta(grid_rev: &GridRevision) -> GridRevisionDelta { let json = serde_json::to_string(&grid_rev).unwrap(); - PlainTextDeltaBuilder::new().insert(&json).build() + TextDeltaBuilder::new().insert(&json).build() } pub fn make_grid_revisions(user_id: &str, grid_rev: &GridRevision) -> RepeatedRevision { diff --git a/shared-lib/flowy-sync/src/entities/folder.rs b/shared-lib/flowy-sync/src/entities/folder.rs index 214190f517..952827d7d6 100644 --- a/shared-lib/flowy-sync/src/entities/folder.rs +++ b/shared-lib/flowy-sync/src/entities/folder.rs @@ -1,7 +1,7 @@ use flowy_derive::ProtoBuf; -use lib_ot::core::PlainTextDelta; +use lib_ot::core::TextDelta; -pub type FolderDelta = PlainTextDelta; +pub type FolderDelta = TextDelta; #[derive(ProtoBuf, Default, Debug, Clone, Eq, PartialEq)] pub struct FolderInfo { diff --git a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs index 2ff3d0e479..6cb942001b 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs @@ -1,5 +1,5 @@ use crate::{entities::folder::FolderDelta, errors::CollaborateError, synchronizer::RevisionSyncObject}; -use lib_ot::core::{OperationTransform, PhantomAttributes, PlainTextDelta}; +use lib_ot::core::{OperationTransform, PhantomAttributes, TextDelta}; pub struct ServerFolder { folder_id: String, @@ -20,13 +20,13 @@ impl RevisionSyncObject for ServerFolder { &self.folder_id } - fn compose(&mut self, other: &PlainTextDelta) -> Result<(), CollaborateError> { + fn compose(&mut self, other: &TextDelta) -> Result<(), CollaborateError> { let new_delta = self.delta.compose(other)?; self.delta = new_delta; Ok(()) } - fn transform(&self, other: &PlainTextDelta) -> Result<(PlainTextDelta, PlainTextDelta), CollaborateError> { + fn transform(&self, other: &TextDelta) -> Result<(TextDelta, TextDelta), CollaborateError> { let value = self.delta.transform(other)?; Ok(value) } @@ -35,7 +35,7 @@ impl RevisionSyncObject for ServerFolder { self.delta.to_json_str() } - fn set_delta(&mut self, new_delta: PlainTextDelta) { + fn set_delta(&mut self, new_delta: TextDelta) { self.delta = new_delta; } } diff --git a/shared-lib/lib-ot/src/core/delta/builder.rs b/shared-lib/lib-ot/src/core/delta/builder.rs index a8bb0459c1..ee21ecd8ca 100644 --- a/shared-lib/lib-ot/src/core/delta/builder.rs +++ b/shared-lib/lib-ot/src/core/delta/builder.rs @@ -1,9 +1,7 @@ use crate::core::delta::{trim, Delta}; -use crate::core::operation::{Attributes, PhantomAttributes}; +use crate::core::operation::Attributes; use crate::core::Operation; -pub type PlainTextDeltaBuilder = DeltaBuilder; - /// A builder for creating new [Delta] objects. /// /// Note that all edit operations must be sorted; the start point of each @@ -12,8 +10,8 @@ pub type PlainTextDeltaBuilder = DeltaBuilder; /// # Examples /// /// ``` -/// use lib_ot::core::PlainTextDeltaBuilder; -/// let delta = PlainTextDeltaBuilder::new() +/// use lib_ot::core::TextDeltaBuilder; +/// let delta = TextDeltaBuilder::new() /// .insert("AppFlowy") /// .build(); /// assert_eq!(delta.content_str().unwrap(), "AppFlowy"); @@ -74,13 +72,13 @@ where /// # Examples /// /// ``` - /// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder}; + /// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; /// - /// let delta = PlainTextDeltaBuilder::new() + /// let delta = TextDeltaBuilder::new() /// .insert("AppFlowy...") /// .build(); /// - /// let changeset = PlainTextDeltaBuilder::new() + /// let changeset = TextDeltaBuilder::new() /// .retain(8) /// .delete(3) /// .build(); @@ -110,9 +108,9 @@ where /// # Examples /// /// ``` - /// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder}; + /// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; /// use lib_ot::rich_text::{RichTextAttribute, RichTextDeltaBuilder}; - /// let delta = PlainTextDeltaBuilder::new() + /// let delta = TextDeltaBuilder::new() /// .retain(3) /// .trim() /// .build(); diff --git a/shared-lib/lib-ot/src/core/delta/cursor.rs b/shared-lib/lib-ot/src/core/delta/cursor.rs index 4c223dfd50..a068f1c029 100644 --- a/shared-lib/lib-ot/src/core/delta/cursor.rs +++ b/shared-lib/lib-ot/src/core/delta/cursor.rs @@ -29,14 +29,17 @@ where /// # Examples /// /// ``` - /// use lib_ot::core::{DeltaIterator, Interval, Operation}; + /// use lib_ot::core::{DeltaCursor, DeltaIterator, Interval, Operation}; /// use lib_ot::rich_text::RichTextDelta; /// let mut delta = RichTextDelta::default(); - /// let op_1 = Operation::insert("123"); - /// let op_2 = Operation::insert("4"); - /// delta.add(op_1.clone()); - /// delta.add(op_2.clone()); - /// assert_eq!(DeltaIterator::from_interval(&delta, Interval::new(0, 3)).ops(), vec![op_1.clone()]); + /// delta.add(Operation::insert("123")); + /// delta.add(Operation::insert("4")); + /// + /// let mut cursor = DeltaCursor::new(&delta, Interval::new(0, 3)); + /// assert_eq!(cursor.next_iv(), Interval::new(0,3)); + /// assert_eq!(cursor.next_with_len(Some(2)).unwrap(), Operation::insert("12")); + /// assert_eq!(cursor.get_next_op().unwrap(), Operation::insert("3")); + /// assert_eq!(cursor.get_next_op(), None); /// ``` pub fn new(delta: &'a Delta, interval: Interval) -> DeltaCursor<'a, T> { // debug_assert!(interval.start <= delta.target_len); diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index b047091815..86eb664921 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -1,9 +1,10 @@ use crate::errors::{ErrorBuilder, OTError, OTErrorCode}; use crate::core::delta::{DeltaIterator, MAX_IV_LEN}; -use crate::core::flowy_str::OTString; use crate::core::interval::Interval; use crate::core::operation::{Attributes, Operation, OperationTransform, PhantomAttributes}; +use crate::core::ot_str::OTString; +use crate::core::DeltaBuilder; use bytes::Bytes; use serde::de::DeserializeOwned; use std::{ @@ -14,12 +15,15 @@ use std::{ str::FromStr, }; -pub type PlainTextDelta = Delta; +pub type TextDelta = Delta; +pub type TextDeltaBuilder = DeltaBuilder; /// A [Delta] contains list of operations that consists of 'Retain', 'Delete' and 'Insert' operation. /// Check out the [Operation] for more details. It describes the document as a sequence of /// operations. /// +/// You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/delta) out for more information. +/// /// If the [T] supports 'serde', that will enable delta to serialize to JSON or deserialize from /// a JSON string. /// @@ -176,10 +180,10 @@ where /// # Examples /// /// ``` - /// use lib_ot::core::PlainTextDeltaBuilder; + /// use lib_ot::core::TextDeltaBuilder; /// let s = "hello"; - /// let delta_a = PlainTextDeltaBuilder::new().insert(s).build(); - /// let delta_b = PlainTextDeltaBuilder::new() + /// let delta_a = TextDeltaBuilder::new().insert(s).build(); + /// let delta_b = TextDeltaBuilder::new() /// .retain(s.len()) /// .insert(", AppFlowy") /// .build(); @@ -233,9 +237,9 @@ where /// # Examples /// /// ``` - /// use lib_ot::core::PlainTextDeltaBuilder; + /// use lib_ot::core::TextDeltaBuilder; /// let s = "hello world"; - /// let delta = PlainTextDeltaBuilder::new().insert(s).build(); + /// let delta = TextDeltaBuilder::new().insert(s).build(); /// let invert_delta = delta.invert_str(s); /// assert_eq!(delta.utf16_base_len, invert_delta.utf16_target_len); /// assert_eq!(delta.utf16_target_len, invert_delta.utf16_base_len); diff --git a/shared-lib/lib-ot/src/core/delta/iterator.rs b/shared-lib/lib-ot/src/core/delta/iterator.rs index d1ab80885f..7997d23bae 100644 --- a/shared-lib/lib-ot/src/core/delta/iterator.rs +++ b/shared-lib/lib-ot/src/core/delta/iterator.rs @@ -7,17 +7,26 @@ use std::ops::{Deref, DerefMut}; pub(crate) const MAX_IV_LEN: usize = i32::MAX as usize; -/// Retain the 'n' characters with the attributes. Use 'retain' instead if you don't -/// need any attributes. +/// [DeltaIterator] is used to iterate over a delta. /// # Examples /// +/// You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/delta) out for more information. +/// /// ``` -/// use lib_ot::rich_text::{RichTextAttribute, RichTextDelta, RichTextDeltaBuilder}; +/// use lib_ot::core::{DeltaIterator, Interval, Operation}; +/// use lib_ot::rich_text::RichTextDelta; +/// let mut delta = RichTextDelta::default(); +/// delta.add(Operation::insert("123")); +/// delta.add(Operation::insert("4")); +/// assert_eq!( +/// DeltaIterator::from_interval(&delta, Interval::new(0, 2)).ops(), +/// vec![Operation::insert("12")] +/// ); /// -/// let mut attribute = RichTextAttribute::Bold(true); -/// let delta = RichTextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); -/// -/// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#); +/// assert_eq!( +/// DeltaIterator::from_interval(&delta, Interval::new(1, 3)).ops(), +/// vec![Operation::insert("23")] +/// ); /// ``` pub struct DeltaIterator<'a, T: Attributes> { cursor: DeltaCursor<'a, T>, diff --git a/shared-lib/lib-ot/src/core/mod.rs b/shared-lib/lib-ot/src/core/mod.rs index 72a6dd9b74..7c1ed3f2ef 100644 --- a/shared-lib/lib-ot/src/core/mod.rs +++ b/shared-lib/lib-ot/src/core/mod.rs @@ -1,9 +1,9 @@ mod delta; -mod flowy_str; mod interval; mod operation; +mod ot_str; pub use delta::*; -pub use flowy_str::*; pub use interval::*; pub use operation::*; +pub use ot_str::*; diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 482a5739ad..040c459b97 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -1,5 +1,5 @@ -use crate::core::flowy_str::OTString; use crate::core::interval::Interval; +use crate::core::ot_str::OTString; use crate::errors::OTError; use serde::{Deserialize, Serialize, __private::Formatter}; use std::fmt::Display; @@ -21,9 +21,9 @@ pub trait OperationTransform { /// # Examples /// /// ``` - /// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder}; - /// let document = PlainTextDeltaBuilder::new().build(); - /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); + /// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; + /// let document = TextDeltaBuilder::new().build(); + /// let delta = TextDeltaBuilder::new().insert("abc").build(); /// let new_document = document.compose(&delta).unwrap(); /// assert_eq!(new_document.content_str().unwrap(), "abc".to_owned()); /// ``` @@ -50,9 +50,9 @@ pub trait OperationTransform { /// # Examples /// /// ``` - /// use lib_ot::core::{OperationTransform, PlainTextDeltaBuilder}; - /// let original_document = PlainTextDeltaBuilder::new().build(); - /// let delta = PlainTextDeltaBuilder::new().insert("abc").build(); + /// use lib_ot::core::{OperationTransform, TextDeltaBuilder}; + /// let original_document = TextDeltaBuilder::new().build(); + /// let delta = TextDeltaBuilder::new().insert("abc").build(); /// /// let undo_delta = delta.invert(&original_document); /// let new_document = original_document.compose(&delta).unwrap(); @@ -67,8 +67,8 @@ pub trait OperationTransform { /// Each operation can carry attributes. For example, the [RichTextAttributes] has a list of key/value attributes. /// Such as { bold: true, italic: true }. /// -/// Because [Operation] is generic over the T, so you must specify the T. For example, the [PlainTextDelta]. It use -/// use [PhantomAttributes] as the T. [PhantomAttributes] does nothing, just a phantom. +///Because [Operation] is generic over the T, so you must specify the T. For example, the [TextDelta] uses +///[PhantomAttributes] as the T. [PhantomAttributes] does nothing, just a phantom. /// pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + OperationTransform { fn is_empty(&self) -> bool { @@ -90,6 +90,8 @@ pub trait Attributes: Default + Display + Eq + PartialEq + Clone + Debug + Opera /// * Retain /// * Insert /// +/// You could check [this](https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/backend/delta) out for more information. +/// /// The [T] should support serde if you want to serialize/deserialize the operation /// to json string. You could check out the operation_serde.rs for more information. /// diff --git a/shared-lib/lib-ot/src/core/operation/operation_serde.rs b/shared-lib/lib-ot/src/core/operation/operation_serde.rs index 40386235da..b7ff7b3c20 100644 --- a/shared-lib/lib-ot/src/core/operation/operation_serde.rs +++ b/shared-lib/lib-ot/src/core/operation/operation_serde.rs @@ -1,5 +1,5 @@ -use crate::core::flowy_str::OTString; use crate::core::operation::{Attributes, Insert, Operation, Retain}; +use crate::core::ot_str::OTString; use serde::{ de, de::{MapAccess, SeqAccess, Visitor}, diff --git a/shared-lib/lib-ot/src/core/flowy_str.rs b/shared-lib/lib-ot/src/core/ot_str.rs similarity index 96% rename from shared-lib/lib-ot/src/core/flowy_str.rs rename to shared-lib/lib-ot/src/core/ot_str.rs index e6811f190c..7f84de6d20 100644 --- a/shared-lib/lib-ot/src/core/flowy_str.rs +++ b/shared-lib/lib-ot/src/core/ot_str.rs @@ -86,8 +86,8 @@ impl OTString { /// assert_eq!(iter.skip(OTString::from("ab一二").utf16_len()).next().unwrap(), "👋".to_string()); /// ``` #[allow(dead_code)] - pub fn utf16_code_point_iter(&self) -> FlowyUtf16CodePointIterator { - FlowyUtf16CodePointIterator::new(self, 0) + pub fn utf16_code_point_iter(&self) -> OTUtf16CodePointIterator { + OTUtf16CodePointIterator::new(self, 0) } } @@ -218,21 +218,21 @@ impl<'a> Iterator for Utf16CodeUnitIterator<'a> { } } -pub struct FlowyUtf16CodePointIterator<'a> { +pub struct OTUtf16CodePointIterator<'a> { s: &'a OTString, offset: usize, } -impl<'a> FlowyUtf16CodePointIterator<'a> { +impl<'a> OTUtf16CodePointIterator<'a> { pub fn new(s: &'a OTString, offset: usize) -> Self { - FlowyUtf16CodePointIterator { s, offset } + OTUtf16CodePointIterator { s, offset } } } use crate::core::interval::Interval; use std::str; -impl<'a> Iterator for FlowyUtf16CodePointIterator<'a> { +impl<'a> Iterator for OTUtf16CodePointIterator<'a> { type Item = String; fn next(&mut self) -> Option { @@ -278,8 +278,8 @@ pub fn len_utf8_from_first_byte(b: u8) -> usize { #[cfg(test)] mod tests { - use crate::core::flowy_str::OTString; use crate::core::interval::Interval; + use crate::core::ot_str::OTString; #[test] fn flowy_str_code_unit() { From ff098c538ef37f935568cf2a36698f37f6fbf0de Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 2 Aug 2022 09:11:04 +0800 Subject: [PATCH 110/112] chore: rename fns --- frontend/rust-lib/flowy-folder/src/manager.rs | 2 +- .../src/services/folder_editor.rs | 4 +-- .../src/services/persistence/mod.rs | 2 +- frontend/rust-lib/flowy-grid/src/manager.rs | 4 +-- .../src/services/block_revision_editor.rs | 4 +-- .../flowy-grid/src/services/grid_editor.rs | 4 +-- .../src/services/persistence/migration.rs | 2 +- .../flowy-revision/src/conflict_resolve.rs | 4 +-- .../rust-lib/flowy-text-block/src/editor.rs | 2 +- .../rust-lib/flowy-text-block/src/queue.rs | 4 +-- .../flowy-text-block/tests/document/script.rs | 2 +- .../tests/editor/attribute_test.rs | 12 ++++---- .../flowy-text-block/tests/editor/mod.rs | 26 ++++++++--------- .../flowy-text-block/tests/editor/op_test.rs | 2 +- .../tests/editor/serde_test.rs | 8 +++--- .../src/client_document/default/mod.rs | 6 ++-- .../src/client_document/document_pad.rs | 10 +++---- .../flowy-sync/src/client_folder/builder.rs | 2 +- .../src/client_folder/folder_pad.rs | 2 +- .../src/client_grid/grid_block_revsion_pad.rs | 28 ++++++++----------- .../src/client_grid/grid_revision_pad.rs | 10 +++---- .../flowy-sync/src/entities/revision.rs | 2 +- .../flowy-sync/src/entities/text_block.rs | 2 +- .../src/server_document/document_pad.rs | 2 +- .../src/server_folder/folder_pad.rs | 2 +- shared-lib/flowy-sync/src/util.rs | 4 +-- shared-lib/lib-ot/src/core/delta/builder.rs | 6 ++-- shared-lib/lib-ot/src/core/delta/delta.rs | 24 +++++++++------- .../lib-ot/src/core/operation/operation.rs | 2 +- 29 files changed, 92 insertions(+), 92 deletions(-) diff --git a/frontend/rust-lib/flowy-folder/src/manager.rs b/frontend/rust-lib/flowy-folder/src/manager.rs index 8850024f25..df070d90f3 100644 --- a/frontend/rust-lib/flowy-folder/src/manager.rs +++ b/frontend/rust-lib/flowy-folder/src/manager.rs @@ -215,7 +215,7 @@ impl DefaultFolderBuilder { for app in workspace_rev.apps.iter() { for (index, view) in app.belongings.iter().enumerate() { let view_data = if index == 0 { - initial_read_me().to_json_str() + initial_read_me().json_str() } else { initial_quill_delta_string() }; diff --git a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs index 6fb0ebf565..de461379e1 100644 --- a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs +++ b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs @@ -80,7 +80,7 @@ impl FolderEditor { pub(crate) fn apply_change(&self, change: FolderChange) -> FlowyResult<()> { let FolderChange { delta, md5 } = change; let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_json_bytes(); + let delta_data = delta.json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -133,6 +133,6 @@ pub struct FolderRevisionCompactor(); impl RevisionCompactor for FolderRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; - Ok(delta.to_json_bytes()) + Ok(delta.json_bytes()) } } diff --git a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs index 468785802c..ffa5219aa8 100644 --- a/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs +++ b/frontend/rust-lib/flowy-folder/src/services/persistence/mod.rs @@ -110,7 +110,7 @@ impl FolderPersistence { pub async fn save_folder(&self, user_id: &str, folder_id: &FolderId, folder: FolderPad) -> FlowyResult<()> { let pool = self.database.db_pool()?; let json = folder.to_json()?; - let delta_data = TextDeltaBuilder::new().insert(&json).build().to_json_bytes(); + let delta_data = TextDeltaBuilder::new().insert(&json).build().json_bytes(); let revision = Revision::initial_revision(user_id, folder_id.as_ref(), delta_data); let record = RevisionRecord { revision, diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index eadd1e47fd..19a3669c46 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -192,7 +192,7 @@ pub async fn make_grid_view_data( // Create grid's block let grid_block_delta = make_grid_block_delta(block_meta_data); - let block_delta_data = grid_block_delta.to_json_bytes(); + let block_delta_data = grid_block_delta.json_bytes(); let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, block_id, block_delta_data).into(); let _ = grid_manager.create_grid_block(&block_id, repeated_revision).await?; @@ -202,7 +202,7 @@ pub async fn make_grid_view_data( // Create grid let grid_meta_delta = make_grid_delta(&grid_rev); - let grid_delta_data = grid_meta_delta.to_json_bytes(); + let grid_delta_data = grid_meta_delta.json_bytes(); let repeated_revision: RepeatedRevision = Revision::initial_revision(user_id, view_id, grid_delta_data.clone()).into(); let _ = grid_manager.create_grid(view_id, repeated_revision).await?; diff --git a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs index 19f3a885cb..a9f68c5776 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_revision_editor.rs @@ -161,7 +161,7 @@ impl GridBlockRevisionEditor { let GridBlockMetaChange { delta, md5 } = change; let user_id = self.user_id.clone(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_json_bytes(); + let delta_data = delta.json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -201,6 +201,6 @@ pub struct GridBlockRevisionCompactor(); impl RevisionCompactor for GridBlockRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; - Ok(delta.to_json_bytes()) + Ok(delta.json_bytes()) } } 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 8c9b890952..44626b96fd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -572,7 +572,7 @@ impl GridRevisionEditor { let GridChangeset { delta, md5 } = change; let user_id = self.user.user_id()?; let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); - let delta_data = delta.to_json_bytes(); + let delta_data = delta.json_bytes(); let revision = Revision::new( &self.rev_manager.object_id, base_rev_id, @@ -664,7 +664,7 @@ pub struct GridRevisionCompactor(); impl RevisionCompactor for GridRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; - Ok(delta.to_json_bytes()) + Ok(delta.json_bytes()) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs index 0fb49a197b..bf3aa7adfb 100644 --- a/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs +++ b/frontend/rust-lib/flowy-grid/src/services/persistence/migration.rs @@ -48,7 +48,7 @@ impl GridMigration { let pool = self.database.db_pool()?; let grid_rev_pad = self.get_grid_revision_pad(grid_id).await?; let json = grid_rev_pad.json_str()?; - let delta_data = TextDeltaBuilder::new().insert(&json).build().to_json_bytes(); + let delta_data = TextDeltaBuilder::new().insert(&json).build().json_bytes(); let revision = Revision::initial_revision(&user_id, grid_id, delta_data); let record = RevisionRecord::new(revision); // diff --git a/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs index 5e89e7db32..8b36d554cd 100644 --- a/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs +++ b/frontend/rust-lib/flowy-revision/src/conflict_resolve.rs @@ -154,7 +154,7 @@ where &rev_manager.object_id, base_rev_id, rev_id, - client_delta.to_json_bytes(), + client_delta.json_bytes(), user_id, md5.clone(), ); @@ -166,7 +166,7 @@ where &rev_manager.object_id, base_rev_id, rev_id, - server_delta.to_json_bytes(), + server_delta.json_bytes(), user_id, md5, ); diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 2a52f43778..2649b2bae1 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -238,7 +238,7 @@ impl RevisionObjectBuilder for TextBlockInfoBuilder { Result::::Ok(DocumentPB { block_id: object_id.to_owned(), - text: delta.to_json_str(), + text: delta.json_str(), rev_id, base_rev_id, }) diff --git a/frontend/rust-lib/flowy-text-block/src/queue.rs b/frontend/rust-lib/flowy-text-block/src/queue.rs index 8756a50a00..e48c39fb97 100644 --- a/frontend/rust-lib/flowy-text-block/src/queue.rs +++ b/frontend/rust-lib/flowy-text-block/src/queue.rs @@ -175,7 +175,7 @@ impl EditBlockQueue { } async fn save_local_delta(&self, delta: RichTextDelta, md5: String) -> Result { - let delta_data = delta.to_json_bytes(); + let delta_data = delta.json_bytes(); let (base_rev_id, rev_id) = self.rev_manager.next_rev_id_pair(); let user_id = self.user.user_id()?; let revision = Revision::new( @@ -195,7 +195,7 @@ pub(crate) struct TextBlockRevisionCompactor(); impl RevisionCompactor for TextBlockRevisionCompactor { fn bytes_from_revisions(&self, revisions: Vec) -> FlowyResult { let delta = make_delta_from_revisions::(revisions)?; - Ok(delta.to_json_bytes()) + Ok(delta.json_bytes()) } } diff --git a/frontend/rust-lib/flowy-text-block/tests/document/script.rs b/frontend/rust-lib/flowy-text-block/tests/document/script.rs index b3ce1cb9bd..76c34a78e0 100644 --- a/frontend/rust-lib/flowy-text-block/tests/document/script.rs +++ b/frontend/rust-lib/flowy-text-block/tests/document/script.rs @@ -75,7 +75,7 @@ impl TextBlockEditorTest { let delta = self.editor.text_block_delta().await.unwrap(); if expected_delta != delta { eprintln!("✅ expect: {}", expected,); - eprintln!("❌ receive: {}", delta.to_json_str()); + eprintln!("❌ receive: {}", delta.json_str()); } assert_eq!(expected_delta, delta); } diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs index c59d85e025..0653e88567 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/attribute_test.rs @@ -762,19 +762,19 @@ fn attributes_preserve_list_format_on_merge() { #[test] fn delta_compose() { - let mut delta = RichTextDelta::from_json_str(r#"[{"insert":"\n"}]"#).unwrap(); + let mut delta = RichTextDelta::from_json(r#"[{"insert":"\n"}]"#).unwrap(); let deltas = vec![ - RichTextDelta::from_json_str(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), - RichTextDelta::from_json_str(r#"[{"insert":"a"}]"#).unwrap(), - RichTextDelta::from_json_str(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), - RichTextDelta::from_json_str(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), + RichTextDelta::from_json(r#"[{"retain":1,"attributes":{"list":"unchecked"}}]"#).unwrap(), + RichTextDelta::from_json(r#"[{"insert":"a"}]"#).unwrap(), + RichTextDelta::from_json(r#"[{"retain":1},{"insert":"\n","attributes":{"list":"unchecked"}}]"#).unwrap(), + RichTextDelta::from_json(r#"[{"retain":2},{"retain":1,"attributes":{"list":""}}]"#).unwrap(), ]; for d in deltas { delta = delta.compose(&d).unwrap(); } assert_eq!( - delta.to_json_str(), + delta.json_str(), r#"[{"insert":"a"},{"insert":"\n","attributes":{"list":"unchecked"}},{"insert":"\n"}]"# ); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs index 46442a6336..bbfd1da6f8 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/mod.rs @@ -108,20 +108,20 @@ impl TestBuilder { TestOp::Insert(delta_i, s, index) => { let document = &mut self.documents[*delta_i]; let delta = document.insert(*index, s).unwrap(); - tracing::debug!("Insert delta: {}", delta.to_json_str()); + tracing::debug!("Insert delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Delete(delta_i, iv) => { let document = &mut self.documents[*delta_i]; let delta = document.replace(*iv, "").unwrap(); - tracing::trace!("Delete delta: {}", delta.to_json_str()); + tracing::trace!("Delete delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Replace(delta_i, iv, s) => { let document = &mut self.documents[*delta_i]; let delta = document.replace(*iv, s).unwrap(); - tracing::trace!("Replace delta: {}", delta.to_json_str()); + tracing::trace!("Replace delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::InsertBold(delta_i, s, iv) => { @@ -133,7 +133,7 @@ impl TestBuilder { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Bold(*enable); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Bold delta: {}", delta.to_json_str()); + tracing::trace!("Bold delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Italic(delta_i, iv, enable) => { @@ -143,28 +143,28 @@ impl TestBuilder { false => RichTextAttribute::Italic(false), }; let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Italic delta: {}", delta.to_json_str()); + tracing::trace!("Italic delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Header(delta_i, iv, level) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Header(*level); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Header delta: {}", delta.to_json_str()); + tracing::trace!("Header delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Link(delta_i, iv, link) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Link(link.to_owned()); let delta = document.format(*iv, attribute).unwrap(); - tracing::trace!("Link delta: {}", delta.to_json_str()); + tracing::trace!("Link delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } TestOp::Bullet(delta_i, iv, enable) => { let document = &mut self.documents[*delta_i]; let attribute = RichTextAttribute::Bullet(*enable); let delta = document.format(*iv, attribute).unwrap(); - tracing::debug!("Bullet delta: {}", delta.to_json_str()); + tracing::debug!("Bullet delta: {}", delta.json_str()); self.deltas.insert(*delta_i, Some(delta)); } @@ -194,15 +194,15 @@ impl TestBuilder { let delta_a = &self.documents[*delta_a_i].delta(); let delta_b = &self.documents[*delta_b_i].delta(); tracing::debug!("Invert: "); - tracing::debug!("a: {}", delta_a.to_json_str()); - tracing::debug!("b: {}", delta_b.to_json_str()); + tracing::debug!("a: {}", delta_a.json_str()); + tracing::debug!("b: {}", delta_b.json_str()); let (_, b_prime) = delta_a.transform(delta_b).unwrap(); let undo = b_prime.invert(delta_a); let new_delta = delta_a.compose(&b_prime).unwrap(); - tracing::debug!("new delta: {}", new_delta.to_json_str()); - tracing::debug!("undo delta: {}", undo.to_json_str()); + tracing::debug!("new delta: {}", new_delta.json_str()); + tracing::debug!("undo delta: {}", undo.json_str()); let new_delta_after_undo = new_delta.compose(&undo).unwrap(); @@ -238,7 +238,7 @@ impl TestBuilder { } TestOp::AssertPrimeJson(doc_i, expected) => { - let prime_json = self.primes[*doc_i].as_ref().unwrap().to_json_str(); + let prime_json = self.primes[*doc_i].as_ref().unwrap().json_str(); let expected_prime: RichTextDelta = serde_json::from_str(expected).unwrap(); let target_prime: RichTextDelta = serde_json::from_str(&prime_json).unwrap(); diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs index cbb4fe3e3f..99d3136e55 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/op_test.rs @@ -345,7 +345,7 @@ fn apply_test() { let delta_a = TextDeltaBuilder::new().insert(s).build(); let delta_b = TextDeltaBuilder::new().retain(s.len()).insert(", AppFlowy").build(); - let after_a = delta_a.content_str().unwrap(); + let after_a = delta_a.content().unwrap(); let after_b = delta_b.apply(&after_a).unwrap(); assert_eq!("hello, AppFlowy", &after_b); } diff --git a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs index 469431c478..ac4a77412c 100644 --- a/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs +++ b/frontend/rust-lib/flowy-text-block/tests/editor/serde_test.rs @@ -65,7 +65,7 @@ fn delta_serialize_multi_attribute_test() { let json = serde_json::to_string(&delta).unwrap(); eprintln!("{}", json); - let delta_from_json = Delta::from_json_str(&json).unwrap(); + let delta_from_json = Delta::from_json(&json).unwrap(); assert_eq!(delta_from_json, delta); } @@ -77,7 +77,7 @@ fn delta_deserialize_test() { {"retain":2,"attributes":{"italic":"true","bold":"true"}}, {"retain":2,"attributes":{"italic":true,"bold":true}} ]"#; - let delta = RichTextDelta::from_json_str(json).unwrap(); + let delta = RichTextDelta::from_json(json).unwrap(); eprintln!("{}", delta); } @@ -86,13 +86,13 @@ fn delta_deserialize_null_test() { let json = r#"[ {"retain":7,"attributes":{"bold":null}} ]"#; - let delta1 = RichTextDelta::from_json_str(json).unwrap(); + let delta1 = RichTextDelta::from_json(json).unwrap(); let mut attribute = RichTextAttribute::Bold(true); attribute.value = RichTextAttributeValue(None); let delta2 = DeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); - assert_eq!(delta2.to_json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); + assert_eq!(delta2.json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); assert_eq!(delta1, delta2); } diff --git a/shared-lib/flowy-sync/src/client_document/default/mod.rs b/shared-lib/flowy-sync/src/client_document/default/mod.rs index 582e3eac2e..ee69e9efd9 100644 --- a/shared-lib/flowy-sync/src/client_document/default/mod.rs +++ b/shared-lib/flowy-sync/src/client_document/default/mod.rs @@ -7,13 +7,13 @@ pub fn initial_quill_delta() -> RichTextDelta { #[inline] pub fn initial_quill_delta_string() -> String { - initial_quill_delta().to_json_str() + initial_quill_delta().json_str() } #[inline] pub fn initial_read_me() -> RichTextDelta { let json = include_str!("READ_ME.json"); - RichTextDelta::from_json_str(json).unwrap() + RichTextDelta::from_json(json).unwrap() } #[cfg(test)] @@ -22,6 +22,6 @@ mod tests { #[test] fn load_read_me() { - println!("{}", initial_read_me().to_json_str()); + println!("{}", initial_read_me().json_str()); } } diff --git a/shared-lib/flowy-sync/src/client_document/document_pad.rs b/shared-lib/flowy-sync/src/client_document/document_pad.rs index d63d2194ad..9a1037d0c8 100644 --- a/shared-lib/flowy-sync/src/client_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/client_document/document_pad.rs @@ -55,16 +55,16 @@ impl ClientDocument { } pub fn from_json(json: &str) -> Result { - let delta = RichTextDelta::from_json_str(json)?; + let delta = RichTextDelta::from_json(json)?; Ok(Self::from_delta(delta)) } pub fn delta_str(&self) -> String { - self.delta.to_json_str() + self.delta.json_str() } pub fn to_bytes(&self) -> Bytes { - self.delta.to_json_bytes() + self.delta.json_bytes() } pub fn to_plain_string(&self) -> String { @@ -85,7 +85,7 @@ impl ClientDocument { } pub fn set_delta(&mut self, data: RichTextDelta) { - tracing::trace!("document: {}", data.to_json_str()); + tracing::trace!("document: {}", data.json_str()); self.delta = data; match &self.notify { @@ -97,7 +97,7 @@ impl ClientDocument { } pub fn compose_delta(&mut self, delta: RichTextDelta) -> Result<(), CollaborateError> { - tracing::trace!("{} compose {}", &self.delta.to_json_str(), delta.to_json_str()); + tracing::trace!("{} compose {}", &self.delta.json_str(), delta.json_str()); let composed_delta = self.delta.compose(&delta)?; let mut undo_delta = delta.invert(&self.delta); diff --git a/shared-lib/flowy-sync/src/client_folder/builder.rs b/shared-lib/flowy-sync/src/client_folder/builder.rs index 848b6f5127..3855d62834 100644 --- a/shared-lib/flowy-sync/src/client_folder/builder.rs +++ b/shared-lib/flowy-sync/src/client_folder/builder.rs @@ -41,7 +41,7 @@ impl FolderPadBuilder { } // TODO: Reconvert from history if delta.to_str() failed. - let content = delta.content_str()?; + let content = delta.content()?; let mut folder: FolderPad = serde_json::from_str(&content).map_err(|e| { tracing::error!("Deserialize folder from {} failed", content); return CollaborateError::internal().context(format!("Deserialize delta to folder failed: {}", e)); diff --git a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs index 52d479f6d4..5927be2c34 100644 --- a/shared-lib/flowy-sync/src/client_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/client_folder/folder_pad.rs @@ -295,7 +295,7 @@ impl FolderPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_json_bytes()) + md5(&self.delta.json_bytes()) } pub fn to_json(&self) -> CollaborateResult { diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs index 35fb7743fc..51a331ecf7 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_revsion_pad.rs @@ -46,7 +46,7 @@ impl GridBlockRevisionPad { } pub fn from_delta(delta: GridBlockRevisionDelta) -> CollaborateResult { - let s = delta.content_str()?; + let s = delta.content()?; let block_revision: GridBlockRevision = serde_json::from_str(&s).map_err(|e| { let msg = format!("Deserialize delta to block meta failed: {}", e); tracing::error!("{}", s); @@ -198,7 +198,7 @@ impl GridBlockRevisionPad { match cal_diff::(old, new) { None => Ok(None), Some(delta) => { - tracing::trace!("[GridBlockMeta] Composing delta {}", delta.to_json_str()); + tracing::trace!("[GridBlockMeta] Composing delta {}", delta.json_str()); // tracing::debug!( // "[GridBlockMeta] current delta: {}", // self.delta.to_str().unwrap_or_else(|_| "".to_string()) @@ -231,11 +231,11 @@ impl GridBlockRevisionPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_json_bytes()) + md5(&self.delta.json_bytes()) } pub fn delta_str(&self) -> String { - self.delta.to_json_str() + self.delta.json_str() } } @@ -252,7 +252,7 @@ pub fn make_grid_block_delta(block_rev: &GridBlockRevision) -> GridBlockRevision pub fn make_grid_block_revisions(user_id: &str, grid_block_meta_data: &GridBlockRevision) -> RepeatedRevision { let delta = make_grid_block_delta(grid_block_meta_data); - let bytes = delta.to_json_bytes(); + let bytes = delta.json_bytes(); let revision = Revision::initial_revision(user_id, &grid_block_meta_data.block_id, bytes); revision.into() } @@ -289,7 +289,7 @@ mod tests { let change = pad.add_row_rev(row.clone(), None).unwrap().unwrap(); assert_eq!(pad.rows.first().unwrap().as_ref(), &row); assert_eq!( - change.delta.to_json_str(), + change.delta.json_str(), r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); } @@ -303,19 +303,19 @@ mod tests { let change = pad.add_row_rev(row_1.clone(), None).unwrap().unwrap(); assert_eq!( - change.delta.to_json_str(), + change.delta.json_str(), r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); let change = pad.add_row_rev(row_2.clone(), None).unwrap().unwrap(); assert_eq!( - change.delta.to_json_str(), + change.delta.json_str(), r#"[{"retain":90},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); let change = pad.add_row_rev(row_3.clone(), Some("2".to_string())).unwrap().unwrap(); assert_eq!( - change.delta.to_json_str(), + change.delta.json_str(), r#"[{"retain":157},{"insert":",{\"id\":\"3\",\"block_id\":\"1\",\"cells\":[],\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); @@ -380,10 +380,7 @@ mod tests { let _ = pad.add_row_rev(row.clone(), None).unwrap().unwrap(); let change = pad.delete_rows(vec![Cow::Borrowed(&row.id)]).unwrap().unwrap(); - assert_eq!( - change.delta.to_json_str(), - r#"[{"retain":24},{"delete":66},{"retain":2}]"# - ); + assert_eq!(change.delta.json_str(), r#"[{"retain":24},{"delete":66},{"retain":2}]"#); assert_eq!(pad.delta_str(), pre_delta_str); } @@ -410,7 +407,7 @@ mod tests { let change = pad.update_row(changeset).unwrap().unwrap(); assert_eq!( - change.delta.to_json_str(), + change.delta.json_str(), r#"[{"retain":69},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"# ); @@ -421,8 +418,7 @@ mod tests { } fn test_pad() -> GridBlockRevisionPad { - let delta = - GridBlockRevisionDelta::from_json_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); + let delta = GridBlockRevisionDelta::from_json(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap(); GridBlockRevisionPad::from_delta(delta).unwrap() } } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs index 59ae462e8d..b0188066ef 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_revision_pad.rs @@ -52,7 +52,7 @@ impl GridRevisionPad { } pub fn from_delta(delta: GridRevisionDelta) -> CollaborateResult { - let content = delta.content_str()?; + let content = delta.content()?; let grid: GridRevision = serde_json::from_str(&content) .map_err(|e| CollaborateError::internal().context(format!("Deserialize delta to grid failed: {}", e)))?; @@ -457,15 +457,15 @@ impl GridRevisionPad { } pub fn md5(&self) -> String { - md5(&self.delta.to_json_bytes()) + md5(&self.delta.json_bytes()) } pub fn delta_str(&self) -> String { - self.delta.to_json_str() + self.delta.json_str() } pub fn delta_bytes(&self) -> Bytes { - self.delta.to_json_bytes() + self.delta.json_bytes() } pub fn fields(&self) -> &[Arc] { @@ -553,7 +553,7 @@ pub fn make_grid_delta(grid_rev: &GridRevision) -> GridRevisionDelta { pub fn make_grid_revisions(user_id: &str, grid_rev: &GridRevision) -> RepeatedRevision { let delta = make_grid_delta(grid_rev); - let bytes = delta.to_json_bytes(); + let bytes = delta.json_bytes(); let revision = Revision::initial_revision(user_id, &grid_rev.grid_id, bytes); revision.into() } diff --git a/shared-lib/flowy-sync/src/entities/revision.rs b/shared-lib/flowy-sync/src/entities/revision.rs index 408026607c..55567a43bf 100644 --- a/shared-lib/flowy-sync/src/entities/revision.rs +++ b/shared-lib/flowy-sync/src/entities/revision.rs @@ -89,7 +89,7 @@ impl std::fmt::Debug for Revision { let _ = f.write_fmt(format_args!("rev_id {}, ", self.rev_id))?; match RichTextDelta::from_bytes(&self.delta_data) { Ok(delta) => { - let _ = f.write_fmt(format_args!("delta {:?}", delta.to_json_str()))?; + let _ = f.write_fmt(format_args!("delta {:?}", delta.json_str()))?; } Err(e) => { let _ = f.write_fmt(format_args!("delta {:?}", e))?; diff --git a/shared-lib/flowy-sync/src/entities/text_block.rs b/shared-lib/flowy-sync/src/entities/text_block.rs index 91ff7e65c4..7cb8c6df63 100644 --- a/shared-lib/flowy-sync/src/entities/text_block.rs +++ b/shared-lib/flowy-sync/src/entities/text_block.rs @@ -46,7 +46,7 @@ impl std::convert::TryFrom for DocumentPB { } let delta = RichTextDelta::from_bytes(&revision.delta_data)?; - let doc_json = delta.to_json_str(); + let doc_json = delta.json_str(); Ok(DocumentPB { block_id: revision.object_id, diff --git a/shared-lib/flowy-sync/src/server_document/document_pad.rs b/shared-lib/flowy-sync/src/server_document/document_pad.rs index d51919f048..28623a0169 100644 --- a/shared-lib/flowy-sync/src/server_document/document_pad.rs +++ b/shared-lib/flowy-sync/src/server_document/document_pad.rs @@ -39,7 +39,7 @@ impl RevisionSyncObject for ServerDocument { } fn to_json(&self) -> String { - self.delta.to_json_str() + self.delta.json_str() } fn set_delta(&mut self, new_delta: Delta) { diff --git a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs index 6cb942001b..74e164600c 100644 --- a/shared-lib/flowy-sync/src/server_folder/folder_pad.rs +++ b/shared-lib/flowy-sync/src/server_folder/folder_pad.rs @@ -32,7 +32,7 @@ impl RevisionSyncObject for ServerFolder { } fn to_json(&self) -> String { - self.delta.to_json_str() + self.delta.json_str() } fn set_delta(&mut self, new_delta: TextDelta) { diff --git a/shared-lib/flowy-sync/src/util.rs b/shared-lib/flowy-sync/src/util.rs index 9c0ab822c8..7dd5c4af5c 100644 --- a/shared-lib/flowy-sync/src/util.rs +++ b/shared-lib/flowy-sync/src/util.rs @@ -149,7 +149,7 @@ pub fn make_folder_from_revisions_pb( folder_delta = folder_delta.compose(&delta)?; } - let text = folder_delta.to_json_str(); + let text = folder_delta.json_str(); Ok(Some(FolderInfo { folder_id: folder_id.to_string(), text, @@ -183,7 +183,7 @@ pub fn make_document_from_revision_pbs( delta = delta.compose(&new_delta)?; } - let text = delta.to_json_str(); + let text = delta.json_str(); Ok(Some(DocumentPB { block_id: doc_id.to_owned(), diff --git a/shared-lib/lib-ot/src/core/delta/builder.rs b/shared-lib/lib-ot/src/core/delta/builder.rs index ee21ecd8ca..482b1ca8a9 100644 --- a/shared-lib/lib-ot/src/core/delta/builder.rs +++ b/shared-lib/lib-ot/src/core/delta/builder.rs @@ -14,7 +14,7 @@ use crate::core::Operation; /// let delta = TextDeltaBuilder::new() /// .insert("AppFlowy") /// .build(); -/// assert_eq!(delta.content_str().unwrap(), "AppFlowy"); +/// assert_eq!(delta.content().unwrap(), "AppFlowy"); /// ``` pub struct DeltaBuilder { delta: Delta, @@ -55,7 +55,7 @@ where /// let mut attribute = RichTextAttribute::Bold(true); /// let delta = RichTextDeltaBuilder::new().retain_with_attributes(7, attribute.into()).build(); /// - /// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#); + /// assert_eq!(delta.json_str(), r#"[{"retain":7,"attributes":{"bold":true}}]"#); /// ``` pub fn retain_with_attributes(mut self, n: usize, attrs: T) -> Self { self.delta.retain(n, attrs); @@ -84,7 +84,7 @@ where /// .build(); /// /// let new_delta = delta.compose(&changeset).unwrap(); - /// assert_eq!(new_delta.content_str().unwrap(), "AppFlowy"); + /// assert_eq!(new_delta.content().unwrap(), "AppFlowy"); /// ``` pub fn delete(mut self, n: usize) -> Self { self.delta.delete(n); diff --git a/shared-lib/lib-ot/src/core/delta/delta.rs b/shared-lib/lib-ot/src/core/delta/delta.rs index 86eb664921..b422205a90 100644 --- a/shared-lib/lib-ot/src/core/delta/delta.rs +++ b/shared-lib/lib-ot/src/core/delta/delta.rs @@ -188,7 +188,7 @@ where /// .insert(", AppFlowy") /// .build(); /// - /// let after_a = delta_a.content_str().unwrap(); + /// let after_a = delta_a.content().unwrap(); /// let after_b = delta_b.apply(&after_a).unwrap(); /// assert_eq!("hello, AppFlowy", &after_b); /// ``` @@ -559,7 +559,7 @@ fn transform_op_attribute( } let left = left.as_ref().unwrap().get_attributes(); let right = right.as_ref().unwrap().get_attributes(); - // TODO: replace with anyhow and thiserror. + // TODO: replace with anyhow and this error. Ok(left.transform(&right)?.0) } @@ -575,10 +575,10 @@ where /// let json = r#"[ /// {"retain":7,"attributes":{"bold":null}} /// ]"#; - /// let delta = RichTextDelta::from_json_str(json).unwrap(); - /// assert_eq!(delta.to_json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); + /// let delta = RichTextDelta::from_json(json).unwrap(); + /// assert_eq!(delta.json_str(), r#"[{"retain":7,"attributes":{"bold":""}}]"#); /// ``` - pub fn from_json_str(json: &str) -> Result { + pub fn from_json(json: &str) -> Result { let delta = serde_json::from_str(json).map_err(|e| { tracing::trace!("Deserialize failed: {:?}", e); tracing::trace!("{:?}", json); @@ -587,9 +587,10 @@ where Ok(delta) } + /// Deserialize the bytes into [Delta]. It requires the bytes is in utf8 format. pub fn from_bytes>(bytes: B) -> Result { let json = str::from_utf8(bytes.as_ref())?.to_owned(); - let val = Self::from_json_str(&json)?; + let val = Self::from_json(&json)?; Ok(val) } } @@ -598,16 +599,19 @@ impl Delta where T: Attributes + serde::Serialize, { - pub fn to_json_str(&self) -> String { + /// Serialize the [Delta] into a String in JSON format + pub fn json_str(&self) -> String { serde_json::to_string(self).unwrap_or_else(|_| "".to_owned()) } - pub fn content_str(&self) -> Result { + /// Get the content the [Delta] represents. + pub fn content(&self) -> Result { self.apply("") } - pub fn to_json_bytes(&self) -> Bytes { - let json = self.to_json_str(); + /// Serial the [Delta] into a String in Bytes format + pub fn json_bytes(&self) -> Bytes { + let json = self.json_str(); Bytes::from(json.into_bytes()) } } diff --git a/shared-lib/lib-ot/src/core/operation/operation.rs b/shared-lib/lib-ot/src/core/operation/operation.rs index 040c459b97..4bacd1ea7d 100644 --- a/shared-lib/lib-ot/src/core/operation/operation.rs +++ b/shared-lib/lib-ot/src/core/operation/operation.rs @@ -25,7 +25,7 @@ pub trait OperationTransform { /// let document = TextDeltaBuilder::new().build(); /// let delta = TextDeltaBuilder::new().insert("abc").build(); /// let new_document = document.compose(&delta).unwrap(); - /// assert_eq!(new_document.content_str().unwrap(), "abc".to_owned()); + /// assert_eq!(new_document.content().unwrap(), "abc".to_owned()); /// ``` fn compose(&self, other: &Self) -> Result where From 386ee15f1b0efbed755b3039717f61d6095b6ffe Mon Sep 17 00:00:00 2001 From: weidong fu Date: Tue, 2 Aug 2022 14:06:07 +0800 Subject: [PATCH 111/112] chore: fix install script errors --- frontend/scripts/install_dev_env/install_macos.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/scripts/install_dev_env/install_macos.sh b/frontend/scripts/install_dev_env/install_macos.sh index 1e746d954d..f7e9d73909 100755 --- a/frontend/scripts/install_dev_env/install_macos.sh +++ b/frontend/scripts/install_dev_env/install_macos.sh @@ -22,12 +22,14 @@ printError() { printMessage "The Rust programming language is required to compile AppFlowy." printMessage "We can install it now if you don't already have it on your system." -read -p "$(printSuccess "Do you want to install Rust? [y/N]") " installrust +read -p "$(printSuccess "Do you want to install Rust? [Y/N]") " installrust -if [ ${installrust^^} == "Y" ]; then +if [ ${installrust} == "Y" ] || [ ${installrust} == "y" ]; then printMessage "Installing Rust." brew install rustup-init rustup-init -y --default-toolchain=stable + + source "$HOME/.cargo/env" else printMessage "Skipping Rust installation." fi From dc636a6e05712d43039c0545a1618f6e3a22882a Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 3 Aug 2022 08:14:09 +0800 Subject: [PATCH 112/112] chore: add codec to lib-ot --- shared-lib/lib-ot/src/codec/markdown/mod.rs | 0 shared-lib/lib-ot/src/codec/mod.rs | 1 + shared-lib/lib-ot/src/lib.rs | 1 + 3 files changed, 2 insertions(+) create mode 100644 shared-lib/lib-ot/src/codec/markdown/mod.rs create mode 100644 shared-lib/lib-ot/src/codec/mod.rs diff --git a/shared-lib/lib-ot/src/codec/markdown/mod.rs b/shared-lib/lib-ot/src/codec/markdown/mod.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/shared-lib/lib-ot/src/codec/mod.rs b/shared-lib/lib-ot/src/codec/mod.rs new file mode 100644 index 0000000000..163a4fba82 --- /dev/null +++ b/shared-lib/lib-ot/src/codec/mod.rs @@ -0,0 +1 @@ +pub mod markdown; diff --git a/shared-lib/lib-ot/src/lib.rs b/shared-lib/lib-ot/src/lib.rs index 5a3be0ede7..93e2e8857c 100644 --- a/shared-lib/lib-ot/src/lib.rs +++ b/shared-lib/lib-ot/src/lib.rs @@ -1,3 +1,4 @@ pub mod core; pub mod errors; +pub mod parser; pub mod rich_text;