diff --git a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart index 1dfe5cd45f..d132fe1ea0 100644 --- a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart +++ b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart @@ -165,7 +165,7 @@ class BoardBloc extends Bloc { return AFBoardColumnData( id: group.groupId, name: group.desc, - items: _buildRows(group.rows), + items: _buildRows(group), customData: group, ); }).toList(); @@ -196,9 +196,9 @@ class BoardBloc extends Bloc { ); } - List _buildRows(List rows) { - final items = rows.map((row) { - return BoardColumnItem(row: row); + List _buildRows(GroupPB group) { + final items = group.rows.map((row) { + return BoardColumnItem(row: row, fieldId: group.fieldId); }).toList(); return [...items]; @@ -284,7 +284,9 @@ class GridFieldEquatable extends Equatable { class BoardColumnItem extends AFColumnItem { final RowPB row; - BoardColumnItem({required this.row}); + final String fieldId; + + BoardColumnItem({required this.row, required this.fieldId}); @override String get id => row.id; @@ -301,22 +303,27 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate { GroupControllerDelegateImpl(this.controller); @override - void insertRow(String groupId, RowPB row, int? index) { - final item = BoardColumnItem(row: row); + void insertRow(GroupPB group, RowPB row, int? index) { + final item = BoardColumnItem(row: row, fieldId: group.fieldId); if (index != null) { - controller.insertColumnItem(groupId, index, item); + controller.insertColumnItem(group.groupId, index, item); } else { - controller.addColumnItem(groupId, item); + controller.addColumnItem(group.groupId, item); } } @override - void removeRow(String groupId, String rowId) { - controller.removeColumnItem(groupId, rowId); + void removeRow(GroupPB group, String rowId) { + controller.removeColumnItem(group.groupId, rowId); } @override - void updateRow(String groupId, RowPB row) { - controller.updateColumnItem(groupId, BoardColumnItem(row: row)); + void updateRow(GroupPB group, RowPB row) { + controller.updateColumnItem( + group.groupId, + BoardColumnItem( + row: row, + fieldId: group.fieldId, + )); } } diff --git a/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart index ab6aeacfcc..7f1ae766e6 100644 --- a/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart +++ b/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart @@ -4,7 +4,6 @@ import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; import 'package:app_flowy/plugins/grid/application/row/row_service.dart'; import 'package:equatable/equatable.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/block_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'; import 'dart:async'; @@ -14,10 +13,12 @@ import 'card_data_controller.dart'; part 'card_bloc.freezed.dart'; class BoardCardBloc extends Bloc { + final String fieldId; final RowFFIService _rowService; final CardDataController _dataController; BoardCardBloc({ + required this.fieldId, required String gridId, required CardDataController dataController, }) : _rowService = RowFFIService( @@ -25,22 +26,22 @@ class BoardCardBloc extends Bloc { blockId: dataController.rowPB.blockId, ), _dataController = dataController, - super(BoardCardState.initial( - dataController.rowPB, dataController.loadData())) { + super( + BoardCardState.initial( + dataController.rowPB, + _makeCells(fieldId, dataController.loadData()), + ), + ) { on( (event, emit) async { - await event.map( - initial: (_InitialRow value) async { + await event.when( + initial: () async { await _startListening(); }, - didReceiveCells: (_DidReceiveCells value) async { - final cells = value.gridCellMap.values - .map((e) => GridCellEquatable(e.field)) - .toList(); + didReceiveCells: (cells, reason) async { emit(state.copyWith( - gridCellMap: value.gridCellMap, - cells: UnmodifiableListView(cells), - changeReason: value.reason, + cells: cells, + changeReason: reason, )); }, ); @@ -58,7 +59,7 @@ class BoardCardBloc extends Bloc { return RowInfo( gridId: _rowService.gridId, fields: UnmodifiableListView( - state.cells.map((cell) => cell._field).toList(), + state.cells.map((cell) => cell.identifier.field).toList(), ), rowPB: state.rowPB, ); @@ -66,8 +67,9 @@ class BoardCardBloc extends Bloc { Future _startListening() async { _dataController.addListener( - onRowChanged: (cells, reason) { + onRowChanged: (cellMap, reason) { if (!isClosed) { + final cells = _makeCells(fieldId, cellMap); add(BoardCardEvent.didReceiveCells(cells, reason)); } }, @@ -75,42 +77,49 @@ class BoardCardBloc extends Bloc { } } +UnmodifiableListView _makeCells( + String fieldId, GridCellMap originalCellMap) { + List cells = []; + for (final entry in originalCellMap.entries) { + if (entry.value.fieldId != fieldId) { + cells.add(BoardCellEquatable(entry.value)); + } + } + return UnmodifiableListView(cells); +} + @freezed class BoardCardEvent with _$BoardCardEvent { const factory BoardCardEvent.initial() = _InitialRow; const factory BoardCardEvent.didReceiveCells( - GridCellMap gridCellMap, RowsChangedReason reason) = _DidReceiveCells; + UnmodifiableListView cells, + RowsChangedReason reason, + ) = _DidReceiveCells; } @freezed class BoardCardState with _$BoardCardState { const factory BoardCardState({ required RowPB rowPB, - required GridCellMap gridCellMap, - required UnmodifiableListView cells, + required UnmodifiableListView cells, RowsChangedReason? changeReason, }) = _BoardCardState; - factory BoardCardState.initial(RowPB rowPB, GridCellMap cellDataMap) => - BoardCardState( - rowPB: rowPB, - gridCellMap: cellDataMap, - cells: UnmodifiableListView( - cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList(), - ), - ); + factory BoardCardState.initial( + RowPB rowPB, UnmodifiableListView cells) => + BoardCardState(rowPB: rowPB, cells: cells); } -class GridCellEquatable extends Equatable { - final FieldPB _field; +class BoardCellEquatable extends Equatable { + final GridCellIdentifier identifier; - const GridCellEquatable(FieldPB field) : _field = field; + const BoardCellEquatable(this.identifier); @override List get props => [ - _field.id, - _field.fieldType, - _field.visibility, - _field.width, + identifier.field.id, + identifier.field.fieldType, + identifier.field.visibility, + identifier.field.width, ]; } diff --git a/frontend/app_flowy/lib/plugins/board/application/group_controller.dart b/frontend/app_flowy/lib/plugins/board/application/group_controller.dart index b0a89baaa3..0ca71ff5f6 100644 --- a/frontend/app_flowy/lib/plugins/board/application/group_controller.dart +++ b/frontend/app_flowy/lib/plugins/board/application/group_controller.dart @@ -7,9 +7,9 @@ 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); - void updateRow(String groupId, RowPB row); + void removeRow(GroupPB group, String rowId); + void insertRow(GroupPB group, RowPB row, int? index); + void updateRow(GroupPB group, RowPB row); } class GroupController { @@ -37,7 +37,7 @@ class GroupController { (GroupChangesetPB changeset) { for (final deletedRow in changeset.deletedRows) { group.rows.removeWhere((rowPB) => rowPB.id == deletedRow); - delegate.removeRow(group.groupId, deletedRow); + delegate.removeRow(group, deletedRow); } for (final insertedRow in changeset.insertedRows) { @@ -51,7 +51,7 @@ class GroupController { } delegate.insertRow( - group.groupId, + group, insertedRow.row, index, ); @@ -66,7 +66,7 @@ class GroupController { group.rows[index] = updatedRow; } - delegate.updateRow(group.groupId, updatedRow); + delegate.updateRow(group, updatedRow); } }, (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart index eeddb123d0..bd1bf54296 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart @@ -73,7 +73,8 @@ class _BoardContentState extends State { @override Widget build(BuildContext context) { return BlocBuilder( - buildWhen: (previous, current) => previous.groupIds != current.groupIds, + buildWhen: (previous, current) => + previous.groupIds.length != current.groupIds.length, builder: (context, state) { return Container( color: Colors.white, @@ -159,7 +160,8 @@ class _BoardContentState extends State { AFBoardColumnData column, AFColumnItem columnItem, ) { - final rowPB = (columnItem as BoardColumnItem).row; + final boardColumnItem = columnItem as BoardColumnItem; + final rowPB = boardColumnItem.row; final rowCache = context.read().getRowCache(rowPB.blockId); /// Return placeholder widget if the rowCache is null. @@ -186,6 +188,7 @@ class _BoardContentState extends State { child: BoardCard( gridId: gridId, groupId: column.id, + fieldId: boardColumnItem.fieldId, isEditing: isEditing, cellBuilder: cellBuilder, dataController: cardController, diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart index f75de47651..b2383bd937 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart @@ -35,8 +35,9 @@ class _BoardSelectOptionCellState extends State { return BlocProvider.value( value: _cellBloc, child: BlocBuilder( - buildWhen: (previous, current) => - previous.selectedOptions != current.selectedOptions, + buildWhen: (previous, current) { + return previous.selectedOptions != current.selectedOptions; + }, builder: (context, state) { if (state.selectedOptions .where((element) => element.id == widget.groupId) diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart index 65c7d3dade..dfb8149c9e 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart @@ -15,6 +15,7 @@ typedef OnEndEditing = void Function(String rowId); class BoardCard extends StatefulWidget { final String gridId; final String groupId; + final String fieldId; final bool isEditing; final CardDataController dataController; final BoardCellBuilder cellBuilder; @@ -24,6 +25,7 @@ class BoardCard extends StatefulWidget { const BoardCard({ required this.gridId, required this.groupId, + required this.fieldId, required this.isEditing, required this.dataController, required this.cellBuilder, @@ -43,6 +45,7 @@ class _BoardCardState extends State { void initState() { _cardBloc = BoardCardBloc( gridId: widget.gridId, + fieldId: widget.fieldId, dataController: widget.dataController, )..add(const BoardCardEvent.initial()); super.initState(); @@ -53,6 +56,9 @@ class _BoardCardState extends State { return BlocProvider.value( value: _cardBloc, child: BlocBuilder( + buildWhen: (previous, current) { + return previous.cells.length != current.cells.length; + }, builder: (context, state) { return BoardCardContainer( accessoryBuilder: (context) { @@ -62,7 +68,10 @@ class _BoardCardState extends State { widget.openCard(context); }, child: Column( - children: _makeCells(context, state.gridCellMap), + children: _makeCells( + context, + state.cells.map((cell) => cell.identifier).toList(), + ), ), ); }, @@ -70,9 +79,12 @@ class _BoardCardState extends State { ); } - List _makeCells(BuildContext context, GridCellMap cellMap) { - return cellMap.values.map( - (cellId) { + List _makeCells( + BuildContext context, + List cells, + ) { + return cells.map( + (GridCellIdentifier cellId) { final child = widget.cellBuilder.buildCell(widget.groupId, cellId); return Padding( padding: const EdgeInsets.only(left: 4, right: 4, top: 6), 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 cdc6cf6e6b..9ae7918955 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -18,7 +18,7 @@ use flowy_sync::client_grid::{GridRevisionChangeset, GridRevisionPad, JsonDeseri use flowy_sync::entities::revision::Revision; use flowy_sync::errors::CollaborateResult; use flowy_sync::util::make_text_delta_from_revisions; -use lib_infra::future::FutureResult; +use lib_infra::future::{wrap_future, FutureResult}; use std::collections::HashMap; use std::sync::Arc; @@ -591,34 +591,33 @@ impl GridRevisionEditor { match self.block_manager.get_row_rev(&from_row_id).await? { None => tracing::warn!("Move row failed, can not find the row:{}", from_row_id), Some(row_rev) => { - if let Some(row_changeset) = self - .view_manager - .move_group_row(row_rev, to_group_id, to_row_id.clone()) - .await - { - tracing::trace!("Move group row cause row data changed: {:?}", row_changeset); + let block_manager = self.block_manager.clone(); + self.view_manager + .move_group_row(row_rev, to_group_id, to_row_id.clone(), |row_changeset| { + wrap_future(async move { + tracing::trace!("Move group row cause row data changed: {:?}", row_changeset); + let cell_changesets = row_changeset + .cell_by_field_id + .into_iter() + .map(|(field_id, cell_rev)| CellChangesetPB { + grid_id: view_id.clone(), + row_id: row_changeset.row_id.clone(), + field_id, + content: cell_rev.data, + }) + .collect::>(); - let cell_changesets = row_changeset - .cell_by_field_id - .into_iter() - .map(|(field_id, cell_rev)| CellChangesetPB { - grid_id: view_id.clone(), - row_id: row_changeset.row_id.clone(), - field_id, - content: cell_rev.data, + for cell_changeset in cell_changesets { + match block_manager.update_cell(cell_changeset).await { + Ok(_) => {} + Err(e) => tracing::error!("Apply cell changeset error:{:?}", e), + } + } }) - .collect::>(); - - for cell_changeset in cell_changesets { - match self.block_manager.update_cell(cell_changeset).await { - Ok(_) => {} - Err(e) => tracing::error!("Apply cell changeset error:{:?}", e), - } - } - } + }) + .await?; } } - Ok(()) } diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs index 6a04e18815..8b89aa72ae 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs @@ -140,8 +140,8 @@ impl GridViewRevisionEditor { row_changeset: &mut RowChangeset, to_group_id: &str, to_row_id: Option, - ) { - if let Some(changesets) = self + ) -> Vec { + match self .group_service .write() .await @@ -150,9 +150,8 @@ impl GridViewRevisionEditor { }) .await { - for changeset in changesets { - self.notify_did_update_group(changeset).await; - } + None => vec![], + Some(changesets) => changesets, } } /// Only call once after grid view editor initialized @@ -266,7 +265,7 @@ impl GridViewRevisionEditor { Ok(()) } - async fn notify_did_update_group(&self, changeset: GroupChangesetPB) { + pub async fn notify_did_update_group(&self, changeset: GroupChangesetPB) { send_dart_notification(&changeset.group_id, GridNotification::DidUpdateGroup) .payload(changeset) .send(); diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs b/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs index 657058b31f..8c9893e4ef 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_manager.rs @@ -134,19 +134,23 @@ impl GridViewManager { row_rev: Arc, to_group_id: String, to_row_id: Option, - ) -> Option { + with_row_changeset: impl FnOnce(RowChangeset) -> AFFuture<()>, + ) -> FlowyResult<()> { let mut row_changeset = RowChangeset::new(row_rev.id.clone()); - for view_editor in self.view_editors.iter() { - view_editor - .move_group_row(&row_rev, &mut row_changeset, &to_group_id, to_row_id.clone()) - .await; + let view_editor = self.get_default_view_editor().await?; + let group_changesets = view_editor + .move_group_row(&row_rev, &mut row_changeset, &to_group_id, to_row_id.clone()) + .await; + + if row_changeset.is_empty() == false { + with_row_changeset(row_changeset).await; } - if row_changeset.is_empty() { - None - } else { - Some(row_changeset) + for group_changeset in group_changesets { + view_editor.notify_did_update_group(group_changeset).await; } + + Ok(()) } pub(crate) async fn did_update_field(&self, field_id: &str) -> FlowyResult<()> {