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 e1bed697c8..c909bf1b31 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 @@ -29,6 +29,17 @@ class FieldService { return GridEventGetEditFieldContext(payload).send(); } + Future> moveField(String fieldId, int fromIndex, int toIndex) { + final payload = MoveItemPayload.create() + ..gridId = gridId + ..itemId = fieldId + ..ty = MoveItemType.MoveField + ..fromIndex = fromIndex + ..toIndex = toIndex; + + return GridEventMoveItem(payload).send(); + } + Future> updateField({ required String fieldId, String? name, 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 8ea390d7ab..08cd01e316 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 @@ -1,4 +1,5 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -25,7 +26,10 @@ class GridHeaderBloc extends Bloc { didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { emit(state.copyWith(fields: value.fields)); }, - moveField: (_MoveField value) {}, + moveField: (_MoveField value) async { + final result = await _fieldService.moveField(value.field.id, value.fromIndex, value.toIndex); + result.fold((l) {}, (err) => Log.error(err)); + }, ); }, ); @@ -49,7 +53,7 @@ class GridHeaderBloc extends Bloc { class GridHeaderEvent with _$GridHeaderEvent { const factory GridHeaderEvent.initial() = _InitialHeader; const factory GridHeaderEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; - const factory GridHeaderEvent.moveField(int fromIndex, int toIndex) = _MoveField; + const factory GridHeaderEvent.moveField(Field field, int fromIndex, int toIndex) = _MoveField; } @freezed 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 340f7c7026..127a39d024 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 @@ -75,6 +75,13 @@ class FlowyGrid extends StatefulWidget { class _FlowyGridState extends State { final _scrollController = GridScrollController(scrollGroupContorller: LinkedScrollControllerGroup()); + late ScrollController headerScrollController; + + @override + void initState() { + headerScrollController = _scrollController.linkHorizontalController(); + super.initState(); + } @override void dispose() { @@ -96,11 +103,14 @@ class _FlowyGridState extends State { ], ); - return Column(children: [ - const _GridToolbarAdaptor(), - _gridHeader(context, state.gridId, contentWidth), - Flexible(child: child), - ]); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const _GridToolbarAdaptor(), + _gridHeader(context, state.gridId, contentWidth), + Flexible(child: child), + ], + ); }, ); } @@ -145,7 +155,7 @@ class _FlowyGridState extends State { child: GridHeaderSliverAdaptor( gridId: gridId, fieldCache: fieldCache, - anchorScrollController: _scrollController.linkHorizontalController(), + anchorScrollController: headerScrollController, ), ); } 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 2ac5e5f673..95abccc830 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 @@ -110,7 +110,7 @@ class _GridHeaderState extends State<_GridHeader> { header: const _CellLeading(), footer: _CellTrailing(gridId: widget.gridId), onReorder: (int oldIndex, int newIndex) { - Log.info("from $oldIndex to $newIndex"); + _onReorder(cells, oldIndex, context, newIndex); }, children: cells, ), @@ -119,6 +119,13 @@ class _GridHeaderState extends State<_GridHeader> { }, ); } + + void _onReorder(List cells, int oldIndex, BuildContext context, int newIndex) { + if (cells.length > oldIndex) { + final field = cells[oldIndex].cellContext.field; + context.read().add(GridHeaderEvent.moveField(field, oldIndex, newIndex)); + } + } } class _CellLeading extends StatelessWidget { 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 41a70d8549..e348d105d1 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -385,16 +385,30 @@ impl ClientGridEditor { pub async fn move_item(&self, params: MoveItemParams) -> FlowyResult<()> { match params.ty { MoveItemType::MoveField => { - self.move_field(params.from_index, params.to_index, ¶ms.item_id) + self.move_field(¶ms.item_id, params.from_index, params.to_index) .await } MoveItemType::MoveRow => self.move_row(params.from_index, params.to_index, ¶ms.item_id).await, } } - pub async fn move_field(&self, from: i32, to: i32, field_id: &str) -> FlowyResult<()> { - // GridFieldChangeset - todo!() + pub async fn move_field(&self, field_id: &str, from: i32, to: i32) -> FlowyResult<()> { + let _ = self + .modify(|grid_pad| Ok(grid_pad.move_field(field_id, from as usize, to as usize)?)) + .await?; + if let Some((index, field_meta)) = self.pad.read().await.get_field_meta(field_id) { + let delete_field_order = FieldOrder::from(field_id); + let insert_field = IndexField::from_field_meta(field_meta, index); + let notified_changeset = GridFieldChangeset { + grid_id: self.grid_id.clone(), + inserted_fields: vec![insert_field], + deleted_fields: vec![delete_field_order], + updated_fields: vec![], + }; + + let _ = self.notify_did_update_grid(notified_changeset).await?; + } + Ok(()) } pub async fn move_row(&self, from: i32, to: i32, row_id: &str) -> FlowyResult<()> { 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 5c59437d4f..2cf56fd5f0 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 @@ -205,6 +205,25 @@ impl GridMetaPad { ) } + pub fn move_field( + &mut self, + field_id: &str, + from_index: usize, + to_index: usize, + ) -> CollaborateResult> { + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { + None => Ok(None), + Some(index) => { + debug_assert_eq!(index, from_index); + let field_meta = grid_meta.fields.remove(index); + grid_meta.fields.insert(to_index, field_meta); + Ok(Some(())) + } + }, + ) + } + pub fn contain_field(&self, field_id: &str) -> bool { self.grid_meta.fields.iter().any(|field| field.id == field_id) }