소스 검색

refactor: move row params

appflowy 2 년 전
부모
커밋
f32068d64b

+ 10 - 5
frontend/app_flowy/lib/plugins/board/application/board_bloc.dart

@@ -21,7 +21,7 @@ part 'board_bloc.freezed.dart';
 class BoardBloc extends Bloc<BoardEvent, BoardState> {
   final BoardDataController _dataController;
   late final AFBoardDataController afBoardDataController;
-  List<GroupController> groupControllers = [];
+  Map<String, GroupController> groupControllers = {};
 
   GridFieldCache get fieldCache => _dataController.fieldCache;
   String get gridId => _dataController.gridId;
@@ -38,13 +38,17 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
         columnId,
         fromIndex,
         toIndex,
-      ) {},
+      ) {
+        groupControllers[columnId]?.moveRow(fromIndex, toIndex);
+      },
       onMoveColumnItemToColumn: (
         fromColumnId,
         fromIndex,
         toColumnId,
         toIndex,
-      ) {},
+      ) {
+        //
+      },
     );
 
     on<BoardEvent>(
@@ -84,7 +88,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
   @override
   Future<void> close() async {
     await _dataController.dispose();
-    for (final controller in groupControllers) {
+    for (final controller in groupControllers.values) {
       controller.dispose();
     }
     return super.close();
@@ -94,11 +98,12 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
     for (final group in groups) {
       final delegate = GroupControllerDelegateImpl(afBoardDataController);
       final controller = GroupController(
+        gridId: state.gridId,
         group: group,
         delegate: delegate,
       );
       controller.startListening();
-      groupControllers.add(controller);
+      groupControllers[controller.group.groupId] = (controller);
     }
   }
 

+ 31 - 3
frontend/app_flowy/lib/plugins/board/application/group_controller.dart

@@ -1,8 +1,12 @@
+import 'package:app_flowy/plugins/grid/application/row/row_service.dart';
 import 'package:flowy_sdk/log.dart';
+import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
 
 import 'group_listener.dart';
 
+typedef OnGroupError = void Function(FlowyError);
+
 abstract class GroupControllerDelegate {
   void removeRow(String groupId, String rowId);
   void insertRow(String groupId, RowPB row, int? index);
@@ -12,12 +16,36 @@ abstract class GroupControllerDelegate {
 class GroupController {
   final GroupPB group;
   final GroupListener _listener;
+  final MoveRowFFIService _rowService;
   final GroupControllerDelegate delegate;
+  OnGroupError? _onError;
+
+  GroupController({
+    required String gridId,
+    required this.group,
+    required this.delegate,
+  })  : _rowService = MoveRowFFIService(gridId: gridId),
+        _listener = GroupListener(group);
+
+  Future<void> moveRow(int fromIndex, int toIndex) async {
+    if (fromIndex < group.rows.length && toIndex < group.rows.length) {
+      final fromRow = group.rows[fromIndex];
+      final toRow = group.rows[toIndex];
 
-  GroupController({required this.group, required this.delegate})
-      : _listener = GroupListener(group);
+      final result = await _rowService.moveRow(
+        rowId: fromRow.id,
+        fromIndex: fromIndex,
+        toIndex: toIndex,
+        upperRowId: toRow.id,
+        layout: GridLayout.Board,
+      );
+
+      result.fold((l) => null, (r) => _onError?.call(r));
+    }
+  }
 
-  void startListening() {
+  void startListening({OnGroupError? onError}) {
+    _onError = onError;
     _listener.start(onGroupChanged: (result) {
       result.fold(
         (GroupRowsChangesetPB changeset) {

+ 29 - 0
frontend/app_flowy/lib/plugins/grid/application/row/row_service.dart

@@ -71,3 +71,32 @@ class RowFFIService {
     return GridEventDuplicateRow(payload).send();
   }
 }
+
+class MoveRowFFIService {
+  final String gridId;
+
+  MoveRowFFIService({
+    required this.gridId,
+  });
+
+  Future<Either<Unit, FlowyError>> moveRow({
+    required String rowId,
+    required int fromIndex,
+    required int toIndex,
+    required GridLayout layout,
+    String? upperRowId,
+  }) {
+    var payload = MoveRowPayloadPB.create()
+      ..viewId = gridId
+      ..rowId = rowId
+      ..layout = layout
+      ..fromIndex = fromIndex
+      ..toIndex = toIndex;
+
+    if (upperRowId != null) {
+      payload.upperRowId = upperRowId;
+    }
+
+    return GridEventMoveRow(payload).send();
+  }
+}

+ 19 - 19
frontend/rust-lib/flowy-grid/src/entities/grid_entities.rs

@@ -96,28 +96,27 @@ pub struct MoveRowPayloadPB {
     pub view_id: String,
 
     #[pb(index = 2)]
-    pub row_id: String,
-
-    #[pb(index = 3)]
-    pub from_index: i32,
-
-    #[pb(index = 4)]
-    pub to_index: i32,
+    pub from_row_id: String,
 
+    // #[pb(index = 3)]
+    // pub from_index: i32,
+    //
+    // #[pb(index = 4)]
+    // pub to_index: i32,
     #[pb(index = 5)]
     pub layout: GridLayout,
 
-    #[pb(index = 6, one_of)]
-    pub upper_row_id: Option<String>,
+    #[pb(index = 6)]
+    pub to_row_id: String,
 }
 
 pub struct MoveRowParams {
     pub view_id: String,
-    pub row_id: String,
-    pub from_index: i32,
-    pub to_index: i32,
+    pub from_row_id: String,
+    // pub from_index: i32,
+    // pub to_index: i32,
     pub layout: GridLayout,
-    pub upper_row_id: Option<String>,
+    pub to_row_id: String,
 }
 
 impl TryInto<MoveRowParams> for MoveRowPayloadPB {
@@ -125,18 +124,19 @@ impl TryInto<MoveRowParams> for MoveRowPayloadPB {
 
     fn try_into(self) -> Result<MoveRowParams, Self::Error> {
         let view_id = NotEmptyStr::parse(self.view_id).map_err(|_| ErrorCode::GridViewIdIsEmpty)?;
-        let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
-        let upper_row_id = match self.upper_row_id {
+        let from_row_id = NotEmptyStr::parse(self.from_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
+        let to_row_id = NotEmptyStr::parse(self.to_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
+        let upper_row_id = match self.to_row_id {
             None => None,
             Some(upper_row_id) => Some(NotEmptyStr::parse(upper_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?.0),
         };
         Ok(MoveRowParams {
             view_id: view_id.0,
-            row_id: row_id.0,
-            from_index: self.from_index,
-            to_index: self.to_index,
+            from_row_id: from_row_id.0,
+            // from_index: self.from_index,
+            // to_index: self.to_index,
             layout: self.layout,
-            upper_row_id,
+            to_row_id: upper_row_id,
         })
     }
 }

+ 9 - 0
frontend/rust-lib/flowy-grid/src/entities/group_entities/group_changeset.rs

@@ -1,5 +1,6 @@
 use crate::entities::{InsertedRowPB, RowPB};
 use flowy_derive::ProtoBuf;
+use std::fmt::Formatter;
 
 #[derive(Debug, Default, ProtoBuf)]
 pub struct GroupRowsChangesetPB {
@@ -16,6 +17,14 @@ pub struct GroupRowsChangesetPB {
     pub updated_rows: Vec<RowPB>,
 }
 
+impl std::fmt::Display for GroupRowsChangesetPB {
+    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+        let _ = f.write_fmt(format_args!("Group:{}", self.group_id))?;
+        let _ = f.write_fmt(format_args!("Insert:{:?}", self.inserted_rows))?;
+        f.write_fmt(format_args!("Delete:{:?}", self.deleted_rows))
+    }
+}
+
 impl GroupRowsChangesetPB {
     pub fn is_empty(&self) -> bool {
         self.inserted_rows.is_empty() && self.deleted_rows.is_empty() && self.updated_rows.is_empty()

+ 1 - 8
frontend/rust-lib/flowy-grid/src/services/block_manager_trait_impl.rs

@@ -1,5 +1,5 @@
 use crate::services::block_manager::GridBlockManager;
-use crate::services::grid_view_manager::{GridViewRowDelegate, GridViewRowOperation};
+use crate::services::grid_view_manager::GridViewRowDelegate;
 use flowy_error::FlowyResult;
 use flowy_grid_data_model::revision::RowRevision;
 use lib_infra::future::{wrap_future, AFFuture};
@@ -36,10 +36,3 @@ impl GridViewRowDelegate for Arc<GridBlockManager> {
         })
     }
 }
-
-impl GridViewRowOperation for Arc<GridBlockManager> {
-    fn gv_move_row(&self, row_rev: Arc<RowRevision>, from: usize, to: usize) -> AFFuture<FlowyResult<()>> {
-        let block_manager = self.clone();
-        wrap_future(async move { block_manager.move_row(row_rev, from, to).await })
-    }
-}

+ 36 - 2
frontend/rust-lib/flowy-grid/src/services/grid_editor.rs

@@ -72,7 +72,6 @@ impl GridRevisionEditor {
                 user.clone(),
                 Arc::new(grid_pad.clone()),
                 Arc::new(block_manager.clone()),
-                Arc::new(block_manager.clone()),
                 Arc::new(task_scheduler.clone()),
             )
             .await?,
@@ -494,7 +493,42 @@ impl GridRevisionEditor {
     }
 
     pub async fn move_row(&self, params: MoveRowParams) -> FlowyResult<()> {
-        self.view_manager.move_row(params).await
+        let MoveRowParams {
+            view_id: _,
+            from_row_id: row_id,
+            from_index,
+            to_index,
+            layout: _,
+            to_row_id: upper_row_id,
+        } = params;
+
+        let from_index = from_index as usize;
+        let to_index = to_index as usize;
+
+        match self.block_manager.get_row_rev(&row_id).await? {
+            None => tracing::warn!("Move row failed, can not find the row:{}", row_id),
+            Some(row_rev) => match upper_row_id {
+                None => {
+                    tracing::trace!("Move row from {} to {}", from_index, to_index);
+                    let _ = self
+                        .block_manager
+                        .move_row(row_rev.clone(), from_index, to_index)
+                        .await?;
+                }
+                Some(to_row_id) => match self.block_manager.index_of_row(&to_row_id).await {
+                    None => tracing::error!("Can not find the row: {} when moving the row", to_row_id),
+                    Some(to_row_index) => {
+                        tracing::trace!("Move row from {} to {}", from_index, to_row_index);
+                        let _ = self
+                            .block_manager
+                            .move_row(row_rev.clone(), from_index, to_row_index)
+                            .await?;
+                        self.view_manager.move_row(row_rev, to_row_id).await;
+                    }
+                },
+            },
+        }
+        Ok(())
     }
 
     pub async fn move_field(&self, params: MoveFieldParams) -> FlowyResult<()> {

+ 16 - 11
frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs

@@ -118,17 +118,22 @@ impl GridViewRevisionEditor {
         }
     }
 
-    // async fn get_mut_group<F>(&self, group_id: &str, f: F) -> FlowyResult<()>
-    // where
-    //     F: Fn(&mut Group) -> FlowyResult<()>,
-    // {
-    //     for group in self.groups.write().await.iter_mut() {
-    //         if group.id == group_id {
-    //             let _ = f(group)?;
-    //         }
-    //     }
-    //     Ok(())
-    // }
+    pub(crate) async fn did_move_row(&self, row_rev: &RowRevision, upper_row_id: &str) {
+        if let Some(changesets) = self
+            .group_service
+            .write()
+            .await
+            .did_move_row(row_rev, upper_row_id, |field_id| {
+                self.field_delegate.get_field_rev(&field_id)
+            })
+            .await
+        {
+            for changeset in changesets {
+                tracing::trace!("Group changeset: {}", changeset);
+                self.notify_did_update_group(changeset).await;
+            }
+        }
+    }
 
     pub(crate) async fn load_groups(&self) -> FlowyResult<Vec<GroupPB>> {
         let field_revs = self.field_delegate.get_field_revs().await;

+ 3 - 38
frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs

@@ -31,17 +31,11 @@ pub trait GridViewRowDelegate: Send + Sync + 'static {
     fn gv_row_revs(&self) -> AFFuture<Vec<Arc<RowRevision>>>;
 }
 
-pub trait GridViewRowOperation: Send + Sync + 'static {
-    // Will be removed in the future.
-    fn gv_move_row(&self, row_rev: Arc<RowRevision>, from: usize, to: usize) -> AFFuture<FlowyResult<()>>;
-}
-
 pub(crate) struct GridViewManager {
     grid_id: String,
     user: Arc<dyn GridUser>,
     field_delegate: Arc<dyn GridViewFieldDelegate>,
     row_delegate: Arc<dyn GridViewRowDelegate>,
-    row_operation: Arc<dyn GridViewRowOperation>,
     view_editors: DashMap<ViewId, Arc<GridViewRevisionEditor>>,
     scheduler: Arc<dyn GridServiceTaskScheduler>,
 }
@@ -52,7 +46,6 @@ impl GridViewManager {
         user: Arc<dyn GridUser>,
         field_delegate: Arc<dyn GridViewFieldDelegate>,
         row_delegate: Arc<dyn GridViewRowDelegate>,
-        row_operation: Arc<dyn GridViewRowOperation>,
         scheduler: Arc<dyn GridServiceTaskScheduler>,
     ) -> FlowyResult<Self> {
         Ok(Self {
@@ -61,7 +54,6 @@ impl GridViewManager {
             scheduler,
             field_delegate,
             row_delegate,
-            row_operation,
             view_editors: DashMap::default(),
         })
     }
@@ -119,37 +111,10 @@ impl GridViewManager {
         Ok(RepeatedGridGroupPB { items: groups })
     }
 
-    pub(crate) async fn move_row(&self, params: MoveRowParams) -> FlowyResult<()> {
-        let MoveRowParams {
-            view_id: _,
-            row_id,
-            from_index,
-            to_index,
-            layout,
-            upper_row_id,
-        } = params;
-
-        let from_index = from_index as usize;
-
-        match self.row_delegate.gv_get_row_rev(&row_id).await {
-            None => tracing::warn!("Move row failed, can not find the row:{}", row_id),
-            Some(row_rev) => match layout {
-                GridLayout::Table => {
-                    tracing::trace!("Move row from {} to {}", from_index, to_index);
-                    let to_index = to_index as usize;
-                    let _ = self.row_operation.gv_move_row(row_rev, from_index, to_index).await?;
-                }
-                GridLayout::Board => {
-                    if let Some(upper_row_id) = upper_row_id {
-                        if let Some(to_index) = self.row_delegate.gv_index_of_row(&upper_row_id).await {
-                            tracing::trace!("Move row from {} to {}", from_index, to_index);
-                            let _ = self.row_operation.gv_move_row(row_rev, from_index, to_index).await?;
-                        }
-                    }
-                }
-            },
+    pub(crate) async fn move_row(&self, row_rev: Arc<RowRevision>, to_row_id: String) {
+        for view_editor in self.view_editors.iter() {
+            view_editor.did_move_row(&row_rev, &to_row_id).await;
         }
-        Ok(())
     }
 
     pub(crate) async fn get_view_editor(&self, view_id: &str) -> FlowyResult<Arc<GridViewRevisionEditor>> {

+ 1 - 0
frontend/rust-lib/flowy-grid/src/services/group/group_generator/checkbox_group.rs

@@ -39,6 +39,7 @@ impl Groupable for CheckboxGroupController {
         &mut self,
         row_rev: &RowRevision,
         cell_data: &Self::CellDataType,
+        to_row_id: &str,
     ) -> Vec<GroupRowsChangesetPB> {
         todo!()
     }

+ 40 - 2
frontend/rust-lib/flowy-grid/src/services/group/group_generator/group_controller.rs

@@ -29,8 +29,12 @@ pub trait Groupable: Send + Sync {
         cell_data: &Self::CellDataType,
     ) -> Vec<GroupRowsChangesetPB>;
 
-    fn move_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType)
-        -> Vec<GroupRowsChangesetPB>;
+    fn move_row_if_match(
+        &mut self,
+        row_rev: &RowRevision,
+        cell_data: &Self::CellDataType,
+        to_row_id: &str,
+    ) -> Vec<GroupRowsChangesetPB>;
 }
 
 pub trait GroupController: GroupControllerSharedAction + Send + Sync {
@@ -53,6 +57,13 @@ pub trait GroupControllerSharedAction: Send + Sync {
         row_rev: &RowRevision,
         field_rev: &FieldRevision,
     ) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
+
+    fn did_move_row(
+        &mut self,
+        row_rev: &RowRevision,
+        field_rev: &FieldRevision,
+        to_row_id: &str,
+    ) -> FlowyResult<Vec<GroupRowsChangesetPB>>;
 }
 
 const DEFAULT_GROUP_ID: &str = "default_group";
@@ -120,6 +131,18 @@ impl Group {
             Some(_) => {}
         }
     }
+
+    pub fn insert_row(&mut self, index: usize, row_pb: RowPB) {
+        if index < self.rows.len() {
+            self.rows.insert(index, row_pb);
+        } else {
+            tracing::error!("Insert row index:{} beyond the bounds:{},", index, self.rows.len());
+        }
+    }
+
+    pub fn index_of_row(&self, row_id: &str) -> Option<usize> {
+        self.rows.iter().position(|row| row.id == row_id)
+    }
 }
 
 impl<C, T, G, P> GenericGroupController<C, T, G, P>
@@ -236,6 +259,21 @@ where
             Ok(vec![])
         }
     }
+
+    fn did_move_row(
+        &mut self,
+        row_rev: &RowRevision,
+        field_rev: &FieldRevision,
+        to_row_id: &str,
+    ) -> FlowyResult<Vec<GroupRowsChangesetPB>> {
+        if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
+            let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
+            let cell_data = cell_bytes.parser::<P>()?;
+            Ok(self.move_row_if_match(row_rev, &cell_data, to_row_id))
+        } else {
+            Ok(vec![])
+        }
+    }
 }
 
 // impl<C, T, G, P> GroupController<C, T, G, P>

+ 39 - 8
frontend/rust-lib/flowy-grid/src/services/group/group_generator/select_option_group.rs

@@ -45,8 +45,13 @@ impl Groupable for SingleSelectGroupController {
         &mut self,
         row_rev: &RowRevision,
         cell_data: &Self::CellDataType,
+        to_row_id: &str,
     ) -> Vec<GroupRowsChangesetPB> {
-        todo!()
+        let mut changesets = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            move_row(group, &mut changesets, cell_data, row_rev, to_row_id);
+        });
+        changesets
     }
 }
 
@@ -100,7 +105,6 @@ impl Groupable for MultiSelectGroupController {
 
     fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupRowsChangesetPB> {
         let mut changesets = vec![];
-
         self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
             add_row(group, &mut changesets, cell_data, row_rev);
         });
@@ -123,8 +127,13 @@ impl Groupable for MultiSelectGroupController {
         &mut self,
         row_rev: &RowRevision,
         cell_data: &Self::CellDataType,
+        to_row_id: &str,
     ) -> Vec<GroupRowsChangesetPB> {
-        todo!()
+        let mut changesets = vec![];
+        self.groups_map.iter_mut().for_each(|(_, group): (_, &mut Group)| {
+            move_row(group, &mut changesets, cell_data, row_rev, to_row_id);
+        });
+        changesets
     }
 }
 
@@ -178,11 +187,6 @@ fn add_row(
                 group.add_row(row_pb);
             }
         }
-
-        // else if group.contains_row(&row_rev.id) {
-        //     group.remove_row(&row_rev.id);
-        //     changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
-        // }
     });
 }
 
@@ -201,3 +205,30 @@ fn remove_row(
         }
     });
 }
+
+fn move_row(
+    group: &mut Group,
+    changesets: &mut Vec<GroupRowsChangesetPB>,
+    cell_data: &SelectOptionCellDataPB,
+    row_rev: &RowRevision,
+    upper_row_id: &str,
+) {
+    cell_data.select_options.iter().for_each(|option| {
+        if option.id == group.id {
+            if group.contains_row(&row_rev.id) {
+                changesets.push(GroupRowsChangesetPB::delete(group.id.clone(), vec![row_rev.id.clone()]));
+                group.remove_row(&row_rev.id);
+            }
+        }
+
+        if let Some(index) = group.index_of_row(upper_row_id) {
+            let row_pb = RowPB::from(row_rev);
+            let inserted_row = InsertedRowPB {
+                row: row_pb.clone(),
+                index: Some(index as i32),
+            };
+            changesets.push(GroupRowsChangesetPB::insert(group.id.clone(), vec![inserted_row]));
+            group.insert_row(index, row_pb);
+        }
+    });
+}

+ 28 - 1
frontend/rust-lib/flowy-grid/src/services/group/group_service.rs

@@ -87,7 +87,34 @@ impl GroupService {
         match group_controller.write().await.did_delete_row(row_rev, &field_rev) {
             Ok(changesets) => Some(changesets),
             Err(e) => {
-                tracing::error!("Update group data failed, {:?}", e);
+                tracing::error!("Delete group data failed, {:?}", e);
+                None
+            }
+        }
+    }
+
+    pub(crate) async fn did_move_row<F, O>(
+        &self,
+        row_rev: &RowRevision,
+        upper_row_id: &str,
+        get_field_fn: F,
+    ) -> Option<Vec<GroupRowsChangesetPB>>
+    where
+        F: FnOnce(String) -> O,
+        O: Future<Output = Option<Arc<FieldRevision>>> + Send + Sync + 'static,
+    {
+        let group_controller = self.group_controller.as_ref()?;
+        let field_id = group_controller.read().await.field_id().to_owned();
+        let field_rev = get_field_fn(field_id).await?;
+
+        match group_controller
+            .write()
+            .await
+            .did_move_row(row_rev, &field_rev, upper_row_id)
+        {
+            Ok(changesets) => Some(changesets),
+            Err(e) => {
+                tracing::error!("Move group data failed, {:?}", e);
                 None
             }
         }

+ 6 - 2
shared-lib/flowy-sync/src/client_grid/block_revision_pad.rs

@@ -178,8 +178,12 @@ impl GridBlockRevisionPad {
             if let Some(position) = row_revs.iter().position(|row_rev| row_rev.id == row_id) {
                 debug_assert_eq!(from, position);
                 let row_rev = row_revs.remove(position);
-                row_revs.insert(to, row_rev);
-                Ok(Some(()))
+                if to > row_revs.len() {
+                    return Err(CollaborateError::out_of_bound());
+                } else {
+                    row_revs.insert(to, row_rev);
+                    Ok(Some(()))
+                }
             } else {
                 Ok(None)
             }