From bf93376cf39e588451900fd79b9dff5af135dc9d Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 22 Apr 2022 14:22:47 +0800 Subject: [PATCH 01/12] fix: unselect option --- .../grid/cell/select_option_service.dart | 2 +- .../grid/cell/selection_editor_bloc.dart | 26 +++++++---- .../grid/src/widgets/cell/cell_builder.dart | 6 +-- .../cell/selection_cell/selection_cell.dart | 46 +++++++++++++++++-- .../grid/src/widgets/row/row_detail.dart | 42 +++++++++++------ .../flowy_infra_ui/lib/style_widget/text.dart | 2 +- 6 files changed, 93 insertions(+), 31 deletions(-) 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 c76f06adc9..41c496c373 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 @@ -94,7 +94,7 @@ class SelectOptionService { return GridEventUpdateCellSelectOption(payload).send(); } - Future> remove({ + Future> unSelect({ required String gridId, required String fieldId, required String rowId, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index 92676a0c12..1860e40ef3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -51,7 +51,7 @@ class SelectOptionEditorBloc extends Bloc null, (err) => Log.error(err)); } - void _makeOptionAsSelected(String optionId) { - _selectOptionService.select( - gridId: state.gridId, - fieldId: state.field.id, - rowId: state.rowId, - optionId: optionId, - ); + void _onSelectOption(String optionId) { + final hasSelected = state.selectedOptions.firstWhereOrNull((option) => option.id == optionId); + if (hasSelected != null) { + _selectOptionService.unSelect( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + optionId: optionId, + ); + } else { + _selectOptionService.select( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + optionId: optionId, + ); + } } void _loadOptions() async { 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 015fea1c32..4b52cae908 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 @@ -16,13 +16,13 @@ GridCellWidget buildGridCell(GridCell cellData, {GridCellStyle? style}) { case FieldType.DateTime: return DateCell(cellData: cellData, key: key); case FieldType.MultiSelect: - return MultiSelectCell(cellData: cellData, key: key); + return MultiSelectCell(cellData: cellData, style: style, key: key); case FieldType.Number: return NumberCell(cellData: cellData, key: key); case FieldType.RichText: - return GridTextCell(cellData: cellData, key: key, style: style); + return GridTextCell(cellData: cellData, style: style, key: key); case FieldType.SingleSelect: - return SingleSelectCell(cellData: cellData, key: key); + return SingleSelectCell(cellData: cellData, style: style, key: key); default: throw UnimplementedError; } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index 05dd66e224..f3b42621a9 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -1,19 +1,37 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'extension.dart'; import 'selection_editor.dart'; +class SelectOptionCellStyle extends GridCellStyle { + String placeholder; + + SelectOptionCellStyle({ + required this.placeholder, + }); +} + class SingleSelectCell extends GridCellWidget { final GridCell cellData; + late final SelectOptionCellStyle? cellStyle; SingleSelectCell({ required this.cellData, + GridCellStyle? style, Key? key, - }) : super(key: key); + }) : super(key: key) { + if (style != null) { + cellStyle = (style as SelectOptionCellStyle); + } else { + cellStyle = null; + } + } @override State createState() => _SingleSelectCellState(); @@ -30,11 +48,18 @@ class _SingleSelectCellState extends State { @override Widget build(BuildContext context) { + final theme = context.watch(); + return BlocProvider.value( value: _cellBloc, child: BlocBuilder( builder: (context, state) { - final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList(); + List children = []; + children.addAll(state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList()); + + if (children.isEmpty && widget.cellStyle != null) { + children.add(FlowyText.medium(widget.cellStyle!.placeholder, fontSize: 14, color: theme.shader3)); + } return SizedBox.expand( child: InkWell( onTap: () { @@ -65,11 +90,19 @@ class _SingleSelectCellState extends State { //---------------------------------------------------------------- class MultiSelectCell extends GridCellWidget { final GridCell cellData; + late final SelectOptionCellStyle? cellStyle; MultiSelectCell({ required this.cellData, + GridCellStyle? style, Key? key, - }) : super(key: key); + }) : super(key: key) { + if (style != null) { + cellStyle = (style as SelectOptionCellStyle); + } else { + cellStyle = null; + } + } @override State createState() => _MultiSelectCellState(); @@ -90,7 +123,12 @@ class _MultiSelectCellState extends State { value: _cellBloc, child: BlocBuilder( builder: (context, state) { - final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList(); + List children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList(); + + if (children.isEmpty && widget.cellStyle != null) { + children.add(FlowyText.medium(widget.cellStyle!.placeholder, fontSize: 14)); + } + return SizedBox.expand( child: InkWell( onTap: () { 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 4ba31f783b..28ea259b88 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 @@ -1,12 +1,14 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/workspace/application/grid/row/row_detail_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; import 'package:easy_localization/easy_localization.dart'; @@ -59,8 +61,8 @@ class _RowDetailPageState extends State { bloc.add(const RowDetailEvent.initial()); return bloc; }, - child: const Padding( - padding: EdgeInsets.symmetric(horizontal: 80, vertical: 40), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 80, vertical: 40), child: _PropertyList(), ), ); @@ -68,23 +70,31 @@ class _RowDetailPageState extends State { } class _PropertyList extends StatelessWidget { - const _PropertyList({ + final ScrollController _scrollController; + _PropertyList({ Key? key, - }) : super(key: key); + }) : _scrollController = ScrollController(), + super(key: key); @override Widget build(BuildContext context) { return BlocBuilder( buildWhen: (previous, current) => previous.cellDatas != current.cellDatas, builder: (context, state) { - return ListView.separated( - itemCount: state.cellDatas.length, - itemBuilder: (BuildContext context, int index) { - return _RowDetailCell(cellData: state.cellDatas[index]); - }, - separatorBuilder: (BuildContext context, int index) { - return const VSpace(2); - }, + return ScrollbarListStack( + axis: Axis.vertical, + controller: _scrollController, + barSize: GridSize.scrollBarSize, + child: ListView.separated( + controller: _scrollController, + itemCount: state.cellDatas.length, + itemBuilder: (BuildContext context, int index) { + return _RowDetailCell(cellData: state.cellDatas[index]); + }, + separatorBuilder: (BuildContext context, int index) { + return const VSpace(2); + }, + ), ); }, ); @@ -142,7 +152,9 @@ GridCellStyle? _buildCellStyle(AppTheme theme, FieldType fieldType) { case FieldType.DateTime: return null; case FieldType.MultiSelect: - return null; + return SelectOptionCellStyle( + placeholder: LocaleKeys.grid_row_textPlaceholder.tr(), + ); case FieldType.Number: return null; case FieldType.RichText: @@ -150,7 +162,9 @@ GridCellStyle? _buildCellStyle(AppTheme theme, FieldType fieldType) { placeholder: LocaleKeys.grid_row_textPlaceholder.tr(), ); case FieldType.SingleSelect: - return null; + return SelectOptionCellStyle( + placeholder: LocaleKeys.grid_row_textPlaceholder.tr(), + ); default: return null; } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart index 55f29eba93..74cf7e4c31 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart @@ -46,7 +46,7 @@ class FlowyText extends StatelessWidget { style: TextStyle( color: color ?? theme.textColor, fontWeight: fontWeight, - fontSize: fontSize + 2, + fontSize: fontSize, fontFamily: 'Mulish', )); } From fa7097587f81e9fee72c3b21f9628c358b631819 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 22 Apr 2022 20:39:49 +0800 Subject: [PATCH 02/12] chore: reuse widget while inserting row --- .../application/grid/grid_service.dart | 6 ++-- .../application/grid/row/row_bloc.dart | 21 ++++------- .../application/grid/row/row_detail_bloc.dart | 10 +++--- .../application/grid/row/row_service.dart | 35 ++++++++++--------- .../plugins/grid/src/grid_page.dart | 2 +- .../grid/src/widgets/cell/cell_builder.dart | 2 +- .../grid/src/widgets/row/grid_row.dart | 31 ++++++++-------- 7 files changed, 48 insertions(+), 59 deletions(-) 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 aee2a82be4..5a3cda7b41 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -180,14 +180,14 @@ class GridRowDataDelegateAdaptor extends GridRowDataDelegate { } @override - CellDataMap buildCellDataMap(Row rowData) { + CellDataMap buildCellDataMap(String rowId, Row? rowData) { var map = CellDataMap.new(); for (final field in fields) { if (field.visibility) { map[field.id] = GridCell( - rowId: rowData.id, + rowId: rowId, gridId: _cache.gridId, - cell: rowData.cellByFieldId[field.id], + cell: rowData?.cellByFieldId[field.id], field: field, ); } 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 b49485c16b..213dda768f 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 @@ -17,19 +17,18 @@ class RowBloc extends Bloc { required GridRowCache rowCache, }) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), _rowCache = rowCache, - super(RowState.initial(rowData)) { + super(RowState.initial(rowData, rowCache.loadCellData(rowData.rowId))) { on( (event, emit) async { await event.map( initial: (_InitialRow value) async { await _startListening(); - await _loadRow(emit); }, createRow: (_CreateRow value) { _rowService.createRow(); }, didReceiveCellDatas: (_DidReceiveCellDatas value) async { - emit(state.copyWith(cellDataMap: Some(value.cellData))); + emit(state.copyWith(cellDataMap: value.cellData)); }, ); }, @@ -41,6 +40,7 @@ class RowBloc extends Bloc { if (_rowListenFn != null) { _rowCache.removeRowListener(_rowListenFn!); } + return super.close(); } @@ -51,15 +51,6 @@ class RowBloc extends Bloc { listenWhen: () => !isClosed, ); } - - Future _loadRow(Emitter emit) async { - final data = _rowCache.loadCellData(state.rowData.rowId); - data.foldRight(null, (cellDatas, _) { - if (!isClosed) { - add(RowEvent.didReceiveCellDatas(cellDatas)); - } - }); - } } @freezed @@ -73,11 +64,11 @@ class RowEvent with _$RowEvent { class RowState with _$RowState { const factory RowState({ required GridRow rowData, - required Option cellDataMap, + required CellDataMap cellDataMap, }) = _RowState; - factory RowState.initial(GridRow rowData) => RowState( + factory RowState.initial(GridRow rowData, CellDataMap cellDataMap) => RowState( rowData: rowData, - cellDataMap: none(), + cellDataMap: cellDataMap, ); } 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 2390dc40a0..c9ff9df407 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 @@ -47,12 +47,10 @@ class RowDetailBloc extends Bloc { } Future _loadCellData() async { - final data = _rowCache.loadCellData(rowData.rowId); - data.foldRight(null, (cellDataMap, _) { - if (!isClosed) { - add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList())); - } - }); + final cellDataMap = _rowCache.loadCellData(rowData.rowId); + 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 f524e03d0c..dbaf25188d 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 @@ -18,7 +18,7 @@ typedef CellDataMap = LinkedHashMap; abstract class GridRowDataDelegate { UnmodifiableListView get fields; GridRow buildGridRow(RowOrder rowOrder); - CellDataMap buildCellDataMap(Row rowData); + CellDataMap buildCellDataMap(String rowId, Row? rowData); void onFieldChanged(FieldDidUpdateCallback callback); } @@ -92,7 +92,7 @@ class GridRowCache { notify() { final row = _rowNotifier.rowDataWithId(rowId); if (row != null) { - final cellDataMap = _dataDelegate.buildCellDataMap(row); + final cellDataMap = _dataDelegate.buildCellDataMap(rowId, row); onUpdated(cellDataMap); } } @@ -115,23 +115,22 @@ class GridRowCache { _rowNotifier.removeListener(callback); } - Option loadCellData(String rowId) { + CellDataMap loadCellData(String rowId) { final Row? data = _rowNotifier.rowDataWithId(rowId); - if (data != null) { - return Some(_dataDelegate.buildCellDataMap(data)); + if (data == null) { + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + GridEventGetRow(payload).send().then((result) { + result.fold( + (rowData) => _rowNotifier.rowData = rowData, + (err) => Log.error(err), + ); + }); } - final payload = RowIdentifierPayload.create() - ..gridId = gridId - ..rowId = rowId; - - GridEventGetRow(payload).send().then((result) { - result.fold( - (rowData) => _rowNotifier.rowData = rowData, - (err) => Log.error(err), - ); - }); - return none(); + return _dataDelegate.buildCellDataMap(rowId, data); } void updateWithBlock(List blocks) { @@ -331,6 +330,10 @@ class GridCell with _$GridCell { required Field field, Cell? cell, }) = _GridCell; + + ValueKey key() { + return ValueKey(rowId + (cell?.fieldId ?? "")); + } } typedef InsertedIndexs = List; 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 6e01d56b66..56c78195bc 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 @@ -213,7 +213,7 @@ class _GridRowsState extends State<_GridRows> { key: _key, initialItemCount: context.read().state.rows.length, itemBuilder: (BuildContext context, int index, Animation animation) { - final rowData = context.read().state.rows[index]; + final GridRow rowData = context.read().state.rows[index]; return _renderRow(context, rowData, animation); }, ); 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 4b52cae908..df57efaff6 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 @@ -9,7 +9,7 @@ import 'selection_cell/selection_cell.dart'; import 'text_cell.dart'; GridCellWidget buildGridCell(GridCell cellData, {GridCellStyle? style}) { - final key = ValueKey(cellData.field.id + cellData.rowId); + final key = cellData.key(); switch (cellData.field.fieldType) { case FieldType.Checkbox: return CheckboxCell(cellData: cellData, key: key); 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 1201120f37..327f29ba74 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 @@ -164,24 +164,21 @@ class _RowCells extends StatelessWidget { ); } - List _makeCells(Option data) { - return data.fold( - () => [], - (cellDataMap) => cellDataMap.values.map( - (cellData) { - Widget? expander; - if (cellData.field.isPrimary) { - expander = _CellExpander(onExpand: onExpand); - } + List _makeCells(CellDataMap cellDataMap) { + return cellDataMap.values.map( + (cellData) { + Widget? expander; + if (cellData.field.isPrimary) { + expander = _CellExpander(onExpand: onExpand); + } - return CellContainer( - width: cellData.field.width.toDouble(), - child: buildGridCell(cellData), - expander: expander, - ); - }, - ).toList(), - ); + return CellContainer( + width: cellData.field.width.toDouble(), + child: buildGridCell(cellData), + expander: expander, + ); + }, + ).toList(); } } From b0f5af679c404b7cebff0b01ad38233b5a3a429d Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 22 Apr 2022 22:13:51 +0800 Subject: [PATCH 03/12] chore: cache cell data --- .../app_flowy/lib/startup/deps_resolver.dart | 28 +++--- .../application/grid/cell/cell_service.dart | 94 ++++++++++++++++++- .../grid/cell/checkbox_cell_bloc.dart | 7 +- .../application/grid/cell/date_cell_bloc.dart | 9 +- .../grid/cell/number_cell_bloc.dart | 9 +- .../grid/cell/selection_cell_bloc.dart | 10 +- .../grid/cell/selection_editor_bloc.dart | 2 +- .../application/grid/cell/text_cell_bloc.dart | 7 +- .../workspace/application/grid/grid_bloc.dart | 9 +- .../application/grid/grid_service.dart | 37 +++----- .../application/grid/row/row_bloc.dart | 2 +- .../application/grid/row/row_detail_bloc.dart | 1 + .../application/grid/row/row_service.dart | 58 +++++++----- .../plugins/grid/src/grid_page.dart | 2 + .../grid/src/widgets/cell/cell_builder.dart | 21 +++-- .../grid/src/widgets/cell/checkbox_cell.dart | 6 +- .../grid/src/widgets/cell/date_cell.dart | 6 +- .../grid/src/widgets/cell/number_cell.dart | 6 +- .../cell/selection_cell/selection_cell.dart | 12 +-- .../cell/selection_cell/selection_editor.dart | 1 + .../grid/src/widgets/cell/text_cell.dart | 6 +- .../grid/src/widgets/row/grid_row.dart | 21 ++++- .../grid/src/widgets/row/row_detail.dart | 30 ++++-- 23 files changed, 249 insertions(+), 135 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 8f239f1ece..da5274b0ca 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -168,34 +168,34 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( - (cellData, _) => TextCellBloc( - cellData: cellData, + getIt.registerFactoryParam( + (context, _) => TextCellBloc( + cellDataContext: context, ), ); - getIt.registerFactoryParam( - (cellData, _) => SelectionCellBloc( - cellData: cellData, + getIt.registerFactoryParam( + (context, _) => SelectionCellBloc( + cellDataContext: context, ), ); - getIt.registerFactoryParam( - (cellData, _) => NumberCellBloc( - cellData: cellData, + getIt.registerFactoryParam( + (context, _) => NumberCellBloc( + cellDataContext: context, ), ); - getIt.registerFactoryParam( - (cellData, _) => DateCellBloc( - cellData: cellData, + getIt.registerFactoryParam( + (context, _) => DateCellBloc( + cellDataContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => CheckboxCellBloc( service: CellService(), - cellData: cellData, + cellDataContext: cellData, ), ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index dce064eae2..9cf5ddd042 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -1,12 +1,90 @@ import 'dart:collection'; -import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; -import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:dartz/dartz.dart'; 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-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +part 'cell_service.freezed.dart'; + +class GridCellDataContext { + GridCell cellData; + GridCellCache cellCache; + GridCellDataContext({ + required this.cellData, + required this.cellCache, + }); + + String get gridId => cellData.gridId; + + String get cellId => cellData.rowId + (cellData.cell?.fieldId ?? ""); + + String get rowId => cellData.rowId; + + String get fieldId => cellData.field.id; + + FieldType get fieldType => cellData.field.fieldType; + + Field get field => cellData.field; +} + +// key: rowId +typedef CellDataMap = LinkedHashMap; + +abstract class GridCellCacheData { + String get fieldId; + String get cacheKey; + dynamic get cacheData; +} + +abstract class GridCellFieldDelegate { + void onFieldChanged(void Function(String) callback); +} + +class GridCellCache { + final String gridId; + final GridCellFieldDelegate fieldDelegate; + + /// fieldId: {cacheKey: cacheData} + final Map> _cells = {}; + GridCellCache({ + required this.gridId, + required this.fieldDelegate, + }) { + fieldDelegate.onFieldChanged((fieldId) { + _cells.remove(fieldId); + }); + } + + void insert(T cacheData) { + var map = _cells[cacheData.fieldId]; + if (map == null) { + _cells[cacheData.fieldId] = {}; + map = _cells[cacheData.fieldId]; + } + + map![cacheData.cacheKey] = cacheData.cacheData; + } + + T? get(String fieldId, String cacheKey) { + final map = _cells[fieldId]; + if (map == null) { + return null; + } else { + final object = map[cacheKey]; + if (object is T) { + return object; + } else { + Log.error("Cache data type does not match the cache data type"); + return null; + } + } + } +} class CellService { CellService(); @@ -73,3 +151,13 @@ class CellCache { return "${identifier.rowId}/${identifier.field.id}"; } } + +@freezed +class GridCell with _$GridCell { + const factory GridCell({ + required String gridId, + required String rowId, + required Field field, + Cell? cell, + }) = _GridCell; +} 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 880267f6c9..11ab2d2d8a 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 @@ -1,5 +1,4 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; -import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -15,10 +14,10 @@ class CheckboxCellBloc extends Bloc { CheckboxCellBloc({ required CellService service, - required GridCell cellData, + required GridCellDataContext cellDataContext, }) : _service = service, - _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - super(CheckboxCellState.initial(cellData)) { + _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), + super(CheckboxCellState.initial(cellDataContext.cellData)) { on( (event, emit) async { await event.map( 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 cbabe6c5fe..3f08ede31f 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,6 +1,5 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; -import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -15,11 +14,11 @@ class DateCellBloc extends Bloc { final CellListener _cellListener; final SingleFieldListener _fieldListener; - DateCellBloc({required GridCell cellData}) + DateCellBloc({required GridCellDataContext cellDataContext}) : _service = CellService(), - _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - _fieldListener = SingleFieldListener(fieldId: cellData.field.id), - super(DateCellState.initial(cellData)) { + _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), + _fieldListener = SingleFieldListener(fieldId: cellDataContext.fieldId), + super(DateCellState.initial(cellDataContext.cellData)) { on( (event, emit) async { event.map( 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 27f17257e1..9ebd59f1e2 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 @@ -1,6 +1,5 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; -import 'package:app_flowy/workspace/application/grid/row/row_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'; @@ -16,11 +15,11 @@ class NumberCellBloc extends Bloc { final SingleFieldListener _fieldListener; NumberCellBloc({ - required GridCell cellData, + required GridCellDataContext cellDataContext, }) : _service = CellService(), - _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - _fieldListener = SingleFieldListener(fieldId: cellData.field.id), - super(NumberCellState.initial(cellData)) { + _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), + _fieldListener = SingleFieldListener(fieldId: cellDataContext.fieldId), + super(NumberCellState.initial(cellDataContext.cellData)) { on( (event, emit) async { await event.map( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index 2d7435dc7a..e5a50d478a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -1,7 +1,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; -import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -16,11 +16,11 @@ class SelectionCellBloc extends Bloc { final SingleFieldListener _fieldListener; SelectionCellBloc({ - required GridCell cellData, + required GridCellDataContext cellDataContext, }) : _service = SelectOptionService(), - _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - _fieldListener = SingleFieldListener(fieldId: cellData.field.id), - super(SelectionCellState.initial(cellData)) { + _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), + _fieldListener = SingleFieldListener(fieldId: cellDataContext.fieldId), + super(SelectionCellState.initial(cellDataContext.cellData)) { on( (event, emit) async { await event.map( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index 1860e40ef3..8abd379cb9 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -1,6 +1,6 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; -import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; 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 f32c066c5e..da7759d253 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 @@ -1,4 +1,3 @@ -import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -14,10 +13,10 @@ class TextCellBloc extends Bloc { final CellListener _cellListener; TextCellBloc({ - required GridCell cellData, + required GridCellDataContext cellDataContext, }) : _service = CellService(), - _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - super(TextCellState.initial(cellData)) { + _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), + super(TextCellState.initial(cellDataContext.cellData)) { 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 93036082fb..6cae2e275c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -5,6 +5,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'cell/cell_service.dart'; import 'grid_service.dart'; import 'row/row_service.dart'; @@ -14,6 +15,7 @@ class GridBloc extends Bloc { final GridService _gridService; final GridFieldCache fieldCache; late final GridRowCache rowCache; + late final GridCellCache cellCache; GridBloc({required View view}) : _gridService = GridService(gridId: view.id), @@ -21,7 +23,12 @@ class GridBloc extends Bloc { super(GridState.initial(view.id)) { rowCache = GridRowCache( gridId: view.id, - dataDelegate: GridRowDataDelegateAdaptor(fieldCache), + fieldDelegate: GridRowCacheDelegateImpl(fieldCache), + ); + + cellCache = GridCellCache( + gridId: view.id, + fieldDelegate: GridCellCacheDelegateImpl(fieldCache), ); on( 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 5a3cda7b41..4ea13499cb 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -8,6 +8,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'cell/cell_service.dart'; import 'row/row_service.dart'; class GridService { @@ -155,43 +156,31 @@ class GridFieldCache { } } -class GridRowDataDelegateAdaptor extends GridRowDataDelegate { +class GridRowCacheDelegateImpl extends GridRowFieldDelegate { final GridFieldCache _cache; + GridRowCacheDelegateImpl(GridFieldCache cache) : _cache = cache; - GridRowDataDelegateAdaptor(GridFieldCache cache) : _cache = cache; @override UnmodifiableListView get fields => _cache.unmodifiableFields; - @override - GridRow buildGridRow(RowOrder rowOrder) { - return GridRow( - gridId: _cache.gridId, - fields: _cache.unmodifiableFields, - rowId: rowOrder.rowId, - height: rowOrder.height.toDouble(), - ); - } - @override void onFieldChanged(FieldDidUpdateCallback callback) { _cache.addListener(listener: () { callback(); }); } +} + +class GridCellCacheDelegateImpl extends GridCellFieldDelegate { + final GridFieldCache _cache; + GridCellCacheDelegateImpl(GridFieldCache cache) : _cache = cache; @override - CellDataMap buildCellDataMap(String rowId, Row? rowData) { - var map = CellDataMap.new(); - for (final field in fields) { - if (field.visibility) { - map[field.id] = GridCell( - rowId: rowId, - gridId: _cache.gridId, - cell: rowData?.cellByFieldId[field.id], - field: field, - ); + void onFieldChanged(void Function(String) callback) { + _cache.addListener(onChanged: (fields) { + for (final field in fields) { + callback(field.id); } - } - return map; + }); } } 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 213dda768f..fd83974d68 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 @@ -1,9 +1,9 @@ import 'dart:collection'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; import 'row_service.dart'; -import 'package:dartz/dartz.dart'; part 'row_bloc.freezed.dart'; 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 c9ff9df407..57895888f0 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 @@ -1,3 +1,4 @@ +import 'package:app_flowy/workspace/application/grid/cell/cell_service.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/row/row_service.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart index dbaf25188d..f3706d2782 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,6 @@ import 'dart:collection'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; @@ -13,12 +14,9 @@ part 'row_service.freezed.dart'; typedef RowUpdateCallback = void Function(); typedef FieldDidUpdateCallback = void Function(); -typedef CellDataMap = LinkedHashMap; -abstract class GridRowDataDelegate { +abstract class GridRowFieldDelegate { UnmodifiableListView get fields; - GridRow buildGridRow(RowOrder rowOrder); - CellDataMap buildCellDataMap(String rowId, Row? rowData); void onFieldChanged(FieldDidUpdateCallback callback); } @@ -26,16 +24,25 @@ class GridRowCache { final String gridId; final RowsNotifier _rowNotifier; final GridRowListener _rowsListener; - final GridRowDataDelegate _dataDelegate; + final GridRowFieldDelegate _fieldDelegate; List get clonedRows => _rowNotifier.clonedRows; - GridRowCache({required this.gridId, required GridRowDataDelegate dataDelegate}) - : _rowNotifier = RowsNotifier(rowBuilder: dataDelegate.buildGridRow), + GridRowCache({required this.gridId, required GridRowFieldDelegate fieldDelegate}) + : _rowNotifier = RowsNotifier( + rowBuilder: (rowOrder) { + return GridRow( + gridId: gridId, + fields: fieldDelegate.fields, + rowId: rowOrder.rowId, + height: rowOrder.height.toDouble(), + ); + }, + ), _rowsListener = GridRowListener(gridId: gridId), - _dataDelegate = dataDelegate { + _fieldDelegate = fieldDelegate { // - dataDelegate.onFieldChanged(() => _rowNotifier.fieldDidChange()); + fieldDelegate.onFieldChanged(() => _rowNotifier.fieldDidChange()); // listen on the row update _rowsListener.rowsUpdateNotifier.addPublishListener((result) { @@ -92,7 +99,7 @@ class GridRowCache { notify() { final row = _rowNotifier.rowDataWithId(rowId); if (row != null) { - final cellDataMap = _dataDelegate.buildCellDataMap(rowId, row); + final CellDataMap cellDataMap = _makeCellDataMap(rowId, row); onUpdated(cellDataMap); } } @@ -111,6 +118,21 @@ class GridRowCache { return listenrHandler; } + CellDataMap _makeCellDataMap(String rowId, Row? row) { + var cellDataMap = CellDataMap.new(); + for (final field in _fieldDelegate.fields) { + if (field.visibility) { + cellDataMap[field.id] = GridCell( + rowId: rowId, + gridId: gridId, + cell: row?.cellByFieldId[field.id], + field: field, + ); + } + } + return cellDataMap; + } + void removeRowListener(VoidCallback callback) { _rowNotifier.removeListener(callback); } @@ -130,7 +152,7 @@ class GridRowCache { }); } - return _dataDelegate.buildCellDataMap(rowId, data); + return _makeCellDataMap(rowId, data); } void updateWithBlock(List blocks) { @@ -322,20 +344,6 @@ class GridRow with _$GridRow { }) = _GridRow; } -@freezed -class GridCell with _$GridCell { - const factory GridCell({ - required String gridId, - required String rowId, - required Field field, - Cell? cell, - }) = _GridCell; - - ValueKey key() { - return ValueKey(rowId + (cell?.fieldId ?? "")); - } -} - typedef InsertedIndexs = List; typedef DeletedIndexs = List; typedef UpdatedIndexs = LinkedHashMap; 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 56c78195bc..5a913137af 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,11 +227,13 @@ class _GridRowsState extends State<_GridRows> { Animation animation, ) { final rowCache = context.read().rowCache; + final cellCache = context.read().cellCache; return SizeTransition( sizeFactor: animation, child: GridRowWidget( rowData: rowData, rowCache: rowCache, + cellCache: cellCache, 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 df57efaff6..b66cea7b07 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,4 @@ -import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; import 'package:flutter/widgets.dart'; @@ -8,21 +8,22 @@ import 'number_cell.dart'; import 'selection_cell/selection_cell.dart'; import 'text_cell.dart'; -GridCellWidget buildGridCell(GridCell cellData, {GridCellStyle? style}) { - final key = cellData.key(); - switch (cellData.field.fieldType) { +GridCellWidget buildGridCell(GridCellDataContext cellDataContext, {GridCellStyle? style}) { + final key = ValueKey(cellDataContext.cellId); + final fieldType = cellDataContext.cellData.field.fieldType; + switch (fieldType) { case FieldType.Checkbox: - return CheckboxCell(cellData: cellData, key: key); + return CheckboxCell(cellDataContext: cellDataContext, key: key); case FieldType.DateTime: - return DateCell(cellData: cellData, key: key); + return DateCell(cellDataContext: cellDataContext, key: key); case FieldType.MultiSelect: - return MultiSelectCell(cellData: cellData, style: style, key: key); + return MultiSelectCell(cellDataContext: cellDataContext, style: style, key: key); case FieldType.Number: - return NumberCell(cellData: cellData, key: key); + return NumberCell(cellDataContext: cellDataContext, key: key); case FieldType.RichText: - return GridTextCell(cellData: cellData, style: style, key: key); + return GridTextCell(cellDataContext: cellDataContext, style: style, key: key); case FieldType.SingleSelect: - return SingleSelectCell(cellData: cellData, style: style, key: key); + return SingleSelectCell(cellDataContext: cellDataContext, style: style, key: key); default: throw UnimplementedError; } 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 608913d41d..80e0468274 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,10 +7,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_builder.dart'; class CheckboxCell extends GridCellWidget { - final GridCell cellData; + final GridCellDataContext cellDataContext; CheckboxCell({ - required this.cellData, + required this.cellDataContext, Key? key, }) : super(key: key); @@ -23,7 +23,7 @@ class _CheckboxCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellData)..add(const CheckboxCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellDataContext)..add(const CheckboxCellEvent.initial()); super.initState(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart index 84d60c797a..2be56133f2 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart @@ -14,10 +14,10 @@ abstract class GridCellDelegate { } class DateCell extends GridCellWidget { - final GridCell cellData; + final GridCellDataContext cellDataContext; DateCell({ - required this.cellData, + required this.cellDataContext, Key? key, }) : super(key: key); @@ -30,7 +30,7 @@ class _DateCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellData)..add(const DateCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellDataContext)..add(const DateCellEvent.initial()); super.initState(); } 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 2d98aa0bd6..1b57a69ec8 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 @@ -8,10 +8,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_builder.dart'; class NumberCell extends GridCellWidget { - final GridCell cellData; + final GridCellDataContext cellDataContext; NumberCell({ - required this.cellData, + required this.cellDataContext, Key? key, }) : super(key: key); @@ -27,7 +27,7 @@ class _NumberCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellData)..add(const NumberCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellDataContext)..add(const NumberCellEvent.initial()); _controller = TextEditingController(text: _cellBloc.state.content); _focusNode = FocusNode(); _focusNode.addListener(() { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index f3b42621a9..3402c05060 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -18,11 +18,11 @@ class SelectOptionCellStyle extends GridCellStyle { } class SingleSelectCell extends GridCellWidget { - final GridCell cellData; + final GridCellDataContext cellDataContext; late final SelectOptionCellStyle? cellStyle; SingleSelectCell({ - required this.cellData, + required this.cellDataContext, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -42,7 +42,7 @@ class _SingleSelectCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellData)..add(const SelectionCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellDataContext)..add(const SelectionCellEvent.initial()); super.initState(); } @@ -89,11 +89,11 @@ class _SingleSelectCellState extends State { //---------------------------------------------------------------- class MultiSelectCell extends GridCellWidget { - final GridCell cellData; + final GridCellDataContext cellDataContext; late final SelectOptionCellStyle? cellStyle; MultiSelectCell({ - required this.cellData, + required this.cellDataContext, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -113,7 +113,7 @@ class _MultiSelectCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellData)..add(const SelectionCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellDataContext)..add(const SelectionCellEvent.initial()); super.initState(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart index d3fcd9efcf..2f4b54cc9b 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart @@ -1,4 +1,5 @@ import 'dart:collection'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/cell/selection_editor_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; 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 4c9c07697e..7a32583b20 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 GridCell cellData; + final GridCellDataContext cellDataContext; late final GridTextCellStyle? cellStyle; GridTextCell({ - required this.cellData, + required this.cellDataContext, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -41,7 +41,7 @@ class _GridTextCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellData); + _cellBloc = getIt(param1: widget.cellDataContext); _cellBloc.add(const TextCellEvent.initial()); _controller = TextEditingController(text: _cellBloc.state.content); _focusNode = FocusNode(); 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 327f29ba74..a543693f82 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 @@ -8,17 +8,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:provider/provider.dart'; import 'row_action_sheet.dart'; -import 'package:dartz/dartz.dart' show Option; import 'row_detail.dart'; class GridRowWidget extends StatefulWidget { final GridRow rowData; final GridRowCache rowCache; + final GridCellCache cellCache; const GridRowWidget({ required this.rowData, required this.rowCache, + required this.cellCache, Key? key, }) : super(key: key); @@ -49,7 +50,7 @@ class _GridRowWidgetState extends State { builder: (context, state) { final children = [ const _RowLeading(), - _RowCells(onExpand: () => onExpandCell(context)), + _RowCells(cellCache: widget.cellCache, onExpand: () => onExpandCell(context)), const _RowTrailing(), ]; @@ -73,7 +74,11 @@ class _GridRowWidgetState extends State { } void onExpandCell(BuildContext context) { - final page = RowDetailPage(rowData: widget.rowData, rowCache: widget.rowCache); + final page = RowDetailPage( + rowData: widget.rowData, + rowCache: widget.rowCache, + cellCache: widget.cellCache, + ); page.show(context); } } @@ -147,8 +152,9 @@ class _DeleteRowButton extends StatelessWidget { } class _RowCells extends StatelessWidget { + final GridCellCache cellCache; final VoidCallback onExpand; - const _RowCells({required this.onExpand, Key? key}) : super(key: key); + const _RowCells({required this.cellCache, required this.onExpand, Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -172,9 +178,14 @@ class _RowCells extends StatelessWidget { expander = _CellExpander(onExpand: onExpand); } + final cellDataContext = GridCellDataContext( + cellData: cellData, + cellCache: cellCache, + ); + return CellContainer( width: cellData.field.width.toDouble(), - child: buildGridCell(cellData), + child: buildGridCell(cellDataContext), expander: expander, ); }, 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 28ea259b88..81d64d87da 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 @@ -1,3 +1,4 @@ +import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/workspace/application/grid/row/row_detail_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; @@ -20,10 +21,12 @@ import 'package:window_size/window_size.dart'; class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate { final GridRow rowData; final GridRowCache rowCache; + final GridCellCache cellCache; const RowDetailPage({ required this.rowData, required this.rowCache, + required this.cellCache, Key? key, }) : super(key: key); @@ -63,15 +66,17 @@ class _RowDetailPageState extends State { }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 80, vertical: 40), - child: _PropertyList(), + child: _PropertyList(cellCache: widget.cellCache), ), ); } } class _PropertyList extends StatelessWidget { + final GridCellCache cellCache; final ScrollController _scrollController; _PropertyList({ + required this.cellCache, Key? key, }) : _scrollController = ScrollController(), super(key: key); @@ -89,7 +94,11 @@ class _PropertyList extends StatelessWidget { controller: _scrollController, itemCount: state.cellDatas.length, itemBuilder: (BuildContext context, int index) { - return _RowDetailCell(cellData: state.cellDatas[index]); + final cellDataContext = GridCellDataContext( + cellData: state.cellDatas[index], + cellCache: cellCache, + ); + return _RowDetailCell(cellDataContext: cellDataContext); }, separatorBuilder: (BuildContext context, int index) { return const VSpace(2); @@ -102,15 +111,16 @@ class _PropertyList extends StatelessWidget { } class _RowDetailCell extends StatelessWidget { - final GridCell cellData; - const _RowDetailCell({required this.cellData, Key? key}) : super(key: key); + final GridCellDataContext cellDataContext; + const _RowDetailCell({required this.cellDataContext, Key? key}) : super(key: key); @override Widget build(BuildContext context) { final theme = context.watch(); + final cell = buildGridCell( - cellData, - style: _buildCellStyle(theme, cellData.field.fieldType), + cellDataContext, + style: _buildCellStyle(theme, cellDataContext.fieldType), ); return SizedBox( height: 36, @@ -120,7 +130,7 @@ class _RowDetailCell extends StatelessWidget { children: [ SizedBox( width: 150, - child: FieldCellButton(field: cellData.field, onTap: () => _showFieldEditor(context)), + child: FieldCellButton(field: cellDataContext.field, onTap: () => _showFieldEditor(context)), ), const HSpace(10), Expanded( @@ -136,10 +146,10 @@ class _RowDetailCell extends StatelessWidget { void _showFieldEditor(BuildContext context) { FieldEditor( - gridId: cellData.gridId, + gridId: cellDataContext.gridId, fieldContextLoader: FieldContextLoaderAdaptor( - gridId: cellData.gridId, - field: cellData.field, + gridId: cellDataContext.gridId, + field: cellDataContext.field, ), ).show(context); } From 5af378c81087f1093d3b623f31c39d940749bddf Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 22 Apr 2022 23:36:39 +0800 Subject: [PATCH 04/12] chore: remove field listener in cell --- .../app_flowy/lib/startup/deps_resolver.dart | 20 ++--- .../application/grid/cell/cell_service.dart | 87 +++++++++++++++---- .../grid/cell/checkbox_cell_bloc.dart | 6 +- .../application/grid/cell/date_cell_bloc.dart | 8 +- .../grid/cell/number_cell_bloc.dart | 8 +- .../grid/cell/selection_cell_bloc.dart | 77 +++++++++------- .../application/grid/cell/text_cell_bloc.dart | 6 +- .../grid/src/widgets/cell/cell_builder.dart | 18 ++-- .../grid/src/widgets/cell/checkbox_cell.dart | 6 +- .../grid/src/widgets/cell/date_cell.dart | 6 +- .../grid/src/widgets/cell/number_cell.dart | 6 +- .../cell/selection_cell/selection_cell.dart | 12 +-- .../grid/src/widgets/cell/text_cell.dart | 6 +- .../grid/src/widgets/row/grid_row.dart | 4 +- .../grid/src/widgets/row/row_detail.dart | 20 ++--- 15 files changed, 180 insertions(+), 110 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index da5274b0ca..f8583046b6 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -168,34 +168,34 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => TextCellBloc( - cellDataContext: context, + cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => SelectionCellBloc( - cellDataContext: context, + cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => NumberCellBloc( - cellDataContext: context, + cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => DateCellBloc( - cellDataContext: context, + cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => CheckboxCellBloc( service: CellService(), - cellDataContext: cellData, + cellContext: cellData, ), ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index 9cf5ddd042..2156d86ebc 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -11,10 +11,10 @@ import 'package:freezed_annotation/freezed_annotation.dart'; part 'cell_service.freezed.dart'; -class GridCellDataContext { +class GridCellContext { GridCell cellData; GridCellCache cellCache; - GridCellDataContext({ + GridCellContext({ required this.cellData, required this.cellCache, }); @@ -30,15 +30,47 @@ class GridCellDataContext { FieldType get fieldType => cellData.field.fieldType; Field get field => cellData.field; + + GridCellCacheKey get cacheKey => GridCellCacheKey(rowId: cellData.rowId, fieldId: cellData.field.id); + + T? getCacheData() { + return cellCache.get(cacheKey); + } + + void setCacheData(dynamic data) { + cellCache.insert(GridCellCacheData(key: cacheKey, value: data)); + } + + void onFieldChanged(VoidCallback callback) { + cellCache.addListener(fieldId, rowId, callback); + } + + void removeListener() { + cellCache.removeListener(fieldId, rowId); + } } // key: rowId typedef CellDataMap = LinkedHashMap; -abstract class GridCellCacheData { - String get fieldId; - String get cacheKey; - dynamic get cacheData; +class GridCellCacheData { + GridCellCacheKey key; + dynamic value; + GridCellCacheData({ + required this.key, + required this.value, + }); +} + +class GridCellCacheKey { + final String fieldId; + final String rowId; + GridCellCacheKey({ + required this.fieldId, + required this.rowId, + }); + + String get cellId => "$rowId + $fieldId"; } abstract class GridCellFieldDelegate { @@ -49,33 +81,56 @@ class GridCellCache { final String gridId; final GridCellFieldDelegate fieldDelegate; + /// fieldId: {rowId: callback} + final Map> _cellListenerByFieldId = {}; + /// fieldId: {cacheKey: cacheData} - final Map> _cells = {}; + final Map> _cellCacheByFieldId = {}; GridCellCache({ required this.gridId, required this.fieldDelegate, }) { fieldDelegate.onFieldChanged((fieldId) { - _cells.remove(fieldId); + _cellCacheByFieldId.remove(fieldId); + final map = _cellListenerByFieldId[fieldId]; + if (map != null) { + for (final callback in map.values) { + callback(); + } + } }); } - void insert(T cacheData) { - var map = _cells[cacheData.fieldId]; + void addListener(String fieldId, String rowId, VoidCallback callback) { + var map = _cellListenerByFieldId[fieldId]; if (map == null) { - _cells[cacheData.fieldId] = {}; - map = _cells[cacheData.fieldId]; + _cellListenerByFieldId[fieldId] = {}; + map = _cellListenerByFieldId[fieldId]; } - map![cacheData.cacheKey] = cacheData.cacheData; + map![rowId] = callback; } - T? get(String fieldId, String cacheKey) { - final map = _cells[fieldId]; + void removeListener(String fieldId, String rowId) { + _cellListenerByFieldId[fieldId]?.remove(rowId); + } + + void insert(T item) { + var map = _cellCacheByFieldId[item.key.fieldId]; + if (map == null) { + _cellCacheByFieldId[item.key.fieldId] = {}; + map = _cellCacheByFieldId[item.key.fieldId]; + } + + map![item.key.cellId] = item.value; + } + + T? get(GridCellCacheKey key) { + final map = _cellCacheByFieldId[key.fieldId]; if (map == null) { return null; } else { - final object = map[cacheKey]; + final object = map[key.cellId]; if (object is T) { return object; } else { 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 11ab2d2d8a..5acf532af6 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 @@ -14,10 +14,10 @@ class CheckboxCellBloc extends Bloc { CheckboxCellBloc({ required CellService service, - required GridCellDataContext cellDataContext, + required GridCellContext cellContext, }) : _service = service, - _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), - super(CheckboxCellState.initial(cellDataContext.cellData)) { + _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), + super(CheckboxCellState.initial(cellContext.cellData)) { on( (event, emit) async { await event.map( 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 3f08ede31f..7f5f1fc808 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 @@ -14,11 +14,11 @@ class DateCellBloc extends Bloc { final CellListener _cellListener; final SingleFieldListener _fieldListener; - DateCellBloc({required GridCellDataContext cellDataContext}) + DateCellBloc({required GridCellContext cellContext}) : _service = CellService(), - _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), - _fieldListener = SingleFieldListener(fieldId: cellDataContext.fieldId), - super(DateCellState.initial(cellDataContext.cellData)) { + _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), + _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), + super(DateCellState.initial(cellContext.cellData)) { on( (event, emit) async { event.map( 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 9ebd59f1e2..b46d70cc8f 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 @@ -15,11 +15,11 @@ class NumberCellBloc extends Bloc { final SingleFieldListener _fieldListener; NumberCellBloc({ - required GridCellDataContext cellDataContext, + required GridCellContext cellContext, }) : _service = CellService(), - _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), - _fieldListener = SingleFieldListener(fieldId: cellDataContext.fieldId), - super(NumberCellState.initial(cellDataContext.cellData)) { + _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), + _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), + super(NumberCellState.initial(cellContext.cellData)) { on( (event, emit) async { await event.map( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index e5a50d478a..a10757d220 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -1,12 +1,14 @@ -import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; -import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; -import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; +import 'dart:async'; + import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'dart:async'; + +import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; part 'selection_cell_bloc.freezed.dart'; @@ -14,19 +16,21 @@ class SelectionCellBloc extends Bloc { final SelectOptionService _service; final CellListener _cellListener; final SingleFieldListener _fieldListener; + final GridCellContext _cellContext; SelectionCellBloc({ - required GridCellDataContext cellDataContext, + required GridCellContext cellContext, }) : _service = SelectOptionService(), - _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), - _fieldListener = SingleFieldListener(fieldId: cellDataContext.fieldId), - super(SelectionCellState.initial(cellDataContext.cellData)) { + _cellContext = cellContext, + _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), + _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), + super(SelectionCellState.initial(cellContext.cellData)) { on( (event, emit) async { await event.map( initial: (_InitialCell value) async { - _loadOptions(); _startListening(); + _loadOptions(); }, didReceiveOptions: (_DidReceiveOptions value) { emit(state.copyWith(options: value.options, selectedOptions: value.selectedOptions)); @@ -40,26 +44,35 @@ class SelectionCellBloc extends Bloc { Future close() async { await _cellListener.stop(); await _fieldListener.stop(); + _cellContext.removeListener(); return super.close(); } void _loadOptions() async { - final result = await _service.getOpitonContext( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - ); - if (isClosed) { - return; + var selectOptionContext = _cellContext.getCacheData(); + if (selectOptionContext == null) { + final result = await _service.getOpitonContext( + gridId: state.cellData.gridId, + fieldId: state.cellData.field.id, + rowId: state.cellData.rowId, + ); + if (isClosed) { + return; + } + + result.fold( + (newSelectOptionContext) { + _cellContext.setCacheData(newSelectOptionContext); + selectOptionContext = newSelectOptionContext; + }, + (err) => Log.error(err), + ); } - result.fold( - (selectOptionContext) => add(SelectionCellEvent.didReceiveOptions( - selectOptionContext.options, - selectOptionContext.selectOptions, - )), - (err) => Log.error(err), - ); + add(SelectionCellEvent.didReceiveOptions( + selectOptionContext!.options, + selectOptionContext!.selectOptions, + )); } void _startListening() { @@ -71,13 +84,15 @@ class SelectionCellBloc extends Bloc { }); _cellListener.start(); - _fieldListener.updateFieldNotifier?.addPublishListener((result) { - result.fold( - (field) => _loadOptions(), - (err) => Log.error(err), - ); - }); - _fieldListener.start(); + _cellContext.onFieldChanged(() => _loadOptions()); + + // _fieldListener.updateFieldNotifier?.addPublishListener((result) { + // result.fold( + // (field) => _loadOptions(), + // (err) => Log.error(err), + // ); + // }); + // _fieldListener.start(); } } 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 da7759d253..94cb749eb2 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 @@ -13,10 +13,10 @@ class TextCellBloc extends Bloc { final CellListener _cellListener; TextCellBloc({ - required GridCellDataContext cellDataContext, + required GridCellContext cellContext, }) : _service = CellService(), - _cellListener = CellListener(rowId: cellDataContext.rowId, fieldId: cellDataContext.fieldId), - super(TextCellState.initial(cellDataContext.cellData)) { + _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), + super(TextCellState.initial(cellContext.cellData)) { on( (event, emit) async { await event.map( 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 b66cea7b07..e95fcd9a53 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 @@ -8,22 +8,22 @@ import 'number_cell.dart'; import 'selection_cell/selection_cell.dart'; import 'text_cell.dart'; -GridCellWidget buildGridCell(GridCellDataContext cellDataContext, {GridCellStyle? style}) { - final key = ValueKey(cellDataContext.cellId); - final fieldType = cellDataContext.cellData.field.fieldType; +GridCellWidget buildGridCell(GridCellContext cellContext, {GridCellStyle? style}) { + final key = ValueKey(cellContext.cellId); + final fieldType = cellContext.cellData.field.fieldType; switch (fieldType) { case FieldType.Checkbox: - return CheckboxCell(cellDataContext: cellDataContext, key: key); + return CheckboxCell(cellContext: cellContext, key: key); case FieldType.DateTime: - return DateCell(cellDataContext: cellDataContext, key: key); + return DateCell(cellContext: cellContext, key: key); case FieldType.MultiSelect: - return MultiSelectCell(cellDataContext: cellDataContext, style: style, key: key); + return MultiSelectCell(cellContext: cellContext, style: style, key: key); case FieldType.Number: - return NumberCell(cellDataContext: cellDataContext, key: key); + return NumberCell(cellContext: cellContext, key: key); case FieldType.RichText: - return GridTextCell(cellDataContext: cellDataContext, style: style, key: key); + return GridTextCell(cellContext: cellContext, style: style, key: key); case FieldType.SingleSelect: - return SingleSelectCell(cellDataContext: cellDataContext, style: style, key: key); + return SingleSelectCell(cellContext: cellContext, style: style, key: key); default: throw UnimplementedError; } 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 80e0468274..991b56a832 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,10 +7,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_builder.dart'; class CheckboxCell extends GridCellWidget { - final GridCellDataContext cellDataContext; + final GridCellContext cellContext; CheckboxCell({ - required this.cellDataContext, + required this.cellContext, Key? key, }) : super(key: key); @@ -23,7 +23,7 @@ class _CheckboxCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellDataContext)..add(const CheckboxCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellContext)..add(const CheckboxCellEvent.initial()); super.initState(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart index 2be56133f2..a3cc807266 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart @@ -14,10 +14,10 @@ abstract class GridCellDelegate { } class DateCell extends GridCellWidget { - final GridCellDataContext cellDataContext; + final GridCellContext cellContext; DateCell({ - required this.cellDataContext, + required this.cellContext, Key? key, }) : super(key: key); @@ -30,7 +30,7 @@ class _DateCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellDataContext)..add(const DateCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellContext)..add(const DateCellEvent.initial()); super.initState(); } 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 1b57a69ec8..168d2258d3 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 @@ -8,10 +8,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_builder.dart'; class NumberCell extends GridCellWidget { - final GridCellDataContext cellDataContext; + final GridCellContext cellContext; NumberCell({ - required this.cellDataContext, + required this.cellContext, Key? key, }) : super(key: key); @@ -27,7 +27,7 @@ class _NumberCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellDataContext)..add(const NumberCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellContext)..add(const NumberCellEvent.initial()); _controller = TextEditingController(text: _cellBloc.state.content); _focusNode = FocusNode(); _focusNode.addListener(() { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index 3402c05060..41ea4b2002 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -18,11 +18,11 @@ class SelectOptionCellStyle extends GridCellStyle { } class SingleSelectCell extends GridCellWidget { - final GridCellDataContext cellDataContext; + final GridCellContext cellContext; late final SelectOptionCellStyle? cellStyle; SingleSelectCell({ - required this.cellDataContext, + required this.cellContext, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -42,7 +42,7 @@ class _SingleSelectCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellDataContext)..add(const SelectionCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellContext)..add(const SelectionCellEvent.initial()); super.initState(); } @@ -89,11 +89,11 @@ class _SingleSelectCellState extends State { //---------------------------------------------------------------- class MultiSelectCell extends GridCellWidget { - final GridCellDataContext cellDataContext; + final GridCellContext cellContext; late final SelectOptionCellStyle? cellStyle; MultiSelectCell({ - required this.cellDataContext, + required this.cellContext, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -113,7 +113,7 @@ class _MultiSelectCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellDataContext)..add(const SelectionCellEvent.initial()); + _cellBloc = getIt(param1: widget.cellContext)..add(const SelectionCellEvent.initial()); super.initState(); } 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 7a32583b20..6d77f5f2cf 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 GridCellDataContext cellDataContext; + final GridCellContext cellContext; late final GridTextCellStyle? cellStyle; GridTextCell({ - required this.cellDataContext, + required this.cellContext, GridCellStyle? style, Key? key, }) : super(key: key) { @@ -41,7 +41,7 @@ class _GridTextCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellDataContext); + _cellBloc = getIt(param1: widget.cellContext); _cellBloc.add(const TextCellEvent.initial()); _controller = TextEditingController(text: _cellBloc.state.content); _focusNode = FocusNode(); 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 a543693f82..cc56d3bed0 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 @@ -178,14 +178,14 @@ class _RowCells extends StatelessWidget { expander = _CellExpander(onExpand: onExpand); } - final cellDataContext = GridCellDataContext( + final cellContext = GridCellContext( cellData: cellData, cellCache: cellCache, ); return CellContainer( width: cellData.field.width.toDouble(), - child: buildGridCell(cellDataContext), + child: buildGridCell(cellContext), expander: expander, ); }, 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 81d64d87da..e61516ba4f 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 @@ -94,11 +94,11 @@ class _PropertyList extends StatelessWidget { controller: _scrollController, itemCount: state.cellDatas.length, itemBuilder: (BuildContext context, int index) { - final cellDataContext = GridCellDataContext( + final cellContext = GridCellContext( cellData: state.cellDatas[index], cellCache: cellCache, ); - return _RowDetailCell(cellDataContext: cellDataContext); + return _RowDetailCell(cellContext: cellContext); }, separatorBuilder: (BuildContext context, int index) { return const VSpace(2); @@ -111,16 +111,16 @@ class _PropertyList extends StatelessWidget { } class _RowDetailCell extends StatelessWidget { - final GridCellDataContext cellDataContext; - const _RowDetailCell({required this.cellDataContext, Key? key}) : super(key: key); + final GridCellContext cellContext; + const _RowDetailCell({required this.cellContext, Key? key}) : super(key: key); @override Widget build(BuildContext context) { final theme = context.watch(); final cell = buildGridCell( - cellDataContext, - style: _buildCellStyle(theme, cellDataContext.fieldType), + cellContext, + style: _buildCellStyle(theme, cellContext.fieldType), ); return SizedBox( height: 36, @@ -130,7 +130,7 @@ class _RowDetailCell extends StatelessWidget { children: [ SizedBox( width: 150, - child: FieldCellButton(field: cellDataContext.field, onTap: () => _showFieldEditor(context)), + child: FieldCellButton(field: cellContext.field, onTap: () => _showFieldEditor(context)), ), const HSpace(10), Expanded( @@ -146,10 +146,10 @@ class _RowDetailCell extends StatelessWidget { void _showFieldEditor(BuildContext context) { FieldEditor( - gridId: cellDataContext.gridId, + gridId: cellContext.gridId, fieldContextLoader: FieldContextLoaderAdaptor( - gridId: cellDataContext.gridId, - field: cellDataContext.field, + gridId: cellContext.gridId, + field: cellContext.field, ), ).show(context); } From ec16fbe551fd59066afa3c0fb9f64b6c7414b8ee Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 23 Apr 2022 15:11:05 +0800 Subject: [PATCH 05/12] chore: cache cell data --- .../application/grid/cell/cell_service.dart | 44 ++++++++++--------- .../grid/src/widgets/row/grid_row.dart | 2 +- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index 2156d86ebc..49a04586b3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -14,10 +14,16 @@ part 'cell_service.freezed.dart'; class GridCellContext { GridCell cellData; GridCellCache cellCache; + late GridCellCacheKey _cacheKey; GridCellContext({ required this.cellData, required this.cellCache, - }); + }) { + _cacheKey = GridCellCacheKey( + objectId: "$hashCode", + fieldId: cellData.field.id, + ); + } String get gridId => cellData.gridId; @@ -31,22 +37,22 @@ class GridCellContext { Field get field => cellData.field; - GridCellCacheKey get cacheKey => GridCellCacheKey(rowId: cellData.rowId, fieldId: cellData.field.id); + GridCellCacheKey get cacheKey => _cacheKey; T? getCacheData() { return cellCache.get(cacheKey); } void setCacheData(dynamic data) { - cellCache.insert(GridCellCacheData(key: cacheKey, value: data)); + cellCache.insert(GridCellCacheData(key: cacheKey, object: data)); } void onFieldChanged(VoidCallback callback) { - cellCache.addListener(fieldId, rowId, callback); + cellCache.addListener(cacheKey, callback); } void removeListener() { - cellCache.removeListener(fieldId, rowId); + cellCache.removeListener(cacheKey); } } @@ -55,22 +61,20 @@ typedef CellDataMap = LinkedHashMap; class GridCellCacheData { GridCellCacheKey key; - dynamic value; + dynamic object; GridCellCacheData({ required this.key, - required this.value, + required this.object, }); } class GridCellCacheKey { final String fieldId; - final String rowId; + final String objectId; GridCellCacheKey({ required this.fieldId, - required this.rowId, + required this.objectId, }); - - String get cellId => "$rowId + $fieldId"; } abstract class GridCellFieldDelegate { @@ -101,18 +105,18 @@ class GridCellCache { }); } - void addListener(String fieldId, String rowId, VoidCallback callback) { - var map = _cellListenerByFieldId[fieldId]; + void addListener(GridCellCacheKey cacheKey, VoidCallback callback) { + var map = _cellListenerByFieldId[cacheKey.fieldId]; if (map == null) { - _cellListenerByFieldId[fieldId] = {}; - map = _cellListenerByFieldId[fieldId]; + _cellListenerByFieldId[cacheKey.fieldId] = {}; + map = _cellListenerByFieldId[cacheKey.fieldId]; } - map![rowId] = callback; + map![cacheKey.objectId] = callback; } - void removeListener(String fieldId, String rowId) { - _cellListenerByFieldId[fieldId]?.remove(rowId); + void removeListener(GridCellCacheKey cacheKey) { + _cellListenerByFieldId[cacheKey.fieldId]?.remove(cacheKey.objectId); } void insert(T item) { @@ -122,7 +126,7 @@ class GridCellCache { map = _cellCacheByFieldId[item.key.fieldId]; } - map![item.key.cellId] = item.value; + map![item.key.objectId] = item.object; } T? get(GridCellCacheKey key) { @@ -130,7 +134,7 @@ class GridCellCache { if (map == null) { return null; } else { - final object = map[key.cellId]; + final object = map[key.objectId]; if (object is T) { return object; } 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 cc56d3bed0..f5ebba8921 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 @@ -159,7 +159,7 @@ class _RowCells extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder( - buildWhen: (previous, current) => previous.cellDataMap != current.cellDataMap, + buildWhen: (previous, current) => previous.cellDataMap.length != current.cellDataMap.length, builder: (context, state) { return Row( mainAxisSize: MainAxisSize.min, From be49784f5aac8b19d38d9e63fc5c35b06698bfcd Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 23 Apr 2022 22:41:47 +0800 Subject: [PATCH 06/12] chore: refactor cell context --- .../app_flowy/lib/startup/deps_resolver.dart | 10 +- .../application/grid/cell/cell_service.dart | 163 +++++++++++++----- .../grid/cell/checkbox_cell_bloc.dart | 50 ++---- .../application/grid/cell/date_cell_bloc.dart | 57 ++---- .../grid/cell/number_cell_bloc.dart | 60 ++----- .../grid/cell/select_option_service.dart | 70 ++++---- .../grid/cell/selection_cell_bloc.dart | 91 +++------- .../grid/cell/selection_editor_bloc.dart | 130 +++++--------- .../application/grid/cell/text_cell_bloc.dart | 2 +- .../application/grid/row/row_bloc.dart | 6 +- .../application/grid/row/row_detail_bloc.dart | 8 +- .../application/grid/row/row_service.dart | 10 +- .../grid/src/widgets/cell/cell_builder.dart | 41 ++++- .../cell/selection_cell/selection_cell.dart | 13 +- .../cell/selection_cell/selection_editor.dart | 20 +-- .../grid/src/widgets/row/grid_row.dart | 17 +- .../grid/src/widgets/row/row_detail.dart | 33 ++-- 17 files changed, 344 insertions(+), 437 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index f8583046b6..10b51438e4 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -16,8 +16,10 @@ import 'package:app_flowy/user/presentation/router.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart'; import 'package:get_it/get_it.dart'; @@ -174,25 +176,25 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam, void>( (context, _) => SelectionCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam, void>( (context, _) => NumberCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam, void>( (context, _) => DateCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam, void>( (cellData, _) => CheckboxCellBloc( service: CellService(), cellContext: cellData, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index 49a04586b3..224e8b0d3a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -9,55 +9,126 @@ import 'package:flowy_sdk/protobuf/flowy-grid/cell_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'; + part 'cell_service.freezed.dart'; -class GridCellContext { - GridCell cellData; - GridCellCache cellCache; +class GridCellContext { + final GridCell gridCell; + final GridCellCache cellCache; late GridCellCacheKey _cacheKey; + final GridCellDataLoader cellDataLoader; + + final CellListener _cellListener; + final CellService _cellService = CellService(); + final ValueNotifier _cellDataNotifier = ValueNotifier(null); + GridCellContext({ - required this.cellData, + required this.gridCell, required this.cellCache, - }) { + required this.cellDataLoader, + }) : _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id) { + _cellListener.updateCellNotifier?.addPublishListener((result) { + result.fold( + (notification) => _loadData(), + (err) => Log.error(err), + ); + }); + + _cellListener.start(); + _cacheKey = GridCellCacheKey( objectId: "$hashCode", - fieldId: cellData.field.id, + fieldId: gridCell.field.id, ); } - String get gridId => cellData.gridId; + String get gridId => gridCell.gridId; - String get cellId => cellData.rowId + (cellData.cell?.fieldId ?? ""); + String get rowId => gridCell.rowId; - String get rowId => cellData.rowId; + String get cellId => gridCell.rowId + gridCell.field.id; - String get fieldId => cellData.field.id; + String get fieldId => gridCell.field.id; - FieldType get fieldType => cellData.field.fieldType; + Field get field => gridCell.field; - Field get field => cellData.field; + FieldType get fieldType => gridCell.field.fieldType; GridCellCacheKey get cacheKey => _cacheKey; - T? getCacheData() { - return cellCache.get(cacheKey); + T? getCellData() { + final data = cellCache.get(cacheKey); + if (data == null) { + _loadData(); + } + return data; } - void setCacheData(dynamic data) { + void setCellData(T? data) { cellCache.insert(GridCellCacheData(key: cacheKey, object: data)); } + void saveCellData(String data) { + _cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data); + } + + void _loadData() { + // It may trigger getCell multiple times. Use cancel operation to fix this. + cellDataLoader.loadData().then((data) { + _cellDataNotifier.value = data; + setCellData(data); + }); + } + void onFieldChanged(VoidCallback callback) { cellCache.addListener(cacheKey, callback); } + void onCellChanged(void Function(T) callback) { + _cellDataNotifier.addListener(() { + final value = _cellDataNotifier.value; + if (value is T) { + callback(value); + } + }); + } + void removeListener() { cellCache.removeListener(cacheKey); } } +abstract class GridCellDataLoader { + Future loadData(); +} + +class DefaultCellDataLoader implements GridCellDataLoader { + final CellService service = CellService(); + final GridCell gridCell; + + DefaultCellDataLoader({ + required this.gridCell, + }); + + @override + Future loadData() { + final fut = service.getCell( + gridId: gridCell.gridId, + fieldId: gridCell.field.id, + rowId: gridCell.rowId, + ); + return fut.then((result) { + return result.fold((data) => data, (err) { + Log.error(err); + return null; + }); + }); + } +} + // key: rowId -typedef CellDataMap = LinkedHashMap; +typedef GridCellMap = LinkedHashMap; class GridCellCacheData { GridCellCacheKey key; @@ -175,41 +246,41 @@ class CellService { } } -class CellCache { - final CellService _cellService; - final HashMap _cellDataMap = HashMap(); +// class CellCache { +// final CellService _cellService; +// final HashMap _cellDataMap = HashMap(); - CellCache() : _cellService = CellService(); +// CellCache() : _cellService = CellService(); - Future> getCellData(GridCell identifier) async { - final cellId = _cellId(identifier); - final Cell? data = _cellDataMap[cellId]; - if (data != null) { - return Future(() => Some(data)); - } +// Future> getCellData(GridCell identifier) async { +// final cellId = _cellId(identifier); +// final Cell? data = _cellDataMap[cellId]; +// if (data != null) { +// return Future(() => Some(data)); +// } - final result = await _cellService.getCell( - gridId: identifier.gridId, - fieldId: identifier.field.id, - rowId: identifier.rowId, - ); +// final result = await _cellService.getCell( +// gridId: identifier.gridId, +// fieldId: identifier.field.id, +// rowId: identifier.rowId, +// ); - return result.fold( - (cell) { - _cellDataMap[_cellId(identifier)] = cell; - return Some(cell); - }, - (err) { - Log.error(err); - return none(); - }, - ); - } +// return result.fold( +// (cell) { +// _cellDataMap[_cellId(identifier)] = cell; +// return Some(cell); +// }, +// (err) { +// Log.error(err); +// return none(); +// }, +// ); +// } - String _cellId(GridCell identifier) { - return "${identifier.rowId}/${identifier.field.id}"; - } -} +// String _cellId(GridCell identifier) { +// return "${identifier.rowId}/${identifier.field.id}"; +// } +// } @freezed class GridCell with _$GridCell { 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 5acf532af6..5a36c7f5a8 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 @@ -1,5 +1,3 @@ -import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -9,15 +7,13 @@ import 'cell_service.dart'; part 'checkbox_cell_bloc.freezed.dart'; class CheckboxCellBloc extends Bloc { - final CellService _service; - final CellListener _cellListener; + final GridCellContext _cellContext; CheckboxCellBloc({ required CellService service, - required GridCellContext cellContext, - }) : _service = service, - _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), - super(CheckboxCellState.initial(cellContext.cellData)) { + required GridCellContext cellContext, + }) : _cellContext = cellContext, + super(CheckboxCellState.initial(cellContext)) { on( (event, emit) async { await event.map( @@ -37,42 +33,19 @@ class CheckboxCellBloc extends Bloc { @override Future close() async { - await _cellListener.stop(); return super.close(); } void _startListening() { - _cellListener.updateCellNotifier?.addPublishListener((result) { - result.fold( - (notificationData) async => await _loadCellData(), - (err) => Log.error(err), - ); + _cellContext.onCellChanged((cell) { + if (!isClosed) { + add(CheckboxCellEvent.didReceiveCellUpdate(cell)); + } }); - _cellListener.start(); - } - - Future _loadCellData() async { - final result = await _service.getCell( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - ); - if (isClosed) { - return; - } - result.fold( - (cell) => add(CheckboxCellEvent.didReceiveCellUpdate(cell)), - (err) => Log.error(err), - ); } void _updateCellData() { - _service.updateCell( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - data: !state.isSelected ? "Yes" : "No", - ); + _cellContext.saveCellData(!state.isSelected ? "Yes" : "No"); } } @@ -86,12 +59,11 @@ class CheckboxCellEvent with _$CheckboxCellEvent { @freezed class CheckboxCellState with _$CheckboxCellState { const factory CheckboxCellState({ - required GridCell cellData, required bool isSelected, }) = _CheckboxCellState; - factory CheckboxCellState.initial(GridCell cellData) { - return CheckboxCellState(cellData: cellData, isSelected: _isSelected(cellData.cell)); + factory CheckboxCellState.initial(GridCellContext context) { + return CheckboxCellState(isSelected: _isSelected(context.getCellData())); } } 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 7f5f1fc808..b1eacce788 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,3 @@ -import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field; @@ -10,15 +9,12 @@ import 'cell_service.dart'; part 'date_cell_bloc.freezed.dart'; class DateCellBloc extends Bloc { - final CellService _service; - final CellListener _cellListener; final SingleFieldListener _fieldListener; + final GridCellContext cellContext; - DateCellBloc({required GridCellContext cellContext}) - : _service = CellService(), - _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), - _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), - super(DateCellState.initial(cellContext.cellData)) { + DateCellBloc({required this.cellContext}) + : _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), + super(DateCellState.initial(cellContext)) { on( (event, emit) async { event.map( @@ -30,13 +26,11 @@ class DateCellBloc extends Bloc { }, didReceiveCellUpdate: (_DidReceiveCellUpdate value) { emit(state.copyWith( - cellData: state.cellData.copyWith(cell: value.cell), content: value.cell.content, )); }, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { emit(state.copyWith(field: value.field)); - _loadCellData(); }, ); }, @@ -45,19 +39,16 @@ class DateCellBloc extends Bloc { @override Future close() async { - await _cellListener.stop(); await _fieldListener.stop(); return super.close(); } void _startListening() { - _cellListener.updateCellNotifier?.addPublishListener((result) { - result.fold( - (notificationData) => _loadCellData(), - (err) => Log.error(err), - ); - }, listenWhen: () => !isClosed); - _cellListener.start(); + cellContext.onCellChanged((cell) { + if (!isClosed) { + add(DateCellEvent.didReceiveCellUpdate(cell)); + } + }); _fieldListener.updateFieldNotifier?.addPublishListener((result) { result.fold( @@ -68,29 +59,9 @@ class DateCellBloc extends Bloc { _fieldListener.start(); } - Future _loadCellData() async { - final result = await _service.getCell( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - ); - if (isClosed) { - return; - } - result.fold( - (cell) => add(DateCellEvent.didReceiveCellUpdate(cell)), - (err) => Log.error(err), - ); - } - void _updateCellData(DateTime day) { final data = day.millisecondsSinceEpoch ~/ 1000; - _service.updateCell( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - data: data.toString(), - ); + cellContext.saveCellData(data.toString()); } } @@ -105,15 +76,13 @@ class DateCellEvent with _$DateCellEvent { @freezed class DateCellState with _$DateCellState { const factory DateCellState({ - required GridCell cellData, required String content, required Field field, DateTime? selectedDay, }) = _DateCellState; - factory DateCellState.initial(GridCell cellData) => DateCellState( - cellData: cellData, - field: cellData.field, - content: cellData.cell?.content ?? "", + factory DateCellState.initial(GridCellContext context) => DateCellState( + field: context.field, + content: context.getCellData()?.content ?? "", ); } 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 b46d70cc8f..28eca05498 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 @@ -1,4 +1,3 @@ -import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; @@ -10,16 +9,13 @@ import 'cell_service.dart'; part 'number_cell_bloc.freezed.dart'; class NumberCellBloc extends Bloc { - final CellService _service; - final CellListener _cellListener; + final GridCellContext cellContext; final SingleFieldListener _fieldListener; NumberCellBloc({ - required GridCellContext cellContext, - }) : _service = CellService(), - _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), - _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), - super(NumberCellState.initial(cellContext.cellData)) { + required this.cellContext, + }) : _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), + super(NumberCellState.initial(cellContext)) { on( (event, emit) async { await event.map( @@ -38,60 +34,31 @@ class NumberCellBloc extends Bloc { } Future _updateCellValue(_UpdateCell value, Emitter emit) async { - final result = await _service.updateCell( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - data: value.text, - ); - result.fold( - (field) => _getCellData(), - (err) => Log.error(err), - ); + cellContext.saveCellData(value.text); + cellContext.reloadCellData(); } @override Future close() async { - await _cellListener.stop(); await _fieldListener.stop(); return super.close(); } void _startListening() { - _cellListener.updateCellNotifier?.addPublishListener((result) { - result.fold( - (notificationData) async { - await _getCellData(); - }, - (err) => Log.error(err), - ); + cellContext.onCellChanged((cell) { + if (!isClosed) { + add(NumberCellEvent.didReceiveCellUpdate(cell)); + } }); - _cellListener.start(); _fieldListener.updateFieldNotifier?.addPublishListener((result) { result.fold( - (field) => _getCellData(), + (field) => cellContext.reloadCellData(), (err) => Log.error(err), ); }); _fieldListener.start(); } - - Future _getCellData() async { - final result = await _service.getCell( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - ); - - if (isClosed) { - return; - } - result.fold( - (cell) => add(NumberCellEvent.didReceiveCellUpdate(cell)), - (err) => Log.error(err), - ); - } } @freezed @@ -104,11 +71,10 @@ class NumberCellEvent with _$NumberCellEvent { @freezed class NumberCellState with _$NumberCellState { const factory NumberCellState({ - required GridCell cellData, required String content, }) = _NumberCellState; - factory NumberCellState.initial(GridCell cellData) { - return NumberCellState(cellData: cellData, content: cellData.cell?.content ?? ""); + factory NumberCellState.initial(GridCellContext context) { + return NumberCellState(content: context.getCellData().cell?.content ?? ""); } } 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 41c496c373..aaac04ee49 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 @@ -1,19 +1,43 @@ -import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; -import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:dartz/dartz.dart'; 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/selection_type_option.pb.dart'; -class SelectOptionService { - SelectOptionService(); +import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; - Future> create({ - required String gridId, - required String fieldId, - required String rowId, - required String name, - }) { +import 'cell_service.dart'; + +class SelectOptionCellDataLoader implements GridCellDataLoader { + 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; + }, + ); + }); + } +} + +class SelectOptionService { + final GridCell gridCell; + SelectOptionService({required this.gridCell}); + + String get gridId => gridCell.gridId; + String get fieldId => gridCell.field.id; + String get rowId => gridCell.rowId; + + Future> create({required String name}) { return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then( (result) { return result.fold( @@ -34,9 +58,6 @@ class SelectOptionService { } Future> update({ - required String gridId, - required String fieldId, - required String rowId, required SelectOption option, }) { final cellIdentifier = CellIdentifierPayload.create() @@ -50,9 +71,6 @@ class SelectOptionService { } Future> delete({ - required String gridId, - required String fieldId, - required String rowId, required SelectOption option, }) { final cellIdentifier = CellIdentifierPayload.create() @@ -67,11 +85,7 @@ class SelectOptionService { return GridEventUpdateSelectOption(payload).send(); } - Future> getOpitonContext({ - required String gridId, - required String fieldId, - required String rowId, - }) { + Future> getOpitonContext() { final payload = CellIdentifierPayload.create() ..gridId = gridId ..fieldId = fieldId @@ -80,12 +94,7 @@ class SelectOptionService { return GridEventGetSelectOptionContext(payload).send(); } - Future> select({ - required String gridId, - required String fieldId, - required String rowId, - required String optionId, - }) { + Future> select({required String optionId}) { final payload = SelectOptionCellChangesetPayload.create() ..gridId = gridId ..fieldId = fieldId @@ -94,12 +103,7 @@ class SelectOptionService { return GridEventUpdateCellSelectOption(payload).send(); } - Future> unSelect({ - required String gridId, - required String fieldId, - required String rowId, - required String optionId, - }) { + Future> unSelect({required String optionId}) { final payload = SelectOptionCellChangesetPayload.create() ..gridId = gridId ..fieldId = fieldId diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index a10757d220..6a4a038ac4 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -1,39 +1,31 @@ import 'dart:async'; - -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.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/cell_service.dart'; -import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; part 'selection_cell_bloc.freezed.dart'; class SelectionCellBloc extends Bloc { - final SelectOptionService _service; - final CellListener _cellListener; final SingleFieldListener _fieldListener; - final GridCellContext _cellContext; + final GridCellContext cellContext; SelectionCellBloc({ - required GridCellContext cellContext, - }) : _service = SelectOptionService(), - _cellContext = cellContext, - _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), - _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), - super(SelectionCellState.initial(cellContext.cellData)) { + required this.cellContext, + }) : _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), + super(SelectionCellState.initial(cellContext)) { on( (event, emit) async { await event.map( initial: (_InitialCell value) async { _startListening(); - _loadOptions(); }, didReceiveOptions: (_DidReceiveOptions value) { - emit(state.copyWith(options: value.options, selectedOptions: value.selectedOptions)); + emit(state.copyWith( + options: value.options, + selectedOptions: value.selectedOptions, + )); }, ); }, @@ -42,57 +34,22 @@ class SelectionCellBloc extends Bloc { @override Future close() async { - await _cellListener.stop(); await _fieldListener.stop(); - _cellContext.removeListener(); + cellContext.removeListener(); return super.close(); } - void _loadOptions() async { - var selectOptionContext = _cellContext.getCacheData(); - if (selectOptionContext == null) { - final result = await _service.getOpitonContext( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - ); - if (isClosed) { - return; - } - - result.fold( - (newSelectOptionContext) { - _cellContext.setCacheData(newSelectOptionContext); - selectOptionContext = newSelectOptionContext; - }, - (err) => Log.error(err), - ); - } - - add(SelectionCellEvent.didReceiveOptions( - selectOptionContext!.options, - selectOptionContext!.selectOptions, - )); - } - void _startListening() { - _cellListener.updateCellNotifier?.addPublishListener((result) { - result.fold( - (notificationData) => _loadOptions(), - (err) => Log.error(err), - ); + cellContext.onCellChanged((selectOptionContext) { + if (!isClosed) { + add(SelectionCellEvent.didReceiveOptions( + selectOptionContext.options, + selectOptionContext.selectOptions, + )); + } }); - _cellListener.start(); - _cellContext.onFieldChanged(() => _loadOptions()); - - // _fieldListener.updateFieldNotifier?.addPublishListener((result) { - // result.fold( - // (field) => _loadOptions(), - // (err) => Log.error(err), - // ); - // }); - // _fieldListener.start(); + cellContext.onFieldChanged(() => cellContext.reloadCellData()); } } @@ -108,14 +65,16 @@ class SelectionCellEvent with _$SelectionCellEvent { @freezed class SelectionCellState with _$SelectionCellState { const factory SelectionCellState({ - required GridCell cellData, required List options, required List selectedOptions, }) = _SelectionCellState; - factory SelectionCellState.initial(GridCell cellData) => SelectionCellState( - cellData: cellData, - options: [], - selectedOptions: [], - ); + factory SelectionCellState.initial(GridCellContext context) { + final data = context.getCellData(); + + return SelectionCellState( + options: data?.options ?? [], + selectedOptions: data?.selectOptions ?? [], + ); + } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index 8abd379cb9..b7eb32d18e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -13,28 +13,19 @@ part 'selection_editor_bloc.freezed.dart'; class SelectOptionEditorBloc extends Bloc { final SelectOptionService _selectOptionService; - final SingleFieldListener _fieldListener; - final CellListener _cellListener; + final GridCellContext cellContext; Timer? _delayOperation; SelectOptionEditorBloc({ - required GridCell cellData, - required List options, - required List selectedOptions, - }) : _selectOptionService = SelectOptionService(), - _fieldListener = SingleFieldListener(fieldId: cellData.field.id), - _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - super(SelectOptionEditorState.initial(cellData, options, selectedOptions)) { + required this.cellContext, + }) : _selectOptionService = SelectOptionService(gridCell: cellContext.gridCell), + super(SelectOptionEditorState.initial(cellContext)) { on( (event, emit) async { await event.map( initial: (_Initial value) async { _startListening(); }, - didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - emit(state.copyWith(field: value.field)); - _loadOptions(); - }, didReceiveOptions: (_DidReceiveOptions value) { emit(state.copyWith( options: value.options, @@ -61,26 +52,17 @@ class SelectOptionEditorBloc extends Bloc close() async { _delayOperation?.cancel(); - await _fieldListener.stop(); - await _cellListener.stop(); + cellContext.removeListener(); return super.close(); } void _createOption(String name) async { - final result = await _selectOptionService.create( - gridId: state.gridId, - fieldId: state.field.id, - rowId: state.rowId, - name: name, - ); - result.fold((l) => _loadOptions(), (err) => Log.error(err)); + final result = await _selectOptionService.create(name: name); + result.fold((l) => {}, (err) => Log.error(err)); } void _deleteOption(SelectOption option) async { final result = await _selectOptionService.delete( - gridId: state.gridId, - fieldId: state.field.id, - rowId: state.rowId, option: option, ); @@ -89,9 +71,6 @@ class SelectOptionEditorBloc extends Bloc option.id == optionId); if (hasSelected != null) { - _selectOptionService.unSelect( - gridId: state.gridId, - fieldId: state.field.id, - rowId: state.rowId, - optionId: optionId, - ); + _selectOptionService.unSelect(optionId: optionId); } else { - _selectOptionService.select( - gridId: state.gridId, - fieldId: state.field.id, - rowId: state.rowId, - optionId: optionId, - ); + _selectOptionService.select(optionId: optionId); } } - void _loadOptions() async { - _delayOperation?.cancel(); - _delayOperation = Timer( - const Duration(milliseconds: 1), - () async { - final result = await _selectOptionService.getOpitonContext( - gridId: state.gridId, - fieldId: state.field.id, - rowId: state.rowId, - ); - if (isClosed) { - return; - } + // void _loadOptions() async { + // _delayOperation?.cancel(); + // _delayOperation = Timer( + // const Duration(milliseconds: 1), + // () async { + // final result = await _selectOptionService.getOpitonContext(); + // if (isClosed) { + // return; + // } - result.fold( - (selectOptionContext) => add(SelectOptionEditorEvent.didReceiveOptions( - selectOptionContext.options, - selectOptionContext.selectOptions, - )), - (err) => Log.error(err), - ); - }, - ); - } + // result.fold( + // (selectOptionContext) => add(SelectOptionEditorEvent.didReceiveOptions( + // selectOptionContext.options, + // selectOptionContext.selectOptions, + // )), + // (err) => Log.error(err), + // ); + // }, + // ); + // } void _startListening() { - _cellListener.updateCellNotifier?.addPublishListener((result) { - result.fold( - (notificationData) => _loadOptions(), - (err) => Log.error(err), - ); + cellContext.onCellChanged((selectOptionContext) { + if (!isClosed) { + add(SelectOptionEditorEvent.didReceiveOptions( + selectOptionContext.options, + selectOptionContext.selectOptions, + )); + } }); - _cellListener.start(); - _fieldListener.updateFieldNotifier?.addPublishListener((result) { - result.fold( - (field) => add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)), - (err) => Log.error(err), - ); - }, listenWhen: () => !isClosed); - _fieldListener.start(); + cellContext.onFieldChanged(() => cellContext.reloadCellData()); } } @freezed class SelectOptionEditorEvent with _$SelectOptionEditorEvent { const factory SelectOptionEditorEvent.initial() = _Initial; - const factory SelectOptionEditorEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; const factory SelectOptionEditorEvent.didReceiveOptions( List options, List selectedOptions) = _DidReceiveOptions; const factory SelectOptionEditorEvent.newOption(String optionName) = _NewOption; @@ -176,24 +135,15 @@ class SelectOptionEditorEvent with _$SelectOptionEditorEvent { @freezed class SelectOptionEditorState with _$SelectOptionEditorState { const factory SelectOptionEditorState({ - required String gridId, - required Field field, - required String rowId, required List options, required List selectedOptions, }) = _SelectOptionEditorState; - factory SelectOptionEditorState.initial( - GridCell cellData, - List options, - List selectedOptions, - ) { + factory SelectOptionEditorState.initial(GridCellContext context) { + final data = context.getCellData(); return SelectOptionEditorState( - gridId: cellData.gridId, - field: cellData.field, - rowId: cellData.rowId, - options: options, - selectedOptions: selectedOptions, + options: data?.options ?? [], + selectedOptions: data?.selectOptions ?? [], ); } } 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 94cb749eb2..a051eca2d5 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 @@ -16,7 +16,7 @@ class TextCellBloc extends Bloc { required GridCellContext cellContext, }) : _service = CellService(), _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), - super(TextCellState.initial(cellContext.cellData)) { + super(TextCellState.initial(cellContext.gridCell)) { on( (event, emit) async { await event.map( 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 fd83974d68..08634774ba 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 @@ -57,17 +57,17 @@ class RowBloc extends Bloc { class RowEvent with _$RowEvent { const factory RowEvent.initial() = _InitialRow; const factory RowEvent.createRow() = _CreateRow; - const factory RowEvent.didReceiveCellDatas(CellDataMap cellData) = _DidReceiveCellDatas; + const factory RowEvent.didReceiveCellDatas(GridCellMap cellData) = _DidReceiveCellDatas; } @freezed class RowState with _$RowState { const factory RowState({ required GridRow rowData, - required CellDataMap cellDataMap, + required GridCellMap cellDataMap, }) = _RowState; - factory RowState.initial(GridRow rowData, CellDataMap cellDataMap) => RowState( + factory RowState.initial(GridRow rowData, GridCellMap cellDataMap) => RowState( rowData: rowData, cellDataMap: cellDataMap, ); 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 57895888f0..96ffac61ab 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 @@ -24,7 +24,7 @@ class RowDetailBloc extends Bloc { _loadCellData(); }, didReceiveCellDatas: (_DidReceiveCellDatas value) { - emit(state.copyWith(cellDatas: value.cellDatas)); + emit(state.copyWith(gridCells: value.gridCells)); }, ); }, @@ -58,16 +58,16 @@ class RowDetailBloc extends Bloc { @freezed class RowDetailEvent with _$RowDetailEvent { const factory RowDetailEvent.initial() = _Initial; - const factory RowDetailEvent.didReceiveCellDatas(List cellDatas) = _DidReceiveCellDatas; + const factory RowDetailEvent.didReceiveCellDatas(List gridCells) = _DidReceiveCellDatas; } @freezed class RowDetailState with _$RowDetailState { const factory RowDetailState({ - required List cellDatas, + required List gridCells, }) = _RowDetailState; factory RowDetailState.initial() => RowDetailState( - cellDatas: List.empty(), + gridCells: List.empty(), ); } 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 f3706d2782..57f299f2ab 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 @@ -84,7 +84,7 @@ class GridRowCache { RowUpdateCallback addRowListener({ required String rowId, - void Function(CellDataMap)? onUpdated, + void Function(GridCellMap)? onUpdated, bool Function()? listenWhen, }) { listenrHandler() { @@ -99,7 +99,7 @@ class GridRowCache { notify() { final row = _rowNotifier.rowDataWithId(rowId); if (row != null) { - final CellDataMap cellDataMap = _makeCellDataMap(rowId, row); + final GridCellMap cellDataMap = _makeCellDataMap(rowId, row); onUpdated(cellDataMap); } } @@ -118,8 +118,8 @@ class GridRowCache { return listenrHandler; } - CellDataMap _makeCellDataMap(String rowId, Row? row) { - var cellDataMap = CellDataMap.new(); + GridCellMap _makeCellDataMap(String rowId, Row? row) { + var cellDataMap = GridCellMap.new(); for (final field in _fieldDelegate.fields) { if (field.visibility) { cellDataMap[field.id] = GridCell( @@ -137,7 +137,7 @@ class GridRowCache { _rowNotifier.removeListener(callback); } - CellDataMap loadCellData(String rowId) { + GridCellMap loadCellData(String rowId) { final Row? data = _rowNotifier.rowDataWithId(rowId); if (data == null) { final payload = RowIdentifierPayload.create() 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 e95fcd9a53..195449f4f9 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,6 +1,8 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, FieldType; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter/widgets.dart'; import 'checkbox_cell.dart'; import 'date_cell.dart'; @@ -8,22 +10,47 @@ import 'number_cell.dart'; import 'selection_cell/selection_cell.dart'; import 'text_cell.dart'; -GridCellWidget buildGridCell(GridCellContext cellContext, {GridCellStyle? style}) { - final key = ValueKey(cellContext.cellId); - final fieldType = cellContext.cellData.field.fieldType; - switch (fieldType) { +GridCellWidget buildGridCellWidget(GridCell gridCell, GridCellCache cellCache, {GridCellStyle? style}) { + final key = ValueKey(gridCell.rowId + gridCell.field.id); + + final cellContext = makeCellContext(gridCell, cellCache); + + switch (gridCell.field.fieldType) { case FieldType.Checkbox: return CheckboxCell(cellContext: cellContext, key: key); case FieldType.DateTime: return DateCell(cellContext: cellContext, key: key); case FieldType.MultiSelect: - return MultiSelectCell(cellContext: cellContext, style: style, key: key); + return MultiSelectCell(cellContext: cellContext as GridCellContext, style: style, key: key); case FieldType.Number: return NumberCell(cellContext: cellContext, key: key); case FieldType.RichText: return GridTextCell(cellContext: cellContext, style: style, key: key); case FieldType.SingleSelect: - return SingleSelectCell(cellContext: cellContext, style: style, key: key); + return SingleSelectCell(cellContext: cellContext as GridCellContext, style: style, key: key); + default: + throw UnimplementedError; + } +} + +GridCellContext makeCellContext(GridCell gridCell, GridCellCache cellCache) { + switch (gridCell.field.fieldType) { + case FieldType.Checkbox: + case FieldType.DateTime: + case FieldType.Number: + case FieldType.RichText: + return GridCellContext( + gridCell: gridCell, + cellCache: cellCache, + cellDataLoader: DefaultCellDataLoader(gridCell: gridCell), + ); + case FieldType.MultiSelect: + case FieldType.SingleSelect: + return GridCellContext( + gridCell: gridCell, + cellCache: cellCache, + cellDataLoader: SelectOptionCellDataLoader(gridCell: gridCell), + ); default: throw UnimplementedError; } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index 41ea4b2002..5d1019d32c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -3,6 +3,7 @@ import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -18,7 +19,7 @@ class SelectOptionCellStyle extends GridCellStyle { } class SingleSelectCell extends GridCellWidget { - final GridCellContext cellContext; + final GridCellContext cellContext; late final SelectOptionCellStyle? cellStyle; SingleSelectCell({ @@ -66,9 +67,7 @@ class _SingleSelectCellState extends State { widget.onFocus.value = true; SelectOptionCellEditor.show( context, - state.cellData, - state.options, - state.selectedOptions, + widget.cellContext, () => widget.onFocus.value = false, ); }, @@ -89,7 +88,7 @@ class _SingleSelectCellState extends State { //---------------------------------------------------------------- class MultiSelectCell extends GridCellWidget { - final GridCellContext cellContext; + final GridCellContext cellContext; late final SelectOptionCellStyle? cellStyle; MultiSelectCell({ @@ -135,9 +134,7 @@ class _MultiSelectCellState extends State { widget.onFocus.value = true; SelectOptionCellEditor.show( context, - state.cellData, - state.options, - state.selectedOptions, + widget.cellContext, () => widget.onFocus.value = false, ); }, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart index 2f4b54cc9b..13a4a590c0 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart @@ -26,15 +26,11 @@ import 'text_field.dart'; const double _editorPannelWidth = 300; class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { - final GridCell cellData; - final List options; - final List selectedOptions; + final GridCellContext cellContext; final VoidCallback onDismissed; const SelectOptionCellEditor({ - required this.cellData, - required this.options, - required this.selectedOptions, + required this.cellContext, required this.onDismissed, Key? key, }) : super(key: key); @@ -43,9 +39,7 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { Widget build(BuildContext context) { return BlocProvider( create: (context) => SelectOptionEditorBloc( - cellData: cellData, - options: options, - selectedOptions: selectedOptions, + cellContext: cellContext, )..add(const SelectOptionEditorEvent.initial()), child: BlocBuilder( builder: (context, state) { @@ -67,16 +61,12 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { static void show( BuildContext context, - GridCell cellData, - List options, - List selectedOptions, + GridCellContext cellContext, VoidCallback onDismissed, ) { SelectOptionCellEditor.remove(context); final editor = SelectOptionCellEditor( - cellData: cellData, - options: options, - selectedOptions: selectedOptions, + cellContext: cellContext, onDismissed: onDismissed, ); 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 f5ebba8921..62cdc5c53f 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 @@ -170,22 +170,17 @@ class _RowCells extends StatelessWidget { ); } - List _makeCells(CellDataMap cellDataMap) { - return cellDataMap.values.map( - (cellData) { + List _makeCells(GridCellMap gridCellMap) { + return gridCellMap.values.map( + (gridCell) { Widget? expander; - if (cellData.field.isPrimary) { + if (gridCell.field.isPrimary) { expander = _CellExpander(onExpand: onExpand); } - final cellContext = GridCellContext( - cellData: cellData, - cellCache: cellCache, - ); - return CellContainer( - width: cellData.field.width.toDouble(), - child: buildGridCell(cellContext), + width: gridCell.field.width.toDouble(), + child: buildGridCellWidget(gridCell, cellCache), expander: expander, ); }, 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 e61516ba4f..ae82033320 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 @@ -84,7 +84,7 @@ class _PropertyList extends StatelessWidget { @override Widget build(BuildContext context) { return BlocBuilder( - buildWhen: (previous, current) => previous.cellDatas != current.cellDatas, + buildWhen: (previous, current) => previous.gridCells != current.gridCells, builder: (context, state) { return ScrollbarListStack( axis: Axis.vertical, @@ -92,13 +92,12 @@ class _PropertyList extends StatelessWidget { barSize: GridSize.scrollBarSize, child: ListView.separated( controller: _scrollController, - itemCount: state.cellDatas.length, + itemCount: state.gridCells.length, itemBuilder: (BuildContext context, int index) { - final cellContext = GridCellContext( - cellData: state.cellDatas[index], + return _RowDetailCell( + gridCell: state.gridCells[index], cellCache: cellCache, ); - return _RowDetailCell(cellContext: cellContext); }, separatorBuilder: (BuildContext context, int index) { return const VSpace(2); @@ -111,16 +110,22 @@ class _PropertyList extends StatelessWidget { } class _RowDetailCell extends StatelessWidget { - final GridCellContext cellContext; - const _RowDetailCell({required this.cellContext, Key? key}) : super(key: key); + final GridCell gridCell; + final GridCellCache cellCache; + const _RowDetailCell({ + required this.gridCell, + required this.cellCache, + Key? key, + }) : super(key: key); @override Widget build(BuildContext context) { final theme = context.watch(); - final cell = buildGridCell( - cellContext, - style: _buildCellStyle(theme, cellContext.fieldType), + final cell = buildGridCellWidget( + gridCell, + cellCache, + style: _buildCellStyle(theme, gridCell.field.fieldType), ); return SizedBox( height: 36, @@ -130,7 +135,7 @@ class _RowDetailCell extends StatelessWidget { children: [ SizedBox( width: 150, - child: FieldCellButton(field: cellContext.field, onTap: () => _showFieldEditor(context)), + child: FieldCellButton(field: gridCell.field, onTap: () => _showFieldEditor(context)), ), const HSpace(10), Expanded( @@ -146,10 +151,10 @@ class _RowDetailCell extends StatelessWidget { void _showFieldEditor(BuildContext context) { FieldEditor( - gridId: cellContext.gridId, + gridId: gridCell.gridId, fieldContextLoader: FieldContextLoaderAdaptor( - gridId: cellContext.gridId, - field: cellContext.field, + gridId: gridCell.gridId, + field: gridCell.field, ), ).show(context); } From af5f42d296e395c2891107c881dffd3117eba9fb Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 24 Apr 2022 07:10:09 +0800 Subject: [PATCH 07/12] chore: auto reload when field was changed --- .../app_flowy/lib/startup/deps_resolver.dart | 7 ++- .../application/grid/cell/cell_service.dart | 39 ++++++++++---- .../grid/cell/checkbox_cell_bloc.dart | 12 ++--- .../application/grid/cell/date_cell_bloc.dart | 19 ++----- .../grid/cell/number_cell_bloc.dart | 23 +++----- .../grid/cell/select_option_service.dart | 3 ++ .../grid/cell/selection_cell_bloc.dart | 10 +--- .../grid/cell/selection_editor_bloc.dart | 30 +---------- .../application/grid/cell/text_cell_bloc.dart | 53 ++++--------------- .../grid/src/widgets/cell/cell_builder.dart | 4 +- .../cell/selection_cell/selection_editor.dart | 1 - 11 files changed, 64 insertions(+), 137 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 10b51438e4..e61096831c 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -16,7 +16,6 @@ import 'package:app_flowy/user/presentation/router.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; @@ -182,19 +181,19 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam, void>( + getIt.registerFactoryParam( (context, _) => NumberCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam, void>( + getIt.registerFactoryParam( (context, _) => DateCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam, void>( + getIt.registerFactoryParam( (cellData, _) => CheckboxCellBloc( service: CellService(), cellContext: cellData, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index 224e8b0d3a..b4d67e41ac 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:collection'; import 'package:dartz/dartz.dart'; @@ -6,6 +7,7 @@ import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -13,6 +15,9 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; part 'cell_service.freezed.dart'; +typedef GridDefaultCellContext = GridCellContext; +typedef GridSelectOptionCellContext = GridCellContext; + class GridCellContext { final GridCell gridCell; final GridCellCache cellCache; @@ -22,6 +27,7 @@ class GridCellContext { final CellListener _cellListener; final CellService _cellService = CellService(); final ValueNotifier _cellDataNotifier = ValueNotifier(null); + Timer? _delayOperation; GridCellContext({ required this.gridCell, @@ -41,6 +47,12 @@ class GridCellContext { objectId: "$hashCode", fieldId: gridCell.field.id, ); + + if (cellDataLoader.reloadOnFieldChanged) { + cellCache.addListener(cacheKey, () { + reloadCellData(); + }); + } } String get gridId => gridCell.gridId; @@ -73,16 +85,18 @@ class GridCellContext { _cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data); } - void _loadData() { - // It may trigger getCell multiple times. Use cancel operation to fix this. - cellDataLoader.loadData().then((data) { - _cellDataNotifier.value = data; - setCellData(data); - }); + void reloadCellData() { + _loadData(); } - void onFieldChanged(VoidCallback callback) { - cellCache.addListener(cacheKey, callback); + void _loadData() { + _delayOperation?.cancel(); + _delayOperation = Timer(const Duration(milliseconds: 10), () { + cellDataLoader.loadData().then((data) { + _cellDataNotifier.value = data; + setCellData(data); + }); + }); } void onCellChanged(void Function(T) callback) { @@ -94,13 +108,15 @@ class GridCellContext { }); } - void removeListener() { - cellCache.removeListener(cacheKey); + void dispose() { + _delayOperation?.cancel(); } } abstract class GridCellDataLoader { Future loadData(); + + bool get reloadOnFieldChanged => true; } class DefaultCellDataLoader implements GridCellDataLoader { @@ -125,6 +141,9 @@ class DefaultCellDataLoader implements GridCellDataLoader { }); }); } + + @override + bool get reloadOnFieldChanged => true; } // key: rowId 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 5a36c7f5a8..01d6540e4d 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 @@ -7,13 +7,12 @@ import 'cell_service.dart'; part 'checkbox_cell_bloc.freezed.dart'; class CheckboxCellBloc extends Bloc { - final GridCellContext _cellContext; + final GridDefaultCellContext cellContext; CheckboxCellBloc({ required CellService service, - required GridCellContext cellContext, - }) : _cellContext = cellContext, - super(CheckboxCellState.initial(cellContext)) { + required this.cellContext, + }) : super(CheckboxCellState.initial(cellContext)) { on( (event, emit) async { await event.map( @@ -33,11 +32,12 @@ class CheckboxCellBloc extends Bloc { @override Future close() async { + cellContext.dispose(); return super.close(); } void _startListening() { - _cellContext.onCellChanged((cell) { + cellContext.onCellChanged((cell) { if (!isClosed) { add(CheckboxCellEvent.didReceiveCellUpdate(cell)); } @@ -45,7 +45,7 @@ class CheckboxCellBloc extends Bloc { } void _updateCellData() { - _cellContext.saveCellData(!state.isSelected ? "Yes" : "No"); + cellContext.saveCellData(!state.isSelected ? "Yes" : "No"); } } 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 b1eacce788..5a52e59de1 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,5 +1,3 @@ -import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -9,12 +7,9 @@ import 'cell_service.dart'; part 'date_cell_bloc.freezed.dart'; class DateCellBloc extends Bloc { - final SingleFieldListener _fieldListener; - final GridCellContext cellContext; + final GridDefaultCellContext cellContext; - DateCellBloc({required this.cellContext}) - : _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), - super(DateCellState.initial(cellContext)) { + DateCellBloc({required this.cellContext}) : super(DateCellState.initial(cellContext)) { on( (event, emit) async { event.map( @@ -39,7 +34,7 @@ class DateCellBloc extends Bloc { @override Future close() async { - await _fieldListener.stop(); + cellContext.dispose(); return super.close(); } @@ -49,14 +44,6 @@ class DateCellBloc extends Bloc { add(DateCellEvent.didReceiveCellUpdate(cell)); } }); - - _fieldListener.updateFieldNotifier?.addPublishListener((result) { - result.fold( - (field) => add(DateCellEvent.didReceiveFieldUpdate(field)), - (err) => Log.error(err), - ); - }, listenWhen: () => !isClosed); - _fieldListener.start(); } void _updateCellData(DateTime day) { 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 28eca05498..43044271b4 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 @@ -1,5 +1,3 @@ -import 'package:app_flowy/workspace/application/grid/field/field_listener.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'; @@ -9,13 +7,11 @@ import 'cell_service.dart'; part 'number_cell_bloc.freezed.dart'; class NumberCellBloc extends Bloc { - final GridCellContext cellContext; - final SingleFieldListener _fieldListener; + final GridDefaultCellContext cellContext; NumberCellBloc({ required this.cellContext, - }) : _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), - super(NumberCellState.initial(cellContext)) { + }) : super(NumberCellState.initial(cellContext)) { on( (event, emit) async { await event.map( @@ -40,7 +36,7 @@ class NumberCellBloc extends Bloc { @override Future close() async { - await _fieldListener.stop(); + cellContext.dispose(); return super.close(); } @@ -50,14 +46,6 @@ class NumberCellBloc extends Bloc { add(NumberCellEvent.didReceiveCellUpdate(cell)); } }); - - _fieldListener.updateFieldNotifier?.addPublishListener((result) { - result.fold( - (field) => cellContext.reloadCellData(), - (err) => Log.error(err), - ); - }); - _fieldListener.start(); } } @@ -74,7 +62,8 @@ class NumberCellState with _$NumberCellState { required String content, }) = _NumberCellState; - factory NumberCellState.initial(GridCellContext context) { - return NumberCellState(content: context.getCellData().cell?.content ?? ""); + factory NumberCellState.initial(GridDefaultCellContext context) { + final cell = context.getCellData(); + return NumberCellState(content: cell?.content ?? ""); } } 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 aaac04ee49..f6eac64e85 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 @@ -27,6 +27,9 @@ class SelectOptionCellDataLoader implements GridCellDataLoader true; } class SelectOptionService { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index 6a4a038ac4..6c1d700d9d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -3,18 +3,15 @@ import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; -import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; part 'selection_cell_bloc.freezed.dart'; class SelectionCellBloc extends Bloc { - final SingleFieldListener _fieldListener; final GridCellContext cellContext; SelectionCellBloc({ required this.cellContext, - }) : _fieldListener = SingleFieldListener(fieldId: cellContext.fieldId), - super(SelectionCellState.initial(cellContext)) { + }) : super(SelectionCellState.initial(cellContext)) { on( (event, emit) async { await event.map( @@ -34,8 +31,7 @@ class SelectionCellBloc extends Bloc { @override Future close() async { - await _fieldListener.stop(); - cellContext.removeListener(); + cellContext.dispose(); return super.close(); } @@ -48,8 +44,6 @@ class SelectionCellBloc extends Bloc { )); } }); - - cellContext.onFieldChanged(() => cellContext.reloadCellData()); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index b7eb32d18e..bd3eb0961e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -1,8 +1,5 @@ -import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; -import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -14,7 +11,6 @@ part 'selection_editor_bloc.freezed.dart'; class SelectOptionEditorBloc extends Bloc { final SelectOptionService _selectOptionService; final GridCellContext cellContext; - Timer? _delayOperation; SelectOptionEditorBloc({ required this.cellContext, @@ -51,8 +47,7 @@ class SelectOptionEditorBloc extends Bloc close() async { - _delayOperation?.cancel(); - cellContext.removeListener(); + cellContext.dispose(); return super.close(); } @@ -86,27 +81,6 @@ class SelectOptionEditorBloc extends Bloc add(SelectOptionEditorEvent.didReceiveOptions( - // selectOptionContext.options, - // selectOptionContext.selectOptions, - // )), - // (err) => Log.error(err), - // ); - // }, - // ); - // } - void _startListening() { cellContext.onCellChanged((selectOptionContext) { if (!isClosed) { @@ -116,8 +90,6 @@ class SelectOptionEditorBloc extends Bloc cellContext.reloadCellData()); } } 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 a051eca2d5..4aa8aef027 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 @@ -1,22 +1,16 @@ -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; -import 'cell_listener.dart'; import 'cell_service.dart'; part 'text_cell_bloc.freezed.dart'; class TextCellBloc extends Bloc { - final CellService _service; - final CellListener _cellListener; - + final GridCellContext cellContext; TextCellBloc({ - required GridCellContext cellContext, - }) : _service = CellService(), - _cellListener = CellListener(rowId: cellContext.rowId, fieldId: cellContext.fieldId), - super(TextCellState.initial(cellContext.gridCell)) { + required this.cellContext, + }) : super(TextCellState.initial(cellContext.gridCell)) { on( (event, emit) async { await event.map( @@ -24,7 +18,7 @@ class TextCellBloc extends Bloc { _startListening(); }, updateText: (_UpdateText value) { - updateCellContent(value.text); + cellContext.saveCellData(value.text); emit(state.copyWith(content: value.text)); }, didReceiveCellData: (_DidReceiveCellData value) { @@ -46,45 +40,16 @@ class TextCellBloc extends Bloc { @override Future close() async { - await _cellListener.stop(); + cellContext.dispose(); return super.close(); } - void updateCellContent(String content) { - final fieldId = state.cellData.field.id; - final gridId = state.cellData.gridId; - final rowId = state.cellData.rowId; - _service.updateCell( - data: content, - fieldId: fieldId, - gridId: gridId, - rowId: rowId, - ); - } - void _startListening() { - _cellListener.updateCellNotifier?.addPublishListener((result) { - result.fold( - (notificationData) async => await _loadCellData(), - (err) => Log.error(err), - ); + cellContext.onCellChanged((cell) { + if (!isClosed) { + add(TextCellEvent.didReceiveCellUpdate(cell)); + } }); - _cellListener.start(); - } - - Future _loadCellData() async { - final result = await _service.getCell( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - ); - if (isClosed) { - return; - } - result.fold( - (cell) => add(TextCellEvent.didReceiveCellUpdate(cell)), - (err) => Log.error(err), - ); } } 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 195449f4f9..2b43569d26 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,7 +1,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, FieldType; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter/widgets.dart'; import 'checkbox_cell.dart'; @@ -39,7 +39,7 @@ GridCellContext makeCellContext(GridCell gridCell, GridCellCache cellCache) { case FieldType.DateTime: case FieldType.Number: case FieldType.RichText: - return GridCellContext( + return GridDefaultCellContext( gridCell: gridCell, cellCache: cellCache, cellDataLoader: DefaultCellDataLoader(gridCell: gridCell), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart index 13a4a590c0..fcf263256d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart @@ -1,7 +1,6 @@ import 'dart:collection'; import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/cell/selection_editor_bloc.dart'; -import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart'; From 6d385877a94c648c7c2145fa248bac9476e495c1 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 24 Apr 2022 17:03:00 +0800 Subject: [PATCH 08/12] fix: bugs --- .../app_flowy/lib/startup/deps_resolver.dart | 5 +- .../application/grid/cell/cell_service.dart | 59 ++++--------------- .../grid/cell/selection_cell_bloc.dart | 4 +- .../grid/cell/selection_editor_bloc.dart | 4 +- .../application/grid/cell/text_cell_bloc.dart | 16 ++--- .../grid/src/widgets/cell/cell_builder.dart | 6 +- .../cell/selection_cell/selection_cell.dart | 4 +- .../cell/selection_cell/selection_editor.dart | 4 +- 8 files changed, 28 insertions(+), 74 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index e61096831c..5896d559a3 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -18,7 +18,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart'; import 'package:get_it/get_it.dart'; @@ -169,13 +168,13 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => TextCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam, void>( + getIt.registerFactoryParam( (context, _) => SelectionCellBloc( cellContext: context, ), diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index b4d67e41ac..bcc3c2726b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -10,7 +10,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_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'; part 'cell_service.freezed.dart'; @@ -21,19 +20,22 @@ typedef GridSelectOptionCellContext = GridCellContext; class GridCellContext { final GridCell gridCell; final GridCellCache cellCache; - late GridCellCacheKey _cacheKey; + final GridCellCacheKey _cacheKey; final GridCellDataLoader cellDataLoader; final CellListener _cellListener; final CellService _cellService = CellService(); - final ValueNotifier _cellDataNotifier = ValueNotifier(null); + late final ValueNotifier _cellDataNotifier; Timer? _delayOperation; GridCellContext({ required this.gridCell, required this.cellCache, required this.cellDataLoader, - }) : _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id) { + }) : _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id), + _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id) { + _cellDataNotifier = ValueNotifier(cellCache.get(cacheKey)); + _cellListener.updateCellNotifier?.addPublishListener((result) { result.fold( (notification) => _loadData(), @@ -43,15 +45,8 @@ class GridCellContext { _cellListener.start(); - _cacheKey = GridCellCacheKey( - objectId: "$hashCode", - fieldId: gridCell.field.id, - ); - if (cellDataLoader.reloadOnFieldChanged) { - cellCache.addListener(cacheKey, () { - reloadCellData(); - }); + cellCache.addListener(cacheKey, () => reloadCellData()); } } @@ -82,7 +77,9 @@ class GridCellContext { } void saveCellData(String data) { - _cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data); + _cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data).then((result) { + result.fold((l) => null, (err) => Log.error(err)); + }); } void reloadCellData() { @@ -265,42 +262,6 @@ class CellService { } } -// class CellCache { -// final CellService _cellService; -// final HashMap _cellDataMap = HashMap(); - -// CellCache() : _cellService = CellService(); - -// Future> getCellData(GridCell identifier) async { -// final cellId = _cellId(identifier); -// final Cell? data = _cellDataMap[cellId]; -// if (data != null) { -// return Future(() => Some(data)); -// } - -// final result = await _cellService.getCell( -// gridId: identifier.gridId, -// fieldId: identifier.field.id, -// rowId: identifier.rowId, -// ); - -// return result.fold( -// (cell) { -// _cellDataMap[_cellId(identifier)] = cell; -// return Some(cell); -// }, -// (err) { -// Log.error(err); -// return none(); -// }, -// ); -// } - -// String _cellId(GridCell identifier) { -// return "${identifier.rowId}/${identifier.field.id}"; -// } -// } - @freezed class GridCell with _$GridCell { const factory GridCell({ diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index 6c1d700d9d..f1ee45546f 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -7,7 +7,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; part 'selection_cell_bloc.freezed.dart'; class SelectionCellBloc extends Bloc { - final GridCellContext cellContext; + final GridSelectOptionCellContext cellContext; SelectionCellBloc({ required this.cellContext, @@ -63,7 +63,7 @@ class SelectionCellState with _$SelectionCellState { required List selectedOptions, }) = _SelectionCellState; - factory SelectionCellState.initial(GridCellContext context) { + factory SelectionCellState.initial(GridSelectOptionCellContext context) { final data = context.getCellData(); return SelectionCellState( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index bd3eb0961e..69fa8237ef 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -10,7 +10,7 @@ part 'selection_editor_bloc.freezed.dart'; class SelectOptionEditorBloc extends Bloc { final SelectOptionService _selectOptionService; - final GridCellContext cellContext; + final GridSelectOptionCellContext cellContext; SelectOptionEditorBloc({ required this.cellContext, @@ -111,7 +111,7 @@ class SelectOptionEditorState with _$SelectOptionEditorState { required List selectedOptions, }) = _SelectOptionEditorState; - factory SelectOptionEditorState.initial(GridCellContext context) { + factory SelectOptionEditorState.initial(GridSelectOptionCellContext context) { final data = context.getCellData(); 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 4aa8aef027..f564a69a76 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 @@ -7,10 +7,10 @@ import 'cell_service.dart'; part 'text_cell_bloc.freezed.dart'; class TextCellBloc extends Bloc { - final GridCellContext cellContext; + final GridDefaultCellContext cellContext; TextCellBloc({ required this.cellContext, - }) : super(TextCellState.initial(cellContext.gridCell)) { + }) : super(TextCellState.initial(cellContext)) { on( (event, emit) async { await event.map( @@ -22,14 +22,10 @@ class TextCellBloc extends Bloc { emit(state.copyWith(content: value.text)); }, didReceiveCellData: (_DidReceiveCellData value) { - emit(state.copyWith( - cellData: value.cellData, - content: value.cellData.cell?.content ?? "", - )); + emit(state.copyWith(content: value.cellData.cell?.content ?? "")); }, didReceiveCellUpdate: (_DidReceiveCellUpdate value) { emit(state.copyWith( - cellData: state.cellData.copyWith(cell: value.cell), content: value.cell.content, )); }, @@ -65,11 +61,9 @@ class TextCellEvent with _$TextCellEvent { class TextCellState with _$TextCellState { const factory TextCellState({ required String content, - required GridCell cellData, }) = _TextCellState; - factory TextCellState.initial(GridCell cellData) => TextCellState( - content: cellData.cell?.content ?? "", - cellData: cellData, + factory TextCellState.initial(GridDefaultCellContext context) => TextCellState( + content: context.getCellData()?.content ?? "", ); } 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 2b43569d26..6a60113f62 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,13 +21,13 @@ GridCellWidget buildGridCellWidget(GridCell gridCell, GridCellCache cellCache, { case FieldType.DateTime: return DateCell(cellContext: cellContext, key: key); case FieldType.MultiSelect: - return MultiSelectCell(cellContext: cellContext as GridCellContext, style: style, key: key); + return MultiSelectCell(cellContext: cellContext as GridSelectOptionCellContext, style: style, key: key); case FieldType.Number: return NumberCell(cellContext: cellContext, key: key); case FieldType.RichText: return GridTextCell(cellContext: cellContext, style: style, key: key); case FieldType.SingleSelect: - return SingleSelectCell(cellContext: cellContext as GridCellContext, style: style, key: key); + return SingleSelectCell(cellContext: cellContext as GridSelectOptionCellContext, style: style, key: key); default: throw UnimplementedError; } @@ -46,7 +46,7 @@ GridCellContext makeCellContext(GridCell gridCell, GridCellCache cellCache) { ); case FieldType.MultiSelect: case FieldType.SingleSelect: - return GridCellContext( + return GridSelectOptionCellContext( gridCell: gridCell, cellCache: cellCache, cellDataLoader: SelectOptionCellDataLoader(gridCell: gridCell), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index 5d1019d32c..44ab0813d1 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -19,7 +19,7 @@ class SelectOptionCellStyle extends GridCellStyle { } class SingleSelectCell extends GridCellWidget { - final GridCellContext cellContext; + final GridSelectOptionCellContext cellContext; late final SelectOptionCellStyle? cellStyle; SingleSelectCell({ @@ -88,7 +88,7 @@ class _SingleSelectCellState extends State { //---------------------------------------------------------------- class MultiSelectCell extends GridCellWidget { - final GridCellContext cellContext; + final GridSelectOptionCellContext cellContext; late final SelectOptionCellStyle? cellStyle; MultiSelectCell({ diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart index fcf263256d..0379bd55dd 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart @@ -25,7 +25,7 @@ import 'text_field.dart'; const double _editorPannelWidth = 300; class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { - final GridCellContext cellContext; + final GridSelectOptionCellContext cellContext; final VoidCallback onDismissed; const SelectOptionCellEditor({ @@ -60,7 +60,7 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { static void show( BuildContext context, - GridCellContext cellContext, + GridSelectOptionCellContext cellContext, VoidCallback onDismissed, ) { SelectOptionCellEditor.remove(context); From cffd8fbec603c32acf5c23a94047cf13ca095e1b Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 24 Apr 2022 23:20:28 +0800 Subject: [PATCH 09/12] fix: setup GridCellContext fieldOnchanged callback --- .../application/grid/cell/cell_service.dart | 43 +++++---- .../grid/cell/checkbox_cell_bloc.dart | 4 +- .../application/grid/cell/date_cell_bloc.dart | 12 +-- .../grid/cell/number_cell_bloc.dart | 12 +-- .../grid/cell/selection_cell_bloc.dart | 18 ++-- .../grid/cell/selection_editor_bloc.dart | 18 ++-- .../application/grid/cell/text_cell_bloc.dart | 12 +-- .../workspace/application/grid/grid_bloc.dart | 2 +- .../application/grid/row/row_bloc.dart | 2 +- .../application/grid/row/row_detail_bloc.dart | 2 +- .../application/grid/row/row_service.dart | 89 ++++++++++--------- .../grid/src/widgets/cell/cell_builder.dart | 1 - .../src/services/block_meta_editor.rs | 11 +++ .../src/services/block_meta_manager.rs | 17 ++-- 14 files changed, 133 insertions(+), 110 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index bcc3c2726b..f435a8ac9a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -35,19 +35,6 @@ class GridCellContext { }) : _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id), _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id) { _cellDataNotifier = ValueNotifier(cellCache.get(cacheKey)); - - _cellListener.updateCellNotifier?.addPublishListener((result) { - result.fold( - (notification) => _loadData(), - (err) => Log.error(err), - ); - }); - - _cellListener.start(); - - if (cellDataLoader.reloadOnFieldChanged) { - cellCache.addListener(cacheKey, () => reloadCellData()); - } } String get gridId => gridCell.gridId; @@ -64,6 +51,27 @@ class GridCellContext { GridCellCacheKey get cacheKey => _cacheKey; + void startListening({required void Function(T) onCellChanged}) { + _cellListener.updateCellNotifier?.addPublishListener((result) { + result.fold( + (notification) => _loadData(), + (err) => Log.error(err), + ); + }); + _cellListener.start(); + + if (cellDataLoader.reloadOnFieldChanged) { + cellCache.addListener(cacheKey, () => reloadCellData()); + } + + _cellDataNotifier.addListener(() { + final value = _cellDataNotifier.value; + if (value is T) { + onCellChanged(value); + } + }); + } + T? getCellData() { final data = cellCache.get(cacheKey); if (data == null) { @@ -96,15 +104,6 @@ class GridCellContext { }); } - void onCellChanged(void Function(T) callback) { - _cellDataNotifier.addListener(() { - final value = _cellDataNotifier.value; - if (value is T) { - callback(value); - } - }); - } - void dispose() { _delayOperation?.cancel(); } 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 01d6540e4d..f6e7fa1fe6 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 @@ -37,11 +37,11 @@ class CheckboxCellBloc extends Bloc { } void _startListening() { - cellContext.onCellChanged((cell) { + cellContext.startListening(onCellChanged: ((cell) { if (!isClosed) { add(CheckboxCellEvent.didReceiveCellUpdate(cell)); } - }); + })); } void _updateCellData() { 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 5a52e59de1..3341c560d4 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 @@ -39,11 +39,13 @@ class DateCellBloc extends Bloc { } void _startListening() { - cellContext.onCellChanged((cell) { - if (!isClosed) { - add(DateCellEvent.didReceiveCellUpdate(cell)); - } - }); + cellContext.startListening( + onCellChanged: ((cell) { + if (!isClosed) { + add(DateCellEvent.didReceiveCellUpdate(cell)); + } + }), + ); } void _updateCellData(DateTime day) { 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 43044271b4..19ce769cf4 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 @@ -41,11 +41,13 @@ class NumberCellBloc extends Bloc { } void _startListening() { - cellContext.onCellChanged((cell) { - if (!isClosed) { - add(NumberCellEvent.didReceiveCellUpdate(cell)); - } - }); + cellContext.startListening( + onCellChanged: ((cell) { + if (!isClosed) { + add(NumberCellEvent.didReceiveCellUpdate(cell)); + } + }), + ); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index f1ee45546f..05e27f1f83 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -36,14 +36,16 @@ class SelectionCellBloc extends Bloc { } void _startListening() { - cellContext.onCellChanged((selectOptionContext) { - if (!isClosed) { - add(SelectionCellEvent.didReceiveOptions( - selectOptionContext.options, - selectOptionContext.selectOptions, - )); - } - }); + cellContext.startListening( + onCellChanged: ((selectOptionContext) { + if (!isClosed) { + add(SelectionCellEvent.didReceiveOptions( + selectOptionContext.options, + selectOptionContext.selectOptions, + )); + } + }), + ); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index 69fa8237ef..071ae4d5e8 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -82,14 +82,16 @@ class SelectOptionEditorBloc extends Bloc { } void _startListening() { - cellContext.onCellChanged((cell) { - if (!isClosed) { - add(TextCellEvent.didReceiveCellUpdate(cell)); - } - }); + cellContext.startListening( + onCellChanged: ((cell) { + if (!isClosed) { + add(TextCellEvent.didReceiveCellUpdate(cell)); + } + }), + ); } } 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 6cae2e275c..30ae08f6fd 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -88,7 +88,7 @@ class GridBloc extends Bloc { () => result.fold( (fields) { fieldCache.fields = fields.items; - rowCache.updateWithBlock(grid.blockOrders); + rowCache.resetRows(grid.blockOrders); emit(state.copyWith( grid: Some(grid), 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 08634774ba..cfd99b3e98 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 @@ -17,7 +17,7 @@ class RowBloc extends Bloc { required GridRowCache rowCache, }) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), _rowCache = rowCache, - super(RowState.initial(rowData, rowCache.loadCellData(rowData.rowId))) { + super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) { on( (event, emit) async { await event.map( 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 96ffac61ab..4228ddd863 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 @@ -48,7 +48,7 @@ class RowDetailBloc extends Bloc { } Future _loadCellData() async { - final cellDataMap = _rowCache.loadCellData(rowData.rowId); + final cellDataMap = _rowCache.loadGridCells(rowData.rowId); 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 57f299f2ab..c904f1a2f9 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 @@ -22,14 +22,13 @@ abstract class GridRowFieldDelegate { class GridRowCache { final String gridId; - final RowsNotifier _rowNotifier; + final RowsNotifier _rowsNotifier; final GridRowListener _rowsListener; final GridRowFieldDelegate _fieldDelegate; - - List get clonedRows => _rowNotifier.clonedRows; + List get clonedRows => _rowsNotifier.clonedRows; GridRowCache({required this.gridId, required GridRowFieldDelegate fieldDelegate}) - : _rowNotifier = RowsNotifier( + : _rowsNotifier = RowsNotifier( rowBuilder: (rowOrder) { return GridRow( gridId: gridId, @@ -42,16 +41,16 @@ class GridRowCache { _rowsListener = GridRowListener(gridId: gridId), _fieldDelegate = fieldDelegate { // - fieldDelegate.onFieldChanged(() => _rowNotifier.fieldDidChange()); + fieldDelegate.onFieldChanged(() => _rowsNotifier.fieldDidChange()); // listen on the row update _rowsListener.rowsUpdateNotifier.addPublishListener((result) { result.fold( (changesets) { for (final changeset in changesets) { - _rowNotifier.deleteRows(changeset.deletedRows); - _rowNotifier.insertRows(changeset.insertedRows); - _rowNotifier.updateRows(changeset.updatedRows); + _rowsNotifier.deleteRows(changeset.deletedRows); + _rowsNotifier.insertRows(changeset.insertedRows); + _rowsNotifier.updateRows(changeset.updatedRows); } }, (err) => Log.error(err), @@ -62,14 +61,14 @@ class GridRowCache { Future dispose() async { await _rowsListener.stop(); - _rowNotifier.dispose(); + _rowsNotifier.dispose(); } void addListener({ void Function(List, GridRowChangeReason)? onChanged, bool Function()? listenWhen, }) { - _rowNotifier.addListener(() { + _rowsNotifier.addListener(() { if (onChanged == null) { return; } @@ -78,7 +77,7 @@ class GridRowCache { return; } - onChanged(clonedRows, _rowNotifier._changeReason); + onChanged(clonedRows, _rowsNotifier._changeReason); }); } @@ -87,7 +86,7 @@ class GridRowCache { void Function(GridCellMap)? onUpdated, bool Function()? listenWhen, }) { - listenrHandler() { + listenrHandler() async { if (onUpdated == null) { return; } @@ -97,14 +96,14 @@ class GridRowCache { } notify() { - final row = _rowNotifier.rowDataWithId(rowId); + final row = _rowsNotifier.rowDataWithId(rowId); if (row != null) { - final GridCellMap cellDataMap = _makeCellDataMap(rowId, row); + final GridCellMap cellDataMap = _makeGridCells(rowId, row); onUpdated(cellDataMap); } } - _rowNotifier._changeReason.whenOrNull( + _rowsNotifier._changeReason.whenOrNull( update: (indexs) { if (indexs[rowId] != null) { notify(); @@ -114,11 +113,40 @@ class GridRowCache { ); } - _rowNotifier.addListener(listenrHandler); + _rowsNotifier.addListener(listenrHandler); return listenrHandler; } - GridCellMap _makeCellDataMap(String rowId, Row? row) { + void removeRowListener(VoidCallback callback) { + _rowsNotifier.removeListener(callback); + } + + GridCellMap loadGridCells(String rowId) { + final Row? data = _rowsNotifier.rowDataWithId(rowId); + if (data == null) { + _loadRow(rowId); + } + return _makeGridCells(rowId, data); + } + + void resetRows(List blocks) { + final rowOrders = blocks.expand((block) => block.rowOrders).toList(); + _rowsNotifier.reset(rowOrders); + } + + Future _loadRow(String rowId) async { + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + final result = await GridEventGetRow(payload).send(); + result.fold( + (rowData) => _rowsNotifier.rowData = rowData, + (err) => Log.error(err), + ); + } + + GridCellMap _makeGridCells(String rowId, Row? row) { var cellDataMap = GridCellMap.new(); for (final field in _fieldDelegate.fields) { if (field.visibility) { @@ -132,33 +160,6 @@ class GridRowCache { } return cellDataMap; } - - void removeRowListener(VoidCallback callback) { - _rowNotifier.removeListener(callback); - } - - GridCellMap loadCellData(String rowId) { - final Row? data = _rowNotifier.rowDataWithId(rowId); - if (data == null) { - final payload = RowIdentifierPayload.create() - ..gridId = gridId - ..rowId = rowId; - - GridEventGetRow(payload).send().then((result) { - result.fold( - (rowData) => _rowNotifier.rowData = rowData, - (err) => Log.error(err), - ); - }); - } - - return _makeCellDataMap(rowId, data); - } - - void updateWithBlock(List blocks) { - final rowOrders = blocks.expand((block) => block.rowOrders).toList(); - _rowNotifier.reset(rowOrders); - } } class RowsNotifier extends ChangeNotifier { 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 6a60113f62..97495820ff 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 @@ -2,7 +2,6 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; -import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter/widgets.dart'; import 'checkbox_cell.dart'; import 'date_cell.dart'; diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs b/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs index b4d8bccbe5..ce7c5c8e8d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_meta_editor.rs @@ -96,6 +96,12 @@ impl ClientGridBlockMetaEditor { Ok(()) } + pub async fn get_row_meta(&self, row_id: &str) -> FlowyResult>> { + let row_ids = vec![Cow::Borrowed(row_id)]; + let row_meta = self.get_row_metas(Some(row_ids)).await?.pop(); + Ok(row_meta) + } + pub async fn get_row_metas(&self, row_ids: Option>>) -> FlowyResult>> where T: AsRef + ToOwned + ?Sized, @@ -113,6 +119,11 @@ impl ClientGridBlockMetaEditor { Ok(cell_metas) } + pub async fn get_row_order(&self, row_id: &str) -> FlowyResult> { + let row_ids = Some(vec![Cow::Borrowed(row_id)]); + Ok(self.get_row_orders(row_ids).await?.pop()) + } + pub async fn get_row_orders(&self, row_ids: Option>>) -> FlowyResult> where T: AsRef + ToOwned + ?Sized, diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs index 5e0927795b..cdc06d8723 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs @@ -119,11 +119,15 @@ impl GridBlockMetaEditorManager { let row_id = row_id.to_owned(); let block_id = self.persistence.get_block_id(&row_id)?; let editor = self.get_editor(&block_id).await?; - let row_orders = editor.get_row_orders(Some(vec![Cow::Borrowed(&row_id)])).await?; - let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?; - let _ = self - .notify_did_update_block(GridRowsChangeset::delete(&block_id, row_orders)) - .await?; + match editor.get_row_order(&row_id).await? { + None => {} + Some(row_order) => { + let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?; + let _ = self + .notify_did_update_block(GridRowsChangeset::delete(&block_id, vec![row_order])) + .await?; + } + } Ok(()) } @@ -231,8 +235,7 @@ impl GridBlockMetaEditorManager { async fn notify_did_update_block_row(&self, row_id: &str) -> FlowyResult<()> { let editor = self.get_editor_from_row_id(row_id).await?; - let row_ids = Some(vec![Cow::Borrowed(&row_id)]); - match editor.get_row_orders(row_ids).await?.pop() { + match editor.get_row_order(row_id).await? { None => {} Some(row_order) => { let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]); From 0ac17fa6dfcb97c688e13c610bbf6fa5f56fe5af Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 25 Apr 2022 08:13:09 +0800 Subject: [PATCH 10/12] chore: replace row when row updated --- .../application/grid/cell/cell_listener.dart | 16 +- .../application/grid/cell/cell_service.dart | 34 +- .../grid/field/field_cell_bloc.dart | 8 +- .../grid/field/field_listener.dart | 13 +- .../application/grid/field/grid_listenr.dart | 3 +- .../application/grid/grid_service.dart | 3 +- .../application/grid/row/row_service.dart | 8 +- .../cell/selection_cell/selection_cell.dart | 1 - .../flowy-grid-data-model/grid.pb.dart | 173 ++--- .../flowy-grid-data-model/grid.pbjson.dart | 31 +- .../src/services/block_meta_manager.rs | 61 +- .../flowy-grid/src/services/grid_editor.rs | 16 +- .../flowy-grid/src/services/row/row_loader.rs | 4 + .../src/entities/grid.rs | 39 +- .../src/protobuf/model/grid.rs | 668 ++++++++---------- .../src/protobuf/proto/grid.proto | 12 +- 16 files changed, 483 insertions(+), 607 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart index 314345017e..05289fee03 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart @@ -1,5 +1,4 @@ import 'package:dartz/dartz.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart'; import 'package:flowy_infra/notifier.dart'; @@ -7,16 +6,17 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:app_flowy/core/notification_helper.dart'; -typedef UpdateFieldNotifiedValue = Either; +typedef UpdateFieldNotifiedValue = Either; class CellListener { final String rowId; final String fieldId; - PublishNotifier? updateCellNotifier = PublishNotifier(); + PublishNotifier? _updateCellNotifier = PublishNotifier(); GridNotificationListener? _listener; CellListener({required this.rowId, required this.fieldId}); - void start() { + void start({required void Function(UpdateFieldNotifiedValue) onCellChanged}) { + _updateCellNotifier?.addPublishListener(onCellChanged); _listener = GridNotificationListener(objectId: "$rowId:$fieldId", handler: _handler); } @@ -24,8 +24,8 @@ class CellListener { switch (ty) { case GridNotification.DidUpdateCell: result.fold( - (payload) => updateCellNotifier?.value = left(CellNotificationData.fromBuffer(payload)), - (error) => updateCellNotifier?.value = right(error), + (payload) => _updateCellNotifier?.value = left(unit), + (error) => _updateCellNotifier?.value = right(error), ); break; default: @@ -35,7 +35,7 @@ class CellListener { Future stop() async { await _listener?.stop(); - updateCellNotifier?.dispose(); - updateCellNotifier = null; + _updateCellNotifier?.dispose(); + _updateCellNotifier = null; } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index f435a8ac9a..6c0128a848 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -22,20 +22,18 @@ class GridCellContext { final GridCellCache cellCache; final GridCellCacheKey _cacheKey; final GridCellDataLoader cellDataLoader; - - final CellListener _cellListener; final CellService _cellService = CellService(); + + late final CellListener _cellListener; late final ValueNotifier _cellDataNotifier; + bool isListening = false; Timer? _delayOperation; GridCellContext({ required this.gridCell, required this.cellCache, required this.cellDataLoader, - }) : _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id), - _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id) { - _cellDataNotifier = ValueNotifier(cellCache.get(cacheKey)); - } + }) : _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id); String get gridId => gridCell.gridId; @@ -52,16 +50,20 @@ class GridCellContext { GridCellCacheKey get cacheKey => _cacheKey; void startListening({required void Function(T) onCellChanged}) { - _cellListener.updateCellNotifier?.addPublishListener((result) { - result.fold( - (notification) => _loadData(), - (err) => Log.error(err), - ); - }); - _cellListener.start(); + if (!isListening) { + isListening = true; + _cellDataNotifier = ValueNotifier(cellCache.get(cacheKey)); + _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); + _cellListener.start(onCellChanged: (result) { + result.fold( + (_) => _loadData(), + (err) => Log.error(err), + ); + }); - if (cellDataLoader.reloadOnFieldChanged) { - cellCache.addListener(cacheKey, () => reloadCellData()); + if (cellDataLoader.reloadOnFieldChanged) { + cellCache.addListener(cacheKey, () => reloadCellData()); + } } _cellDataNotifier.addListener(() { @@ -171,7 +173,7 @@ class GridCellCache { final String gridId; final GridCellFieldDelegate fieldDelegate; - /// fieldId: {rowId: callback} + /// fieldId: {objectId: callback} final Map> _cellListenerByFieldId = {}; /// fieldId: {cacheKey: cacheData} 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 576e62e3b1..d0d2999b6c 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 @@ -45,13 +45,15 @@ class FieldCellBloc extends Bloc { } void _startListening() { - _fieldListener.updateFieldNotifier?.addPublishListener((result) { + _fieldListener.start(onFieldChanged: (result) { + if (isClosed) { + return; + } result.fold( (field) => add(FieldCellEvent.didReceiveFieldUpdate(field)), (err) => Log.error(err), ); - }, listenWhen: () => !isClosed); - _fieldListener.start(); + }); } } 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 b31a9c3ff5..ec4ef77f30 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 @@ -11,12 +11,13 @@ typedef UpdateFieldNotifiedValue = Either; class SingleFieldListener { final String fieldId; - PublishNotifier? updateFieldNotifier = PublishNotifier(); + PublishNotifier? _updateFieldNotifier = PublishNotifier(); GridNotificationListener? _listener; SingleFieldListener({required this.fieldId}); - void start() { + void start({required void Function(UpdateFieldNotifiedValue) onFieldChanged}) { + _updateFieldNotifier?.addPublishListener(onFieldChanged); _listener = GridNotificationListener( objectId: fieldId, handler: _handler, @@ -30,8 +31,8 @@ class SingleFieldListener { switch (ty) { case GridNotification.DidUpdateField: result.fold( - (payload) => updateFieldNotifier?.value = left(Field.fromBuffer(payload)), - (error) => updateFieldNotifier?.value = right(error), + (payload) => _updateFieldNotifier?.value = left(Field.fromBuffer(payload)), + (error) => _updateFieldNotifier?.value = right(error), ); break; default: @@ -41,7 +42,7 @@ class SingleFieldListener { Future stop() async { await _listener?.stop(); - updateFieldNotifier?.dispose(); - updateFieldNotifier = null; + _updateFieldNotifier?.dispose(); + _updateFieldNotifier = null; } } 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 6774205a5e..e97d24a3e1 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 @@ -15,7 +15,8 @@ class GridFieldsListener { GridNotificationListener? _listener; GridFieldsListener({required this.gridId}); - void start() { + void start({required void Function(UpdateFieldNotifiedValue) onFieldsChanged}) { + updateFieldsNotifier?.addPublishListener(onFieldsChanged); _listener = GridNotificationListener( objectId: gridId, handler: _handler, 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 4ea13499cb..7911b46eef 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -60,7 +60,7 @@ class GridFieldCache { final FieldsNotifier _fieldNotifier = FieldsNotifier(); GridFieldCache({required this.gridId}) { _fieldListener = GridFieldsListener(gridId: gridId); - _fieldListener.updateFieldsNotifier?.addPublishListener((result) { + _fieldListener.start(onFieldsChanged: (result) { result.fold( (changeset) { _deleteFields(changeset.deletedFields); @@ -70,7 +70,6 @@ class GridFieldCache { (err) => Log.error(err), ); }); - _fieldListener.start(); } Future dispose() async { 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 c904f1a2f9..82879b647e 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 @@ -216,18 +216,18 @@ class RowsNotifier extends ChangeNotifier { _update(newRows, GridRowChangeReason.insert(insertIndexs)); } - void updateRows(List updatedRows) { + void updateRows(List updatedRows) { if (updatedRows.isEmpty) { return; } final UpdatedIndexs updatedIndexs = UpdatedIndexs(); final List newRows = clonedRows; - for (final rowOrder in updatedRows) { + for (final updatedRow in updatedRows) { + final rowOrder = updatedRow.rowOrder; final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId); if (index != -1) { - // Remove the old row data, the data will be filled if the loadRow method gets called. - _rowDataMap.remove(rowOrder.rowId); + _rowDataMap[rowOrder.rowId] = updatedRow.row; newRows.removeAt(index); newRows.insert(index, rowBuilder(rowOrder)); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index 44ab0813d1..adf088f5e4 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -3,7 +3,6 @@ import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart index e64431b1f9..30324be776 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart @@ -1081,12 +1081,77 @@ class IndexRowOrder extends $pb.GeneratedMessage { void clearIndex() => clearField(2); } +class UpdatedRowOrder extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdatedRowOrder', createEmptyInstance: create) + ..aOM(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrder', subBuilder: RowOrder.create) + ..aOM(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'row', subBuilder: Row.create) + ..hasRequiredFields = false + ; + + UpdatedRowOrder._() : super(); + factory UpdatedRowOrder({ + RowOrder? rowOrder, + Row? row, + }) { + final _result = create(); + if (rowOrder != null) { + _result.rowOrder = rowOrder; + } + if (row != null) { + _result.row = row; + } + return _result; + } + factory UpdatedRowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory UpdatedRowOrder.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' + 'Will be removed in next major version') + UpdatedRowOrder clone() => UpdatedRowOrder()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + UpdatedRowOrder copyWith(void Function(UpdatedRowOrder) updates) => super.copyWith((message) => updates(message as UpdatedRowOrder)) as UpdatedRowOrder; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static UpdatedRowOrder create() => UpdatedRowOrder._(); + UpdatedRowOrder createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static UpdatedRowOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static UpdatedRowOrder? _defaultInstance; + + @$pb.TagNumber(1) + RowOrder get rowOrder => $_getN(0); + @$pb.TagNumber(1) + set rowOrder(RowOrder v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasRowOrder() => $_has(0); + @$pb.TagNumber(1) + void clearRowOrder() => clearField(1); + @$pb.TagNumber(1) + RowOrder ensureRowOrder() => $_ensure(0); + + @$pb.TagNumber(2) + Row get row => $_getN(1); + @$pb.TagNumber(2) + set row(Row v) { setField(2, v); } + @$pb.TagNumber(2) + $core.bool hasRow() => $_has(1); + @$pb.TagNumber(2) + void clearRow() => clearField(2); + @$pb.TagNumber(2) + Row ensureRow() => $_ensure(1); +} + class GridRowsChangeset extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridRowsChangeset', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId') ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertedRows', $pb.PbFieldType.PM, subBuilder: IndexRowOrder.create) ..pc(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deletedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create) - ..pc(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create) + ..pc(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedRows', $pb.PbFieldType.PM, subBuilder: UpdatedRowOrder.create) ..hasRequiredFields = false ; @@ -1095,7 +1160,7 @@ class GridRowsChangeset extends $pb.GeneratedMessage { $core.String? blockId, $core.Iterable? insertedRows, $core.Iterable? deletedRows, - $core.Iterable? updatedRows, + $core.Iterable? updatedRows, }) { final _result = create(); if (blockId != null) { @@ -1149,7 +1214,7 @@ class GridRowsChangeset extends $pb.GeneratedMessage { $core.List get deletedRows => $_getList(2); @$pb.TagNumber(4) - $core.List get updatedRows => $_getList(3); + $core.List get updatedRows => $_getList(3); } class GridBlock extends $pb.GeneratedMessage { @@ -1268,108 +1333,6 @@ class Cell extends $pb.GeneratedMessage { void clearContent() => clearField(2); } -enum CellNotificationData_OneOfContent { - content, - notSet -} - -class CellNotificationData extends $pb.GeneratedMessage { - static const $core.Map<$core.int, CellNotificationData_OneOfContent> _CellNotificationData_OneOfContentByTag = { - 4 : CellNotificationData_OneOfContent.content, - 0 : CellNotificationData_OneOfContent.notSet - }; - static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CellNotificationData', createEmptyInstance: create) - ..oo(0, [4]) - ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') - ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') - ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') - ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content') - ..hasRequiredFields = false - ; - - CellNotificationData._() : super(); - factory CellNotificationData({ - $core.String? gridId, - $core.String? fieldId, - $core.String? rowId, - $core.String? content, - }) { - final _result = create(); - if (gridId != null) { - _result.gridId = gridId; - } - if (fieldId != null) { - _result.fieldId = fieldId; - } - if (rowId != null) { - _result.rowId = rowId; - } - if (content != null) { - _result.content = content; - } - return _result; - } - factory CellNotificationData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory CellNotificationData.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' - 'Will be removed in next major version') - CellNotificationData clone() => CellNotificationData()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - CellNotificationData copyWith(void Function(CellNotificationData) updates) => super.copyWith((message) => updates(message as CellNotificationData)) as CellNotificationData; // ignore: deprecated_member_use - $pb.BuilderInfo get info_ => _i; - @$core.pragma('dart2js:noInline') - static CellNotificationData create() => CellNotificationData._(); - CellNotificationData createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static CellNotificationData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static CellNotificationData? _defaultInstance; - - CellNotificationData_OneOfContent whichOneOfContent() => _CellNotificationData_OneOfContentByTag[$_whichOneof(0)]!; - void clearOneOfContent() => clearField($_whichOneof(0)); - - @$pb.TagNumber(1) - $core.String get gridId => $_getSZ(0); - @$pb.TagNumber(1) - set gridId($core.String v) { $_setString(0, v); } - @$pb.TagNumber(1) - $core.bool hasGridId() => $_has(0); - @$pb.TagNumber(1) - void clearGridId() => clearField(1); - - @$pb.TagNumber(2) - $core.String get fieldId => $_getSZ(1); - @$pb.TagNumber(2) - set fieldId($core.String v) { $_setString(1, v); } - @$pb.TagNumber(2) - $core.bool hasFieldId() => $_has(1); - @$pb.TagNumber(2) - void clearFieldId() => clearField(2); - - @$pb.TagNumber(3) - $core.String get rowId => $_getSZ(2); - @$pb.TagNumber(3) - set rowId($core.String v) { $_setString(2, v); } - @$pb.TagNumber(3) - $core.bool hasRowId() => $_has(2); - @$pb.TagNumber(3) - void clearRowId() => clearField(3); - - @$pb.TagNumber(4) - $core.String get content => $_getSZ(3); - @$pb.TagNumber(4) - set content($core.String v) { $_setString(3, v); } - @$pb.TagNumber(4) - $core.bool hasContent() => $_has(3); - @$pb.TagNumber(4) - void clearContent() => clearField(4); -} - class RepeatedCell extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedCell', createEmptyInstance: create) ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Cell.create) diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart index 722a8ebcd6..8ec90dddf9 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart @@ -236,6 +236,17 @@ const IndexRowOrder$json = const { /// Descriptor for `IndexRowOrder`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List indexRowOrderDescriptor = $convert.base64Decode('Cg1JbmRleFJvd09yZGVyEiYKCXJvd19vcmRlchgBIAEoCzIJLlJvd09yZGVyUghyb3dPcmRlchIWCgVpbmRleBgCIAEoBUgAUgVpbmRleEIOCgxvbmVfb2ZfaW5kZXg='); +@$core.Deprecated('Use updatedRowOrderDescriptor instead') +const UpdatedRowOrder$json = const { + '1': 'UpdatedRowOrder', + '2': const [ + const {'1': 'row_order', '3': 1, '4': 1, '5': 11, '6': '.RowOrder', '10': 'rowOrder'}, + const {'1': 'row', '3': 2, '4': 1, '5': 11, '6': '.Row', '10': 'row'}, + ], +}; + +/// Descriptor for `UpdatedRowOrder`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List updatedRowOrderDescriptor = $convert.base64Decode('Cg9VcGRhdGVkUm93T3JkZXISJgoJcm93X29yZGVyGAEgASgLMgkuUm93T3JkZXJSCHJvd09yZGVyEhYKA3JvdxgCIAEoCzIELlJvd1IDcm93'); @$core.Deprecated('Use gridRowsChangesetDescriptor instead') const GridRowsChangeset$json = const { '1': 'GridRowsChangeset', @@ -243,12 +254,12 @@ const GridRowsChangeset$json = const { const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, const {'1': 'inserted_rows', '3': 2, '4': 3, '5': 11, '6': '.IndexRowOrder', '10': 'insertedRows'}, const {'1': 'deleted_rows', '3': 3, '4': 3, '5': 11, '6': '.RowOrder', '10': 'deletedRows'}, - const {'1': 'updated_rows', '3': 4, '4': 3, '5': 11, '6': '.RowOrder', '10': 'updatedRows'}, + const {'1': 'updated_rows', '3': 4, '4': 3, '5': 11, '6': '.UpdatedRowOrder', '10': 'updatedRows'}, ], }; /// Descriptor for `GridRowsChangeset`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List gridRowsChangesetDescriptor = $convert.base64Decode('ChFHcmlkUm93c0NoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIsCgx1cGRhdGVkX3Jvd3MYBCADKAsyCS5Sb3dPcmRlclILdXBkYXRlZFJvd3M='); +final $typed_data.Uint8List gridRowsChangesetDescriptor = $convert.base64Decode('ChFHcmlkUm93c0NoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIzCgx1cGRhdGVkX3Jvd3MYBCADKAsyEC5VcGRhdGVkUm93T3JkZXJSC3VwZGF0ZWRSb3dz'); @$core.Deprecated('Use gridBlockDescriptor instead') const GridBlock$json = const { '1': 'GridBlock', @@ -271,22 +282,6 @@ const Cell$json = const { /// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQ='); -@$core.Deprecated('Use cellNotificationDataDescriptor instead') -const CellNotificationData$json = const { - '1': 'CellNotificationData', - '2': const [ - const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, - const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'}, - const {'1': 'row_id', '3': 3, '4': 1, '5': 9, '10': 'rowId'}, - const {'1': 'content', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'content'}, - ], - '8': const [ - const {'1': 'one_of_content'}, - ], -}; - -/// Descriptor for `CellNotificationData`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List cellNotificationDataDescriptor = $convert.base64Decode('ChRDZWxsTm90aWZpY2F0aW9uRGF0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSGQoIZmllbGRfaWQYAiABKAlSB2ZpZWxkSWQSFQoGcm93X2lkGAMgASgJUgVyb3dJZBIaCgdjb250ZW50GAQgASgJSABSB2NvbnRlbnRCEAoOb25lX29mX2NvbnRlbnQ='); @$core.Deprecated('Use repeatedCellDescriptor instead') const RepeatedCell$json = const { '1': 'RepeatedCell', diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs index cdc06d8723..7853d99c18 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs @@ -6,13 +6,14 @@ use crate::services::row::{group_row_orders, GridBlockSnapshot}; use std::borrow::Cow; use dashmap::DashMap; -use flowy_error::FlowyResult; +use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{ - CellChangeset, CellMeta, CellNotificationData, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, - IndexRowOrder, RowMeta, RowMetaChangeset, RowOrder, + Cell, CellChangeset, CellMeta, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, IndexRowOrder, Row, + RowMeta, RowMetaChangeset, RowOrder, UpdatedRowOrder, }; use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; use flowy_revision::{RevisionManager, RevisionPersistence}; +use lib_infra::future::FutureResult; use std::collections::HashMap; use std::sync::Arc; @@ -108,10 +109,22 @@ impl GridBlockMetaEditorManager { Ok(changesets) } - pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { + pub async fn update_row(&self, changeset: RowMetaChangeset, row_builder: F) -> FlowyResult<()> + where + F: FnOnce(Arc) -> Option, + { let editor = self.get_editor_from_row_id(&changeset.row_id).await?; let _ = editor.update_row(changeset.clone()).await?; - let _ = self.notify_did_update_block_row(&changeset.row_id).await?; + match editor.get_row_meta(&changeset.row_id).await? { + None => tracing::error!("Internal error: can't find the row with id: {}", changeset.row_id), + Some(row_meta) => { + if let Some(row) = row_builder(row_meta.clone()) { + let row_order = UpdatedRowOrder::new(&row_meta, row); + let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]); + let _ = self.notify_did_update_block(block_order_changeset).await?; + } + } + } Ok(()) } @@ -175,18 +188,13 @@ impl GridBlockMetaEditorManager { Ok(()) } - pub async fn update_cell(&self, changeset: CellChangeset) -> FlowyResult<()> { + pub async fn update_cell(&self, changeset: CellChangeset, row_builder: F) -> FlowyResult<()> + where + F: FnOnce(Arc) -> Option, + { let row_changeset: RowMetaChangeset = changeset.clone().into(); - let _ = self.update_row(row_changeset).await?; - - let cell_notification_data = CellNotificationData { - grid_id: changeset.grid_id, - field_id: changeset.field_id, - row_id: changeset.row_id, - content: changeset.data, - }; - self.notify_did_update_cell(cell_notification_data).await?; - + let _ = self.update_row(row_changeset, row_builder).await?; + self.notify_did_update_cell(changeset).await?; Ok(()) } @@ -233,19 +241,6 @@ impl GridBlockMetaEditorManager { Ok(block_cell_metas) } - async fn notify_did_update_block_row(&self, row_id: &str) -> FlowyResult<()> { - let editor = self.get_editor_from_row_id(row_id).await?; - match editor.get_row_order(row_id).await? { - None => {} - Some(row_order) => { - let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]); - let _ = self.notify_did_update_block(block_order_changeset).await?; - } - } - - Ok(()) - } - async fn notify_did_update_block(&self, changeset: GridRowsChangeset) -> FlowyResult<()> { send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridRow) .payload(changeset) @@ -253,11 +248,9 @@ impl GridBlockMetaEditorManager { Ok(()) } - async fn notify_did_update_cell(&self, data: CellNotificationData) -> FlowyResult<()> { - let id = format!("{}:{}", data.row_id, data.field_id); - send_dart_notification(&id, GridNotification::DidUpdateCell) - .payload(data) - .send(); + async fn notify_did_update_cell(&self, changeset: CellChangeset) -> 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/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 8f30c0a7cd..05437f46cd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -247,7 +247,10 @@ impl ClientGridEditor { } pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { - self.block_meta_manager.update_row(changeset).await + let field_metas = self.get_field_metas::(None).await?; + self.block_meta_manager + .update_row(changeset, |row_meta| make_row_from_row_meta(&field_metas, row_meta)) + .await } pub async fn get_rows(&self, block_id: &str) -> FlowyResult { @@ -322,7 +325,11 @@ impl ClientGridEditor { Some((_, field_meta)) => { // Update the changeset.data property with the return value. changeset.data = Some(apply_cell_data_changeset(cell_data_changeset, cell_meta, field_meta)?); - let _ = self.block_meta_manager.update_cell(changeset).await?; + let field_metas = self.get_field_metas::(None).await?; + let _ = self + .block_meta_manager + .update_cell(changeset, |row_meta| make_row_from_row_meta(&field_metas, row_meta)) + .await?; Ok(()) } } @@ -423,6 +430,11 @@ impl ClientGridEditor { self.grid_pad.read().await.delta_bytes() } + async fn row_builder(&self, row_meta: Arc) -> FlowyResult> { + let field_metas = self.get_field_metas::(None).await?; + Ok(make_rows_from_row_metas(&field_metas, &[row_meta]).pop()) + } + async fn modify(&self, f: F) -> FlowyResult<()> where F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult>, 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 770ba758e9..35357a0c83 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 @@ -47,6 +47,10 @@ pub(crate) fn make_row_orders_from_row_metas(row_metas: &[Arc]) -> Vec< row_metas.iter().map(RowOrder::from).collect::>() } +pub(crate) fn make_row_from_row_meta(fields: &[FieldMeta], row_meta: Arc) -> Option { + make_rows_from_row_metas(fields, &vec![row_meta]).pop() +} + pub(crate) fn make_rows_from_row_metas(fields: &[FieldMeta], row_metas: &[Arc]) -> Vec { let field_meta_map = fields .iter() diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs index d246fd490b..c2f6d3841b 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -352,7 +352,25 @@ pub struct IndexRowOrder { pub index: Option, } -#[derive(Debug, Clone, Default, ProtoBuf)] +#[derive(Debug, Default, ProtoBuf)] +pub struct UpdatedRowOrder { + #[pb(index = 1)] + pub row_order: RowOrder, + + #[pb(index = 2)] + pub row: Row, +} + +impl UpdatedRowOrder { + pub fn new(row_meta: &RowMeta, row: Row) -> Self { + Self { + row_order: RowOrder::from(row_meta), + row, + } + } +} + +#[derive(Debug, Default, ProtoBuf)] pub struct GridRowsChangeset { #[pb(index = 1)] pub block_id: String, @@ -364,7 +382,7 @@ pub struct GridRowsChangeset { pub deleted_rows: Vec, #[pb(index = 4)] - pub updated_rows: Vec, + pub updated_rows: Vec, } impl std::convert::From for IndexRowOrder { @@ -399,7 +417,7 @@ impl GridRowsChangeset { } } - 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(), inserted_rows: vec![], @@ -445,21 +463,6 @@ impl Cell { } } -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct CellNotificationData { - #[pb(index = 1)] - pub grid_id: String, - - #[pb(index = 2)] - pub field_id: String, - - #[pb(index = 3)] - pub row_id: String, - - #[pb(index = 4, one_of)] - pub content: Option, -} - #[derive(Debug, Default, ProtoBuf)] pub struct RepeatedCell { #[pb(index = 1)] diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs index 754fc11386..ccf489b8fd 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs @@ -3701,13 +3701,244 @@ impl ::protobuf::reflect::ProtobufValue for IndexRowOrder { } } +#[derive(PartialEq,Clone,Default)] +pub struct UpdatedRowOrder { + // message fields + pub row_order: ::protobuf::SingularPtrField, + pub row: ::protobuf::SingularPtrField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a UpdatedRowOrder { + fn default() -> &'a UpdatedRowOrder { + ::default_instance() + } +} + +impl UpdatedRowOrder { + pub fn new() -> UpdatedRowOrder { + ::std::default::Default::default() + } + + // .RowOrder row_order = 1; + + + pub fn get_row_order(&self) -> &RowOrder { + self.row_order.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_row_order(&mut self) { + self.row_order.clear(); + } + + pub fn has_row_order(&self) -> bool { + self.row_order.is_some() + } + + // Param is passed by value, moved + pub fn set_row_order(&mut self, v: RowOrder) { + self.row_order = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row_order(&mut self) -> &mut RowOrder { + if self.row_order.is_none() { + self.row_order.set_default(); + } + self.row_order.as_mut().unwrap() + } + + // Take field + pub fn take_row_order(&mut self) -> RowOrder { + self.row_order.take().unwrap_or_else(|| RowOrder::new()) + } + + // .Row row = 2; + + + pub fn get_row(&self) -> &Row { + self.row.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_row(&mut self) { + self.row.clear(); + } + + pub fn has_row(&self) -> bool { + self.row.is_some() + } + + // Param is passed by value, moved + pub fn set_row(&mut self, v: Row) { + self.row = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_row(&mut self) -> &mut Row { + if self.row.is_none() { + self.row.set_default(); + } + self.row.as_mut().unwrap() + } + + // Take field + pub fn take_row(&mut self) -> Row { + self.row.take().unwrap_or_else(|| Row::new()) + } +} + +impl ::protobuf::Message for UpdatedRowOrder { + fn is_initialized(&self) -> bool { + for v in &self.row_order { + if !v.is_initialized() { + return false; + } + }; + for v in &self.row { + if !v.is_initialized() { + return false; + } + }; + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.row_order)?; + }, + 2 => { + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.row)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.row_order.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let Some(ref v) = self.row.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.row_order.as_ref() { + os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + if let Some(ref v) = self.row.as_ref() { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> UpdatedRowOrder { + UpdatedRowOrder::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "row_order", + |m: &UpdatedRowOrder| { &m.row_order }, + |m: &mut UpdatedRowOrder| { &mut m.row_order }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "row", + |m: &UpdatedRowOrder| { &m.row }, + |m: &mut UpdatedRowOrder| { &mut m.row }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "UpdatedRowOrder", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static UpdatedRowOrder { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(UpdatedRowOrder::new) + } +} + +impl ::protobuf::Clear for UpdatedRowOrder { + fn clear(&mut self) { + self.row_order.clear(); + self.row.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for UpdatedRowOrder { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for UpdatedRowOrder { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct GridRowsChangeset { // message fields pub block_id: ::std::string::String, pub inserted_rows: ::protobuf::RepeatedField, pub deleted_rows: ::protobuf::RepeatedField, - pub updated_rows: ::protobuf::RepeatedField, + pub updated_rows: ::protobuf::RepeatedField, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -3800,10 +4031,10 @@ impl GridRowsChangeset { ::std::mem::replace(&mut self.deleted_rows, ::protobuf::RepeatedField::new()) } - // repeated .RowOrder updated_rows = 4; + // repeated .UpdatedRowOrder updated_rows = 4; - pub fn get_updated_rows(&self) -> &[RowOrder] { + pub fn get_updated_rows(&self) -> &[UpdatedRowOrder] { &self.updated_rows } pub fn clear_updated_rows(&mut self) { @@ -3811,17 +4042,17 @@ impl GridRowsChangeset { } // Param is passed by value, moved - pub fn set_updated_rows(&mut self, v: ::protobuf::RepeatedField) { + pub fn set_updated_rows(&mut self, v: ::protobuf::RepeatedField) { self.updated_rows = v; } // Mutable pointer to the field. - pub fn mut_updated_rows(&mut self) -> &mut ::protobuf::RepeatedField { + pub fn mut_updated_rows(&mut self) -> &mut ::protobuf::RepeatedField { &mut self.updated_rows } // Take field - pub fn take_updated_rows(&mut self) -> ::protobuf::RepeatedField { + pub fn take_updated_rows(&mut self) -> ::protobuf::RepeatedField { ::std::mem::replace(&mut self.updated_rows, ::protobuf::RepeatedField::new()) } } @@ -3966,7 +4197,7 @@ impl ::protobuf::Message for GridRowsChangeset { |m: &GridRowsChangeset| { &m.deleted_rows }, |m: &mut GridRowsChangeset| { &mut m.deleted_rows }, )); - fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "updated_rows", |m: &GridRowsChangeset| { &m.updated_rows }, |m: &mut GridRowsChangeset| { &mut m.updated_rows }, @@ -4416,331 +4647,6 @@ impl ::protobuf::reflect::ProtobufValue for Cell { } } -#[derive(PartialEq,Clone,Default)] -pub struct CellNotificationData { - // message fields - pub grid_id: ::std::string::String, - pub field_id: ::std::string::String, - pub row_id: ::std::string::String, - // message oneof groups - pub one_of_content: ::std::option::Option, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a CellNotificationData { - fn default() -> &'a CellNotificationData { - ::default_instance() - } -} - -#[derive(Clone,PartialEq,Debug)] -pub enum CellNotificationData_oneof_one_of_content { - content(::std::string::String), -} - -impl CellNotificationData { - pub fn new() -> CellNotificationData { - ::std::default::Default::default() - } - - // string grid_id = 1; - - - pub fn get_grid_id(&self) -> &str { - &self.grid_id - } - pub fn clear_grid_id(&mut self) { - self.grid_id.clear(); - } - - // Param is passed by value, moved - pub fn set_grid_id(&mut self, v: ::std::string::String) { - self.grid_id = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { - &mut self.grid_id - } - - // Take field - pub fn take_grid_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) - } - - // string field_id = 2; - - - pub fn get_field_id(&self) -> &str { - &self.field_id - } - pub fn clear_field_id(&mut self) { - self.field_id.clear(); - } - - // Param is passed by value, moved - pub fn set_field_id(&mut self, v: ::std::string::String) { - self.field_id = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_field_id(&mut self) -> &mut ::std::string::String { - &mut self.field_id - } - - // Take field - pub fn take_field_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) - } - - // string row_id = 3; - - - pub fn get_row_id(&self) -> &str { - &self.row_id - } - pub fn clear_row_id(&mut self) { - self.row_id.clear(); - } - - // Param is passed by value, moved - pub fn set_row_id(&mut self, v: ::std::string::String) { - self.row_id = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_row_id(&mut self) -> &mut ::std::string::String { - &mut self.row_id - } - - // Take field - pub fn take_row_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.row_id, ::std::string::String::new()) - } - - // string content = 4; - - - pub fn get_content(&self) -> &str { - match self.one_of_content { - ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(ref v)) => v, - _ => "", - } - } - pub fn clear_content(&mut self) { - self.one_of_content = ::std::option::Option::None; - } - - pub fn has_content(&self) -> bool { - match self.one_of_content { - ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(..)) => true, - _ => false, - } - } - - // Param is passed by value, moved - pub fn set_content(&mut self, v: ::std::string::String) { - self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(v)) - } - - // Mutable pointer to the field. - pub fn mut_content(&mut self) -> &mut ::std::string::String { - if let ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(_)) = self.one_of_content { - } else { - self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(::std::string::String::new())); - } - match self.one_of_content { - ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(ref mut v)) => v, - _ => panic!(), - } - } - - // Take field - pub fn take_content(&mut self) -> ::std::string::String { - if self.has_content() { - match self.one_of_content.take() { - ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(v)) => v, - _ => panic!(), - } - } else { - ::std::string::String::new() - } - } -} - -impl ::protobuf::Message for CellNotificationData { - fn is_initialized(&self) -> bool { - true - } - - fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { - while !is.eof()? { - let (field_number, wire_type) = is.read_tag_unpack()?; - match field_number { - 1 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; - }, - 2 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; - }, - 3 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?; - }, - 4 => { - if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - self.one_of_content = ::std::option::Option::Some(CellNotificationData_oneof_one_of_content::content(is.read_string()?)); - }, - _ => { - ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; - }, - }; - } - ::std::result::Result::Ok(()) - } - - // Compute sizes of nested messages - #[allow(unused_variables)] - fn compute_size(&self) -> u32 { - let mut my_size = 0; - if !self.grid_id.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.grid_id); - } - if !self.field_id.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.field_id); - } - if !self.row_id.is_empty() { - my_size += ::protobuf::rt::string_size(3, &self.row_id); - } - if let ::std::option::Option::Some(ref v) = self.one_of_content { - match v { - &CellNotificationData_oneof_one_of_content::content(ref v) => { - my_size += ::protobuf::rt::string_size(4, &v); - }, - }; - } - my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); - self.cached_size.set(my_size); - my_size - } - - fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.grid_id.is_empty() { - os.write_string(1, &self.grid_id)?; - } - if !self.field_id.is_empty() { - os.write_string(2, &self.field_id)?; - } - if !self.row_id.is_empty() { - os.write_string(3, &self.row_id)?; - } - if let ::std::option::Option::Some(ref v) = self.one_of_content { - match v { - &CellNotificationData_oneof_one_of_content::content(ref v) => { - os.write_string(4, v)?; - }, - }; - } - os.write_unknown_fields(self.get_unknown_fields())?; - ::std::result::Result::Ok(()) - } - - fn get_cached_size(&self) -> u32 { - self.cached_size.get() - } - - fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { - &self.unknown_fields - } - - fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { - &mut self.unknown_fields - } - - fn as_any(&self) -> &dyn (::std::any::Any) { - self as &dyn (::std::any::Any) - } - fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { - self as &mut dyn (::std::any::Any) - } - fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { - self - } - - fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { - Self::descriptor_static() - } - - fn new() -> CellNotificationData { - CellNotificationData::new() - } - - fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { - static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; - descriptor.get(|| { - let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "grid_id", - |m: &CellNotificationData| { &m.grid_id }, - |m: &mut CellNotificationData| { &mut m.grid_id }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "field_id", - |m: &CellNotificationData| { &m.field_id }, - |m: &mut CellNotificationData| { &mut m.field_id }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "row_id", - |m: &CellNotificationData| { &m.row_id }, - |m: &mut CellNotificationData| { &mut m.row_id }, - )); - fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( - "content", - CellNotificationData::has_content, - CellNotificationData::get_content, - )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "CellNotificationData", - fields, - file_descriptor_proto() - ) - }) - } - - fn default_instance() -> &'static CellNotificationData { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(CellNotificationData::new) - } -} - -impl ::protobuf::Clear for CellNotificationData { - fn clear(&mut self) { - self.grid_id.clear(); - self.field_id.clear(); - self.row_id.clear(); - self.one_of_content = ::std::option::Option::None; - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for CellNotificationData { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for CellNotificationData { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Message(self) - } -} - #[derive(PartialEq,Clone,Default)] pub struct RepeatedCell { // message fields @@ -7843,56 +7749,54 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\x18\ \x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\x12&\n\tro\ w_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05index\ - \x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"\xbf\x01\n\ - \x11GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07block\ - Id\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cins\ - ertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bde\ - letedRows\x12,\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0bup\ - datedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12(\ - \n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\x04Cell\ - \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07conte\ - nt\x18\x02\x20\x01(\tR\x07content\"\x8f\x01\n\x14CellNotificationData\ - \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_i\ - d\x18\x02\x20\x01(\tR\x07fieldId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\ - \x05rowId\x12\x1a\n\x07content\x18\x04\x20\x01(\tH\0R\x07contentB\x10\n\ - \x0eone_of_content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\ - \x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\n\x04nam\ - e\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\ - \x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\x14\n\x05value\x18\x01\ - \x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid_id\x18\ - \x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0\ - R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12InsertFieldPa\ - yload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05fi\ - eld\x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\x12(\n\x10type_option_data\ - \x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\n\x0estart_field_id\x18\ - \x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_field_id\"d\n\ - \x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\ - \x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\ - \x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\ - \x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\ - \x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\x15FieldChangesetPayload\ - \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\ - id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0\ - R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfie\ - ld_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\x06\ - frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\x18\ - \x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\x01(\ - \x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\x06R\ - \x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one\ - _of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\ - \x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0fMoveIt\ - emPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x17\n\ - \x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\x18\x03\ - \x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\x05R\ - \x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\x02ty\ - \"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06grid\ - Id\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_i\ - d\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\x20\x01(\tH\0\ - R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\x12\r\n\tMoveField\x10\ - \0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\ - \0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0c\ - SingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Check\ - box\x10\x05b\x06proto3\ + \x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"Q\n\x0fUpdate\ + dRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrde\ + r\x12\x16\n\x03row\x18\x02\x20\x01(\x0b2\x04.RowR\x03row\"\xc6\x01\n\x11\ + GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\ + \x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cinser\ + tedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bdele\ + tedRows\x123\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\x10.UpdatedRowOrder\ + R\x0bupdatedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02\ + id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\ + \x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\ + \x07content\x18\x02\x20\x01(\tR\x07content\"+\n\x0cRepeatedCell\x12\x1b\ + \n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridP\ + ayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\ + \x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\ + \x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\ + \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row\ + _id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\ + \xb6\x01\n\x12InsertFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\t\ + R\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\ + \x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\ + \n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15on\ + e_of_start_field_id\"d\n\x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\ + \x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\ + \x13.RepeatedFieldOrderR\x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\ + \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orde\ + rs\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\ + \x15FieldChangesetPayload\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07f\ + ieldId\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04n\ + ame\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\ + \x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\ + \tfieldType\x12\x18\n\x06frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\ + \x20\n\nvisibility\x18\x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05w\ + idth\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10type_option_data\x18\ + \t\x20\x01(\x0cH\x06R\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_\ + of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_\ + of_visibilityB\x0e\n\x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\ + \x9c\x01\n\x0fMoveItemPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\ + \x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\ + \nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\ + \x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.Mo\ + veItemTypeR\x02ty\"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\ + \x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\ + \x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\ + \x18\x04\x20\x01(\tH\0R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\ + \x12\r\n\tMoveField\x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\ + \x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08Date\ + Time\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\ + \x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto index 2d6dbecfe4..5d72f77302 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto +++ b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto @@ -73,11 +73,15 @@ message IndexRowOrder { RowOrder row_order = 1; oneof one_of_index { int32 index = 2; }; } +message UpdatedRowOrder { + RowOrder row_order = 1; + Row row = 2; +} message GridRowsChangeset { string block_id = 1; repeated IndexRowOrder inserted_rows = 2; repeated RowOrder deleted_rows = 3; - repeated RowOrder updated_rows = 4; + repeated UpdatedRowOrder updated_rows = 4; } message GridBlock { string id = 1; @@ -87,12 +91,6 @@ message Cell { string field_id = 1; string content = 2; } -message CellNotificationData { - string grid_id = 1; - string field_id = 2; - string row_id = 3; - oneof one_of_content { string content = 4; }; -} message RepeatedCell { repeated Cell items = 1; } From 8b4c46f75b2fdd6cf76cb0566e145d2a2ba27d18 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 25 Apr 2022 21:20:08 +0800 Subject: [PATCH 11/12] chore: clone cell context --- .../application/grid/cell/cell_service.dart | 148 ++++++++++++------ .../grid/cell/checkbox_cell_bloc.dart | 8 +- .../application/grid/cell/date_cell_bloc.dart | 7 +- .../grid/cell/number_cell_bloc.dart | 8 +- .../grid/cell/select_option_service.dart | 5 +- .../grid/cell/selection_cell_bloc.dart | 7 +- .../grid/cell/selection_editor_bloc.dart | 7 +- .../application/grid/cell/text_cell_bloc.dart | 7 +- .../grid/src/widgets/cell/cell_builder.dart | 5 + .../cell/selection_cell/selection_cell.dart | 19 ++- 10 files changed, 158 insertions(+), 63 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index 6c0128a848..d2188776cd 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -11,13 +11,13 @@ import 'package:flowy_sdk/protobuf/flowy-grid/selection_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:equatable/equatable.dart'; part 'cell_service.freezed.dart'; typedef GridDefaultCellContext = GridCellContext; typedef GridSelectOptionCellContext = GridCellContext; -class GridCellContext { +class GridCellContext extends Equatable { final GridCell gridCell; final GridCellCache cellCache; final GridCellCacheKey _cacheKey; @@ -27,6 +27,7 @@ class GridCellContext { late final CellListener _cellListener; late final ValueNotifier _cellDataNotifier; bool isListening = false; + VoidCallback? _onFieldChangedFn; Timer? _delayOperation; GridCellContext({ @@ -35,6 +36,14 @@ class GridCellContext { required this.cellDataLoader, }) : _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id); + GridCellContext clone() { + return GridCellContext( + gridCell: gridCell, + cellDataLoader: cellDataLoader, + cellCache: cellCache, + ); + } + String get gridId => gridCell.gridId; String get rowId => gridCell.rowId; @@ -49,29 +58,47 @@ class GridCellContext { GridCellCacheKey get cacheKey => _cacheKey; - void startListening({required void Function(T) onCellChanged}) { - if (!isListening) { - isListening = true; - _cellDataNotifier = ValueNotifier(cellCache.get(cacheKey)); - _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); - _cellListener.start(onCellChanged: (result) { - result.fold( - (_) => _loadData(), - (err) => Log.error(err), - ); - }); - - if (cellDataLoader.reloadOnFieldChanged) { - cellCache.addListener(cacheKey, () => reloadCellData()); - } + VoidCallback? startListening({required void Function(T) onCellChanged}) { + if (isListening) { + Log.error("Already started. It seems like you should call clone first"); + return null; } - _cellDataNotifier.addListener(() { + isListening = true; + _cellDataNotifier = ValueNotifier(cellCache.get(cacheKey)); + _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); + _cellListener.start(onCellChanged: (result) { + result.fold( + (_) => _loadData(), + (err) => Log.error(err), + ); + }); + + if (cellDataLoader.reloadOnFieldChanged) { + _onFieldChangedFn = () { + Log.info("reloadCellData "); + _loadData(); + }; + cellCache.addListener(cacheKey, _onFieldChangedFn!); + } + + onCellChangedFn() { final value = _cellDataNotifier.value; if (value is T) { onCellChanged(value); } - }); + + if (cellDataLoader.reloadOnCellChanged) { + _loadData(); + } + } + + _cellDataNotifier.addListener(onCellChangedFn); + return onCellChangedFn; + } + + void removeListener(VoidCallback fn) { + _cellDataNotifier.removeListener(fn); } T? getCellData() { @@ -82,47 +109,56 @@ class GridCellContext { return data; } - void setCellData(T? data) { - cellCache.insert(GridCellCacheData(key: cacheKey, object: data)); - } - void saveCellData(String data) { _cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data).then((result) { result.fold((l) => null, (err) => Log.error(err)); }); } - void reloadCellData() { - _loadData(); - } - void _loadData() { _delayOperation?.cancel(); _delayOperation = Timer(const Duration(milliseconds: 10), () { cellDataLoader.loadData().then((data) { _cellDataNotifier.value = data; - setCellData(data); + cellCache.insert(GridCellCacheData(key: cacheKey, object: data)); }); }); } void dispose() { _delayOperation?.cancel(); + + if (_onFieldChangedFn != null) { + cellCache.removeListener(cacheKey, _onFieldChangedFn!); + _onFieldChangedFn = null; + } } + + @override + List get props => [cellCache.get(cacheKey) ?? "", cellId]; } abstract class GridCellDataLoader { Future loadData(); bool get reloadOnFieldChanged => true; + bool get reloadOnCellChanged => false; } -class DefaultCellDataLoader implements GridCellDataLoader { +abstract class GridCellDataConfig { + bool get reloadOnFieldChanged => true; + bool get reloadOnCellChanged => false; +} + +class DefaultCellDataLoader extends GridCellDataLoader { final CellService service = CellService(); final GridCell gridCell; + @override + final bool reloadOnCellChanged; DefaultCellDataLoader({ required this.gridCell, + this.reloadOnCellChanged = false, }); @override @@ -139,9 +175,6 @@ class DefaultCellDataLoader implements GridCellDataLoader { }); }); } - - @override - bool get reloadOnFieldChanged => true; } // key: rowId @@ -174,51 +207,63 @@ class GridCellCache { final GridCellFieldDelegate fieldDelegate; /// fieldId: {objectId: callback} - final Map> _cellListenerByFieldId = {}; + final Map>> _listenerByFieldId = {}; /// fieldId: {cacheKey: cacheData} - final Map> _cellCacheByFieldId = {}; + final Map> _cellDataByFieldId = {}; GridCellCache({ required this.gridId, required this.fieldDelegate, }) { fieldDelegate.onFieldChanged((fieldId) { - _cellCacheByFieldId.remove(fieldId); - final map = _cellListenerByFieldId[fieldId]; + _cellDataByFieldId.remove(fieldId); + final map = _listenerByFieldId[fieldId]; if (map != null) { - for (final callback in map.values) { - callback(); + for (final callbacks in map.values) { + for (final callback in callbacks) { + callback(); + } } } }); } void addListener(GridCellCacheKey cacheKey, VoidCallback callback) { - var map = _cellListenerByFieldId[cacheKey.fieldId]; + var map = _listenerByFieldId[cacheKey.fieldId]; if (map == null) { - _cellListenerByFieldId[cacheKey.fieldId] = {}; - map = _cellListenerByFieldId[cacheKey.fieldId]; + _listenerByFieldId[cacheKey.fieldId] = {}; + map = _listenerByFieldId[cacheKey.fieldId]; + map![cacheKey.objectId] = [callback]; + } else { + var objects = map[cacheKey.objectId]; + if (objects == null) { + map[cacheKey.objectId] = [callback]; + } else { + objects.add(callback); + } } - - map![cacheKey.objectId] = callback; } - void removeListener(GridCellCacheKey cacheKey) { - _cellListenerByFieldId[cacheKey.fieldId]?.remove(cacheKey.objectId); + void removeListener(GridCellCacheKey cacheKey, VoidCallback fn) { + var callbacks = _listenerByFieldId[cacheKey.fieldId]?[cacheKey.objectId]; + final index = callbacks?.indexWhere((callback) => callback == fn); + if (index != null && index != -1) { + callbacks?.removeAt(index); + } } void insert(T item) { - var map = _cellCacheByFieldId[item.key.fieldId]; + var map = _cellDataByFieldId[item.key.fieldId]; if (map == null) { - _cellCacheByFieldId[item.key.fieldId] = {}; - map = _cellCacheByFieldId[item.key.fieldId]; + _cellDataByFieldId[item.key.fieldId] = {}; + map = _cellDataByFieldId[item.key.fieldId]; } map![item.key.objectId] = item.object; } T? get(GridCellCacheKey key) { - final map = _cellCacheByFieldId[key.fieldId]; + final map = _cellDataByFieldId[key.fieldId]; if (map == null) { return null; } else { @@ -226,7 +271,10 @@ class GridCellCache { if (object is T) { return object; } else { - Log.error("Cache data type does not match the cache data type"); + if (object != null) { + Log.error("Cache data type does not match the cache data type"); + } + return null; } } 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 f6e7fa1fe6..4703502cdd 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 @@ -8,6 +8,7 @@ part 'checkbox_cell_bloc.freezed.dart'; class CheckboxCellBloc extends Bloc { final GridDefaultCellContext cellContext; + void Function()? _onCellChangedFn; CheckboxCellBloc({ required CellService service, @@ -32,12 +33,17 @@ class CheckboxCellBloc extends Bloc { @override Future close() async { + if (_onCellChangedFn != null) { + cellContext.removeListener(_onCellChangedFn!); + _onCellChangedFn = null; + } + cellContext.dispose(); return super.close(); } void _startListening() { - cellContext.startListening(onCellChanged: ((cell) { + _onCellChangedFn = cellContext.startListening(onCellChanged: ((cell) { if (!isClosed) { add(CheckboxCellEvent.didReceiveCellUpdate(cell)); } 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 3341c560d4..f21fe38f2d 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 @@ -8,6 +8,7 @@ part 'date_cell_bloc.freezed.dart'; class DateCellBloc extends Bloc { final GridDefaultCellContext cellContext; + void Function()? _onCellChangedFn; DateCellBloc({required this.cellContext}) : super(DateCellState.initial(cellContext)) { on( @@ -34,12 +35,16 @@ class DateCellBloc extends Bloc { @override Future close() async { + if (_onCellChangedFn != null) { + cellContext.removeListener(_onCellChangedFn!); + _onCellChangedFn = null; + } cellContext.dispose(); return super.close(); } void _startListening() { - cellContext.startListening( + _onCellChangedFn = cellContext.startListening( onCellChanged: ((cell) { if (!isClosed) { add(DateCellEvent.didReceiveCellUpdate(cell)); 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 19ce769cf4..ce801f0385 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,6 +8,7 @@ part 'number_cell_bloc.freezed.dart'; class NumberCellBloc extends Bloc { final GridDefaultCellContext cellContext; + void Function()? _onCellChangedFn; NumberCellBloc({ required this.cellContext, @@ -31,17 +32,20 @@ class NumberCellBloc extends Bloc { Future _updateCellValue(_UpdateCell value, Emitter emit) async { cellContext.saveCellData(value.text); - cellContext.reloadCellData(); } @override Future close() async { + if (_onCellChangedFn != null) { + cellContext.removeListener(_onCellChangedFn!); + _onCellChangedFn = null; + } cellContext.dispose(); return super.close(); } void _startListening() { - cellContext.startListening( + _onCellChangedFn = cellContext.startListening( onCellChanged: ((cell) { if (!isClosed) { add(NumberCellEvent.didReceiveCellUpdate(cell)); 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 f6eac64e85..8a10a211d5 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 @@ -9,7 +9,7 @@ import 'package:app_flowy/workspace/application/grid/field/type_option/type_opti import 'cell_service.dart'; -class SelectOptionCellDataLoader implements GridCellDataLoader { +class SelectOptionCellDataLoader extends GridCellDataLoader { final SelectOptionService service; final GridCell gridCell; SelectOptionCellDataLoader({ @@ -27,9 +27,6 @@ class SelectOptionCellDataLoader implements GridCellDataLoader true; } class SelectOptionService { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index 05e27f1f83..2d770aaba5 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -8,6 +8,7 @@ part 'selection_cell_bloc.freezed.dart'; class SelectionCellBloc extends Bloc { final GridSelectOptionCellContext cellContext; + void Function()? _onCellChangedFn; SelectionCellBloc({ required this.cellContext, @@ -31,12 +32,16 @@ class SelectionCellBloc extends Bloc { @override Future close() async { + if (_onCellChangedFn != null) { + cellContext.removeListener(_onCellChangedFn!); + _onCellChangedFn = null; + } cellContext.dispose(); return super.close(); } void _startListening() { - cellContext.startListening( + _onCellChangedFn = cellContext.startListening( onCellChanged: ((selectOptionContext) { if (!isClosed) { add(SelectionCellEvent.didReceiveOptions( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index 071ae4d5e8..0b62945265 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -11,6 +11,7 @@ part 'selection_editor_bloc.freezed.dart'; class SelectOptionEditorBloc extends Bloc { final SelectOptionService _selectOptionService; final GridSelectOptionCellContext cellContext; + void Function()? _onCellChangedFn; SelectOptionEditorBloc({ required this.cellContext, @@ -47,6 +48,10 @@ class SelectOptionEditorBloc extends Bloc close() async { + if (_onCellChangedFn != null) { + cellContext.removeListener(_onCellChangedFn!); + _onCellChangedFn = null; + } cellContext.dispose(); return super.close(); } @@ -82,7 +87,7 @@ class SelectOptionEditorBloc extends Bloc { final GridDefaultCellContext cellContext; + void Function()? _onCellChangedFn; TextCellBloc({ required this.cellContext, }) : super(TextCellState.initial(cellContext)) { @@ -36,12 +37,16 @@ class TextCellBloc extends Bloc { @override Future close() async { + if (_onCellChangedFn != null) { + cellContext.removeListener(_onCellChangedFn!); + _onCellChangedFn = null; + } cellContext.dispose(); return super.close(); } void _startListening() { - cellContext.startListening( + _onCellChangedFn = cellContext.startListening( onCellChanged: ((cell) { if (!isClosed) { add(TextCellEvent.didReceiveCellUpdate(cell)); 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 97495820ff..df72ba3ae1 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 @@ -37,6 +37,11 @@ GridCellContext makeCellContext(GridCell gridCell, GridCellCache cellCache) { case FieldType.Checkbox: case FieldType.DateTime: case FieldType.Number: + return GridDefaultCellContext( + gridCell: gridCell, + cellCache: cellCache, + cellDataLoader: DefaultCellDataLoader(gridCell: gridCell, reloadOnCellChanged: true), + ); case FieldType.RichText: return GridDefaultCellContext( gridCell: gridCell, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index adf088f5e4..ff29d745c7 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -3,6 +3,7 @@ import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_sdk/log.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -42,6 +43,7 @@ class _SingleSelectCellState extends State { @override void initState() { + Log.info("init widget $hashCode"); _cellBloc = getIt(param1: widget.cellContext)..add(const SelectionCellEvent.initial()); super.initState(); } @@ -49,7 +51,7 @@ class _SingleSelectCellState extends State { @override Widget build(BuildContext context) { final theme = context.watch(); - + Log.info("build widget $hashCode"); return BlocProvider.value( value: _cellBloc, child: BlocBuilder( @@ -66,7 +68,7 @@ class _SingleSelectCellState extends State { widget.onFocus.value = true; SelectOptionCellEditor.show( context, - widget.cellContext, + widget.cellContext.clone(), () => widget.onFocus.value = false, ); }, @@ -78,8 +80,21 @@ class _SingleSelectCellState extends State { ); } + @override + void didUpdateWidget(covariant SingleSelectCell oldWidget) { + if (oldWidget.cellContext != widget.cellContext) { + // setState(() { + + // }); + // _cellBloc = getIt(param1: widget.cellContext)..add(const SelectionCellEvent.initial()); + Log.info("did update widget $hashCode"); + } + super.didUpdateWidget(oldWidget); + } + @override Future dispose() async { + Log.info("dispose widget $hashCode"); _cellBloc.close(); super.dispose(); } From d390ef9a3a23ccef424ce63f211cb5fb546c9625 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 25 Apr 2022 22:03:10 +0800 Subject: [PATCH 12/12] chore: fix warnings --- .../application/grid/cell/cell_service.dart | 7 +++- .../workspace/application/grid/grid_bloc.dart | 3 +- .../application/grid/grid_service.dart | 40 ++++++++++++++++--- .../cell/selection_cell/selection_cell.dart | 13 +++--- .../app_flowy/packages/flowy_sdk/lib/log.dart | 2 +- .../src/services/block_meta_manager.rs | 10 ++--- .../flowy-grid/src/services/grid_editor.rs | 5 --- .../flowy-grid/src/services/row/row_loader.rs | 2 +- 8 files changed, 53 insertions(+), 29 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index d2188776cd..1aa090d443 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -17,6 +17,7 @@ part 'cell_service.freezed.dart'; typedef GridDefaultCellContext = GridCellContext; typedef GridSelectOptionCellContext = GridCellContext; +// ignore: must_be_immutable class GridCellContext extends Equatable { final GridCell gridCell; final GridCellCache cellCache; @@ -76,7 +77,6 @@ class GridCellContext extends Equatable { if (cellDataLoader.reloadOnFieldChanged) { _onFieldChangedFn = () { - Log.info("reloadCellData "); _loadData(); }; cellCache.addListener(cacheKey, _onFieldChangedFn!); @@ -200,6 +200,7 @@ class GridCellCacheKey { abstract class GridCellFieldDelegate { void onFieldChanged(void Function(String) callback); + void dispose(); } class GridCellCache { @@ -279,6 +280,10 @@ class GridCellCache { } } } + + Future dispose() async { + fieldDelegate.dispose(); + } } class CellService { 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 30ae08f6fd..4915d77087 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -55,8 +55,9 @@ class GridBloc extends Bloc { @override Future close() async { await _gridService.closeGrid(); - await fieldCache.dispose(); + await cellCache.dispose(); await rowCache.dispose(); + await fieldCache.dispose(); return super.close(); } 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 7911b46eef..d217d2c6b7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -54,10 +54,14 @@ class FieldsNotifier extends ChangeNotifier { List get fields => _fields; } +typedef ChangesetListener = void Function(GridFieldChangeset); + class GridFieldCache { final String gridId; late final GridFieldsListener _fieldListener; final FieldsNotifier _fieldNotifier = FieldsNotifier(); + final List _changesetListener = []; + GridFieldCache({required this.gridId}) { _fieldListener = GridFieldsListener(gridId: gridId); _fieldListener.start(onFieldsChanged: (result) { @@ -66,6 +70,9 @@ class GridFieldCache { _deleteFields(changeset.deletedFields); _insertFields(changeset.insertedFields); _updateFields(changeset.updatedFields); + for (final listener in _changesetListener) { + listener(changeset); + } }, (err) => Log.error(err), ); @@ -77,8 +84,6 @@ class GridFieldCache { _fieldNotifier.dispose(); } - void applyChangeset(GridFieldChangeset changeset) {} - UnmodifiableListView get unmodifiableFields => UnmodifiableListView(_fieldNotifier.fields); List get clonedFields => [..._fieldNotifier.fields]; @@ -111,6 +116,17 @@ class GridFieldCache { _fieldNotifier.removeListener(f); } + void addChangesetListener(ChangesetListener listener) { + _changesetListener.add(listener); + } + + void removeChangesetListener(ChangesetListener listener) { + final index = _changesetListener.indexWhere((element) => element == listener); + if (index != -1) { + _changesetListener.removeAt(index); + } + } + void _deleteFields(List deletedFields) { if (deletedFields.isEmpty) { return; @@ -172,14 +188,26 @@ class GridRowCacheDelegateImpl extends GridRowFieldDelegate { class GridCellCacheDelegateImpl extends GridCellFieldDelegate { final GridFieldCache _cache; + ChangesetListener? _changesetFn; GridCellCacheDelegateImpl(GridFieldCache cache) : _cache = cache; @override void onFieldChanged(void Function(String) callback) { - _cache.addListener(onChanged: (fields) { - for (final field in fields) { - callback(field.id); + changesetFn(GridFieldChangeset changeset) { + for (final updatedField in changeset.updatedFields) { + callback(updatedField.id); } - }); + } + + _cache.addChangesetListener(changesetFn); + _changesetFn = changesetFn; + } + + @override + void dispose() { + if (_changesetFn != null) { + _cache.removeChangesetListener(_changesetFn!); + _changesetFn = null; + } } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index ff29d745c7..939594f19c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -3,6 +3,7 @@ import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; +// ignore: unused_import import 'package:flowy_sdk/log.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -43,7 +44,7 @@ class _SingleSelectCellState extends State { @override void initState() { - Log.info("init widget $hashCode"); + // Log.trace("init widget $hashCode"); _cellBloc = getIt(param1: widget.cellContext)..add(const SelectionCellEvent.initial()); super.initState(); } @@ -51,7 +52,7 @@ class _SingleSelectCellState extends State { @override Widget build(BuildContext context) { final theme = context.watch(); - Log.info("build widget $hashCode"); + // Log.trace("build widget $hashCode"); return BlocProvider.value( value: _cellBloc, child: BlocBuilder( @@ -83,18 +84,14 @@ class _SingleSelectCellState extends State { @override void didUpdateWidget(covariant SingleSelectCell oldWidget) { if (oldWidget.cellContext != widget.cellContext) { - // setState(() { - - // }); - // _cellBloc = getIt(param1: widget.cellContext)..add(const SelectionCellEvent.initial()); - Log.info("did update widget $hashCode"); + // Log.trace("did update widget $hashCode"); } super.didUpdateWidget(oldWidget); } @override Future dispose() async { - Log.info("dispose widget $hashCode"); + // Log.trace("dispose widget $hashCode"); _cellBloc.close(); super.dispose(); } diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/log.dart b/frontend/app_flowy/packages/flowy_sdk/lib/log.dart index a34faaff0e..ad61b70c4f 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/log.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/log.dart @@ -31,7 +31,7 @@ class Log { } static void trace(dynamic msg) { - Log.shared._logger.d(msg); + Log.shared._logger.v(msg); } static void error(dynamic msg) { diff --git a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs index 7853d99c18..229afe75a2 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_meta_manager.rs @@ -3,17 +3,15 @@ use crate::manager::GridUser; use crate::services::block_meta_editor::ClientGridBlockMetaEditor; use crate::services::persistence::block_index::BlockIndexPersistence; use crate::services::row::{group_row_orders, GridBlockSnapshot}; -use std::borrow::Cow; - use dashmap::DashMap; -use flowy_error::{FlowyError, FlowyResult}; +use flowy_error::FlowyResult; use flowy_grid_data_model::entities::{ - Cell, CellChangeset, CellMeta, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, IndexRowOrder, Row, - RowMeta, RowMetaChangeset, RowOrder, UpdatedRowOrder, + CellChangeset, CellMeta, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, IndexRowOrder, Row, RowMeta, + RowMetaChangeset, RowOrder, UpdatedRowOrder, }; use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; use flowy_revision::{RevisionManager, RevisionPersistence}; -use lib_infra::future::FutureResult; +use std::borrow::Cow; use std::collections::HashMap; use std::sync::Arc; 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 05437f46cd..d8d909cabe 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -430,11 +430,6 @@ impl ClientGridEditor { self.grid_pad.read().await.delta_bytes() } - async fn row_builder(&self, row_meta: Arc) -> FlowyResult> { - let field_metas = self.get_field_metas::(None).await?; - Ok(make_rows_from_row_metas(&field_metas, &[row_meta]).pop()) - } - async fn modify(&self, f: F) -> FlowyResult<()> where F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult>, 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 35357a0c83..93b40f4d51 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 @@ -48,7 +48,7 @@ pub(crate) fn make_row_orders_from_row_metas(row_metas: &[Arc]) -> Vec< } pub(crate) fn make_row_from_row_meta(fields: &[FieldMeta], row_meta: Arc) -> Option { - make_rows_from_row_metas(fields, &vec![row_meta]).pop() + make_rows_from_row_metas(fields, &[row_meta]).pop() } pub(crate) fn make_rows_from_row_metas(fields: &[FieldMeta], row_metas: &[Arc]) -> Vec {