From 943b4507ac3c092baa60b1c7216616e366472930 Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 12 Apr 2022 15:22:33 +0800 Subject: [PATCH 01/26] chore: config field separate line --- .../grid/field/field_cell_bloc.dart | 4 ++ .../application/grid/field/field_service.dart | 20 ++++----- .../home/menu/app/header/add_button.dart | 4 +- .../home/menu/app/section/item.dart | 2 +- .../plugins/grid/src/grid_page.dart | 4 +- .../cell/selection_cell/selection_editor.dart | 2 +- .../grid/src/widgets/header/field_cell.dart | 41 +++++++++++++++++-- .../grid/src/widgets/header/grid_header.dart | 17 ++++---- .../presentation/widgets/pop_up_action.dart | 2 +- .../lib/style_widget/button.dart | 2 +- .../lib/style_widget/hover.dart | 25 ++++++----- 11 files changed, 79 insertions(+), 44 deletions(-) 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 c7964573d3..1afbded351 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 @@ -10,10 +10,12 @@ part 'field_cell_bloc.freezed.dart'; class FieldCellBloc extends Bloc { final FieldListener _fieldListener; + final FieldService _fieldService; FieldCellBloc({ required GridFieldCellContext cellContext, }) : _fieldListener = FieldListener(fieldId: cellContext.field.id), + _fieldService = FieldService(gridId: cellContext.gridId), super(FieldCellState.initial(cellContext)) { on( (event, emit) async { @@ -24,6 +26,7 @@ class FieldCellBloc extends Bloc { didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { emit(state.copyWith(field: value.field)); }, + updateWidth: (_UpdateWidth value) {}, ); }, ); @@ -50,6 +53,7 @@ class FieldCellBloc extends Bloc { class FieldCellEvent with _$FieldCellEvent { const factory FieldCellEvent.initial() = _InitialCell; const factory FieldCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; + const factory FieldCellEvent.updateWidth(double offset) = _UpdateWidth; } @freezed diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index c058bcd36c..743a441c7d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -1,9 +1,10 @@ import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; import 'package:flowy_sdk/dispatch/dispatch.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/field_entities.pb.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +part 'field_service.freezed.dart'; class FieldService { final String gridId; @@ -98,17 +99,12 @@ class FieldService { } } -class GridFieldCellContext extends Equatable { - final String gridId; - final Field field; - - const GridFieldCellContext({ - required this.gridId, - required this.field, - }); - - @override - List get props => [field.id]; +@freezed +class GridFieldCellContext with _$GridFieldCellContext { + const factory GridFieldCellContext({ + required String gridId, + required Field field, + }) = _GridFieldCellContext; } abstract class EditFieldContextLoader { diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart index 6df78a67cc..214dc7a198 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/header/add_button.dart @@ -78,10 +78,10 @@ class CreateItem extends StatelessWidget { @override Widget build(BuildContext context) { final theme = context.watch(); - final config = HoverDisplayConfig(hoverColor: theme.hover); + final config = HoverStyle(hoverColor: theme.hover); return FlowyHover( - config: config, + style: config, builder: (context, onHover) { return GestureDetector( onTap: () => onSelected(pluginBuilder), diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart index 15a27268c5..290d2bd328 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/item.dart @@ -43,7 +43,7 @@ class ViewSectionItem extends StatelessWidget { return InkWell( onTap: () => onSelected(context.read().state.view), child: FlowyHover( - config: HoverDisplayConfig(hoverColor: theme.bg3), + style: HoverStyle(hoverColor: theme.bg3), builder: (_, onHover) => _render(context, onHover, state, theme.iconColor), setSelected: () => state.isEditing || isSelected, ), 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 6f6878c515..50d1913057 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 @@ -100,7 +100,7 @@ class _FlowyGridState extends State { controller: _scrollController.verticalController, slivers: [ _renderToolbar(state.gridId), - _renderGridHeader(state.gridId), + _renderHeader(state.gridId), _renderRows(gridId: state.gridId, context: context), const GridFooter(), ], @@ -126,7 +126,7 @@ class _FlowyGridState extends State { ); } - Widget _renderGridHeader(String gridId) { + Widget _renderHeader(String gridId) { return BlocSelector>( selector: (state) => state.fields, builder: (context, fields) { 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 feefb552cd..4ebd4407b0 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 @@ -199,7 +199,7 @@ class _SelectOptionCell extends StatelessWidget { context.read().add(SelectOptionEditorEvent.selectOption(option.id)); }, child: FlowyHover( - config: HoverDisplayConfig(hoverColor: theme.hover), + style: HoverStyle(hoverColor: theme.hover), builder: (_, onHover) { List children = [ SelectOptionTag(option: option, isSelected: isSelected), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index 79e706085f..5d658c693c 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -4,7 +4,9 @@ import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.d import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/hover.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'; import 'field_type_extension.dart'; @@ -25,21 +27,52 @@ class GridFieldCell extends StatelessWidget { child: BlocBuilder( builder: (context, state) { final button = FlowyButton( - hoverColor: theme.hover, + hoverColor: theme.shader6, onTap: () => _showActionSheet(context), - rightIcon: svgWidget("editor/details", color: theme.iconColor), + // rightIcon: svgWidget("editor/details", color: theme.iconColor), leftIcon: svgWidget(state.field.fieldType.iconName(), color: theme.iconColor), text: FlowyText.medium(state.field.name, fontSize: 12), padding: GridSize.cellContentInsets, ); + final line = InkWell( + onTap: () {}, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onHorizontalDragCancel: () {}, + onHorizontalDragUpdate: (value) { + Log.info(value.delta); + }, + child: FlowyHover( + style: HoverStyle( + hoverColor: theme.main1, + borderRadius: BorderRadius.zero, + contentMargin: const EdgeInsets.only(left: 5), + ), + builder: (_, onHover) => const SizedBox(width: 2), + ), + ), + ); + final borderSide = BorderSide(color: theme.shader4, width: 0.4); - final decoration = BoxDecoration(border: Border(top: borderSide, right: borderSide, bottom: borderSide)); + final decoration = BoxDecoration( + border: Border( + top: borderSide, + right: borderSide, + bottom: borderSide, + )); return Container( width: state.field.width.toDouble(), decoration: decoration, - child: button, + child: ConstrainedBox( + constraints: const BoxConstraints.expand(), + child: Stack( + alignment: Alignment.centerRight, + fit: StackFit.expand, + children: [button, Positioned(top: 0, bottom: 0, right: 0, child: line)], + ), + ), ); }, ), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 5568f2ef62..b5893fa095 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -72,28 +72,27 @@ class _GridHeaderWidget extends StatelessWidget { @override Widget build(BuildContext context) { - final theme = context.watch(); final cells = fields.map( (field) => GridFieldCell( GridFieldCellContext(gridId: gridId, field: field), ), ); - final row = Row( + return Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - const _HeaderLeading(), + const _CellLeading(), ...cells, - _HeaderTrailing(gridId: gridId), + _CellTrailing(gridId: gridId), ], ); - return Container(height: GridSize.headerHeight, color: theme.surface, child: row); + // return Container(height: GridSize.headerHeight, color: theme.surface, child: row); } } -class _HeaderLeading extends StatelessWidget { - const _HeaderLeading({Key? key}) : super(key: key); +class _CellLeading extends StatelessWidget { + const _CellLeading({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -103,9 +102,9 @@ class _HeaderLeading extends StatelessWidget { } } -class _HeaderTrailing extends StatelessWidget { +class _CellTrailing extends StatelessWidget { final String gridId; - const _HeaderTrailing({required this.gridId, Key? key}) : super(key: key); + const _CellTrailing({required this.gridId, Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart b/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart index 5c782d3ece..cc822a6ef9 100644 --- a/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart +++ b/frontend/app_flowy/lib/workspace/presentation/widgets/pop_up_action.dart @@ -85,7 +85,7 @@ class ActionCell extends StatelessWidget { final theme = context.watch(); return FlowyHover( - config: HoverDisplayConfig(hoverColor: theme.hover), + style: HoverStyle(hoverColor: theme.hover), builder: (context, onHover) { return GestureDetector( behavior: HitTestBehavior.opaque, diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart index 69cddbf2fb..8249bc115b 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart @@ -28,7 +28,7 @@ class FlowyButton extends StatelessWidget { return InkWell( onTap: onTap, child: FlowyHover( - config: HoverDisplayConfig(borderRadius: Corners.s6Border, hoverColor: hoverColor), + style: HoverStyle(borderRadius: Corners.s6Border, hoverColor: hoverColor), setSelected: () => isSelected, builder: (context, onHover) => _render(), ), diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/hover.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/hover.dart index 48a702c2e4..f8caf35b84 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/hover.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/hover.dart @@ -5,14 +5,14 @@ import 'package:flowy_infra/time/duration.dart'; typedef HoverBuilder = Widget Function(BuildContext context, bool onHover); class FlowyHover extends StatefulWidget { - final HoverDisplayConfig config; + final HoverStyle style; final HoverBuilder builder; final bool Function()? setSelected; const FlowyHover({ Key? key, required this.builder, - required this.config, + required this.style, this.setSelected, }) : super(key: key); @@ -41,7 +41,7 @@ class _FlowyHoverState extends State { if (showHover) { return FlowyHoverContainer( - config: widget.config, + style: widget.style, child: widget.builder(context, _onHover), ); } else { @@ -50,41 +50,44 @@ class _FlowyHoverState extends State { } } -class HoverDisplayConfig { +class HoverStyle { final Color borderColor; final double borderWidth; final Color hoverColor; final BorderRadius borderRadius; + final EdgeInsets contentMargin; - const HoverDisplayConfig( + const HoverStyle( {this.borderColor = Colors.transparent, this.borderWidth = 0, this.borderRadius = const BorderRadius.all(Radius.circular(6)), + this.contentMargin = EdgeInsets.zero, required this.hoverColor}); } class FlowyHoverContainer extends StatelessWidget { - final HoverDisplayConfig config; + final HoverStyle style; final Widget child; const FlowyHoverContainer({ Key? key, required this.child, - required this.config, + required this.style, }) : super(key: key); @override Widget build(BuildContext context) { final hoverBorder = Border.all( - color: config.borderColor, - width: config.borderWidth, + color: style.borderColor, + width: style.borderWidth, ); return Container( + margin: style.contentMargin, decoration: BoxDecoration( border: hoverBorder, - color: config.hoverColor, - borderRadius: config.borderRadius, + color: style.hoverColor, + borderRadius: style.borderRadius, ), child: child, ); From a7074105480c7da3c1d13197714ced0af97860ec Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 12 Apr 2022 21:31:38 +0800 Subject: [PATCH 02/26] chore: format number cell --- .../app_flowy/lib/startup/deps_resolver.dart | 7 -- .../grid/cell_bloc/number_cell_bloc.dart | 49 ++++++++----- .../grid/field/field_cell_bloc.dart | 8 ++- .../grid/field/grid_header_bloc.dart | 72 ------------------- .../workspace/application/grid/prelude.dart | 1 - .../plugins/grid/src/grid_page.dart | 46 ++++++------ .../grid/src/widgets/cell/number_cell.dart | 10 ++- .../grid/src/widgets/footer/grid_footer.dart | 20 +++--- .../grid/src/widgets/header/field_cell.dart | 2 +- .../grid/src/widgets/header/grid_header.dart | 19 ++--- .../scrolling/styled_scrollview.dart | 34 +++++---- 11 files changed, 101 insertions(+), 167 deletions(-) delete mode 100644 frontend/app_flowy/lib/workspace/application/grid/field/grid_header_bloc.dart diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index abf6fffd21..5c835ce217 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -156,13 +156,6 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam>( - (gridId, fields) => GridHeaderBloc( - data: GridHeaderData(gridId: gridId, fields: fields), - service: FieldService(gridId: gridId), - ), - ); - getIt.registerFactoryParam( (data, _) => FieldActionSheetBloc( field: data.field, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart index 9fe0af2d5d..e61e8f96a6 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart @@ -1,4 +1,5 @@ import 'package:app_flowy/workspace/application/grid/cell_bloc/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'; @@ -11,12 +12,14 @@ part 'number_cell_bloc.freezed.dart'; class NumberCellBloc extends Bloc { final CellService _service; - final CellListener _listener; + final CellListener _cellListener; + final FieldListener _fieldListener; NumberCellBloc({ required CellData cellData, }) : _service = CellService(), - _listener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), + _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), + _fieldListener = FieldListener(fieldId: cellData.field.id), super(NumberCellState.initial(cellData)) { on( (event, emit) async { @@ -27,36 +30,36 @@ class NumberCellBloc extends Bloc { didReceiveCellUpdate: (_DidReceiveCellUpdate value) { emit(state.copyWith(content: value.cell.content)); }, - updateCell: (_UpdateCell value) { - _updateCellValue(value, emit); + updateCell: (_UpdateCell value) async { + await _updateCellValue(value, emit); }, ); }, ); } - void _updateCellValue(_UpdateCell value, Emitter emit) { - final number = num.tryParse(value.text); - if (number == null) { - emit(state.copyWith(content: "")); - } else { - _service.updateCell( - gridId: state.cellData.gridId, - fieldId: state.cellData.field.id, - rowId: state.cellData.rowId, - data: value.text, - ); - } + 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), + ); } @override Future close() async { - await _listener.stop(); + await _cellListener.stop(); + await _fieldListener.stop(); return super.close(); } void _startListening() { - _listener.updateCellNotifier.addPublishListener((result) { + _cellListener.updateCellNotifier.addPublishListener((result) { result.fold( (notificationData) async { await _getCellData(); @@ -64,7 +67,15 @@ class NumberCellBloc extends Bloc { (err) => Log.error(err), ); }); - _listener.start(); + _cellListener.start(); + + _fieldListener.updateFieldNotifier.addPublishListener((result) { + result.fold( + (field) => _getCellData(), + (err) => Log.error(err), + ); + }); + _fieldListener.start(); } Future _getCellData() async { 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 1afbded351..376b98f19a 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 @@ -26,7 +26,13 @@ class FieldCellBloc extends Bloc { didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { emit(state.copyWith(field: value.field)); }, - updateWidth: (_UpdateWidth value) {}, + updateWidth: (_UpdateWidth value) { + final defaultWidth = state.field.width.toDouble(); + final width = defaultWidth + value.offset; + if (width > defaultWidth && width < 300) { + _fieldService.updateField(fieldId: state.field.id, width: width); + } + }, ); }, ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_bloc.dart deleted file mode 100644 index 4145e23804..0000000000 --- a/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_bloc.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:app_flowy/workspace/application/grid/data.dart'; -import 'package:app_flowy/workspace/application/grid/field/grid_listenr.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'; -import 'dart:async'; -import 'field_service.dart'; - -part 'grid_header_bloc.freezed.dart'; - -class GridHeaderBloc extends Bloc { - final FieldService service; - final GridFieldsListener _fieldListener; - - GridHeaderBloc({ - required GridHeaderData data, - required this.service, - }) : _fieldListener = GridFieldsListener(gridId: data.gridId), - super(GridHeaderState.initial(data.fields)) { - on( - (event, emit) async { - await event.map( - initial: (_InitialHeader value) async { - _startListening(); - }, - createField: (_CreateField value) {}, - insertField: (_InsertField value) {}, - didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - value.fields.retainWhere((field) => field.visibility); - emit(state.copyWith(fields: value.fields)); - }, - ); - }, - ); - } - - Future _startListening() async { - _fieldListener.updateFieldsNotifier.addPublishListener((result) { - result.fold( - (fields) => add(GridHeaderEvent.didReceiveFieldUpdate(fields)), - (err) => Log.error(err), - ); - }); - - _fieldListener.start(); - } - - @override - Future close() async { - await _fieldListener.stop(); - return super.close(); - } -} - -@freezed -class GridHeaderEvent with _$GridHeaderEvent { - const factory GridHeaderEvent.initial() = _InitialHeader; - const factory GridHeaderEvent.createField() = _CreateField; - const factory GridHeaderEvent.insertField({required bool onLeft}) = _InsertField; - const factory GridHeaderEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; -} - -@freezed -class GridHeaderState with _$GridHeaderState { - const factory GridHeaderState({required List fields}) = _GridHeaderState; - - factory GridHeaderState.initial(List fields) { - fields.retainWhere((field) => field.visibility); - return GridHeaderState(fields: fields); - } -} diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index a795e23fb2..3fd24f8785 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -6,7 +6,6 @@ export 'data.dart'; // Field export 'field/field_service.dart'; -export 'field/grid_header_bloc.dart'; export 'field/field_action_sheet_bloc.dart'; export 'field/field_editor_bloc.dart'; export 'field/field_switch_bloc.dart'; 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 50d1913057..40b282e717 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 @@ -85,7 +85,7 @@ class _FlowyGridState extends State { @override Widget build(BuildContext context) { return BlocBuilder( - buildWhen: (previous, current) => previous.fields != current.fields, + buildWhen: (previous, current) => previous.fields.length != current.fields.length, builder: (context, state) { if (state.fields.isEmpty) { return const Center(child: CircularProgressIndicator.adaptive()); @@ -99,10 +99,10 @@ class _FlowyGridState extends State { physics: StyledScrollPhysics(), controller: _scrollController.verticalController, slivers: [ - _renderToolbar(state.gridId), - _renderHeader(state.gridId), - _renderRows(gridId: state.gridId, context: context), - const GridFooter(), + const _GridToolbarAdaptor(), + GridHeader(gridId: state.gridId, fields: List.from(state.fields)), + _GridRows(), + const SliverToBoxAdapter(child: GridFooter()), ], ), ), @@ -125,33 +125,35 @@ class _FlowyGridState extends State { ), ); } +} - Widget _renderHeader(String gridId) { - return BlocSelector>( - selector: (state) => state.fields, - builder: (context, fields) { - return GridHeader(gridId: gridId, fields: List.from(fields)); - }, - ); - } +class _GridToolbarAdaptor extends StatelessWidget { + const _GridToolbarAdaptor({Key? key}) : super(key: key); - Widget _renderToolbar(String gridId) { - return BlocSelector>( - selector: (state) => state.fields, - builder: (context, fields) { - final toolbarContext = GridToolbarContext( - gridId: gridId, - fields: fields, + @override + Widget build(BuildContext context) { + return BlocSelector( + selector: (state) { + return GridToolbarContext( + gridId: state.gridId, + fields: state.fields, ); - + }, + builder: (context, toolbarContext) { return SliverToBoxAdapter( child: GridToolbar(toolbarContext: toolbarContext), ); }, ); } +} - Widget _renderRows({required String gridId, required BuildContext context}) { +class _GridRows extends StatelessWidget { + final _key = GlobalKey(); + _GridRows({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { return BlocConsumer( listener: (context, state) { state.listState.map( 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 fc31340c9f..cd4db24c7a 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 @@ -26,7 +26,7 @@ class _NumberCellState extends State { @override void initState() { - _cellBloc = getIt(param1: widget.cellData); + _cellBloc = getIt(param1: widget.cellData)..add(const NumberCellEvent.initial()); _controller = TextEditingController(text: _cellBloc.state.content); _focusNode = CellFocusNode(); super.initState(); @@ -48,7 +48,6 @@ class _NumberCellState extends State { return TextField( controller: _controller, focusNode: _focusNode, - onChanged: (value) => focusChanged(), onEditingComplete: () => _focusNode.unfocus(), maxLines: 1, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), @@ -76,7 +75,12 @@ class _NumberCellState extends State { _delayOperation?.cancel(); _delayOperation = Timer(const Duration(milliseconds: 300), () { if (_cellBloc.isClosed == false && _controller.text != _cellBloc.state.content) { - _cellBloc.add(NumberCellEvent.updateCell(_controller.text)); + final number = num.tryParse(_controller.text); + if (number != null) { + _cellBloc.add(NumberCellEvent.updateCell(_controller.text)); + } else { + _controller.text = ""; + } } }); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart index 8d9719ae75..35d9ee1378 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart @@ -12,17 +12,15 @@ class GridFooter extends StatelessWidget { @override Widget build(BuildContext context) { - return SliverToBoxAdapter( - child: SizedBox( - height: GridSize.footerHeight, - child: Padding( - padding: GridSize.headerContentInsets, - child: Row( - children: [ - SizedBox(width: GridSize.leadingHeaderPadding), - const SizedBox(width: 120, child: _AddRowButton()), - ], - ), + return SizedBox( + height: GridSize.footerHeight, + child: Padding( + padding: GridSize.headerContentInsets, + child: Row( + children: [ + SizedBox(width: GridSize.leadingHeaderPadding), + const SizedBox(width: 120, child: _AddRowButton()), + ], ), ), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index 5d658c693c..83fcade362 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -41,7 +41,7 @@ class GridFieldCell extends StatelessWidget { behavior: HitTestBehavior.opaque, onHorizontalDragCancel: () {}, onHorizontalDragUpdate: (value) { - Log.info(value.delta); + context.read().add(FieldCellEvent.updateWidth(value.delta.dx)); }, child: FlowyHover( style: HoverStyle( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index b5893fa095..44730f703d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -19,21 +19,10 @@ class GridHeader extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocProvider( - create: (context) { - final bloc = getIt(param1: gridId, param2: fields); - bloc.add(const GridHeaderEvent.initial()); - return bloc; - }, - child: BlocBuilder( - builder: (context, state) { - return SliverPersistentHeader( - delegate: _GridHeaderDelegate(gridId: gridId, fields: List.from(state.fields)), - floating: true, - pinned: true, - ); - }, - ), + return SliverPersistentHeader( + delegate: _GridHeaderDelegate(gridId: gridId, fields: List.from(fields)), + floating: true, + pinned: true, ); } } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart index ed960a1c12..da316685dd 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart @@ -74,21 +74,21 @@ class _StyledSingleChildScrollViewState extends State slivers; + final double barSize; const StyledCustomScrollView({ Key? key, - this.contentSize, this.axis = Axis.vertical, this.trackColor, this.handleColor, - this.controller, + this.verticalController, this.slivers = const [], + this.barSize = 12, }) : super(key: key); @override @@ -96,17 +96,17 @@ class StyledCustomScrollView extends StatefulWidget { } class _StyledCustomScrollViewState extends State { - late ScrollController scrollController; + late ScrollController controller; @override void initState() { - scrollController = widget.controller ?? ScrollController(); + controller = widget.verticalController ?? ScrollController(); + super.initState(); } @override void dispose() { - scrollController.dispose(); super.dispose(); } @@ -120,19 +120,23 @@ class _StyledCustomScrollViewState extends State { @override Widget build(BuildContext context) { - return ScrollbarListStack( - contentSize: widget.contentSize, - axis: widget.axis, - controller: scrollController, - barSize: 12, - trackColor: widget.trackColor, - handleColor: widget.handleColor, + var child = ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(scrollbars: false), child: CustomScrollView( scrollDirection: widget.axis, physics: StyledScrollPhysics(), - controller: scrollController, + controller: controller, slivers: widget.slivers, ), ); + + return ScrollbarListStack( + axis: widget.axis, + controller: controller, + barSize: widget.barSize, + trackColor: widget.trackColor, + handleColor: widget.handleColor, + child: child, + ); } } From b0e07c952ee49ca08d3add5f14c4c8a3895ee33e Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 13 Apr 2022 10:47:07 +0800 Subject: [PATCH 03/26] chore: fixed grid toolbar --- .../grid/cell_bloc/date_cell_bloc.dart | 11 +- .../application/grid/field/field_service.dart | 9 ++ .../plugins/grid/src/grid_page.dart | 125 +++++++++++------- .../grid/src/widgets/cell/date_cell.dart | 18 ++- .../grid/src/widgets/footer/grid_footer.dart | 24 +--- .../grid/src/widgets/header/grid_header.dart | 67 +++------- 6 files changed, 135 insertions(+), 119 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart index 8d46b7e659..ff8d7d012e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart @@ -2,7 +2,7 @@ import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dar 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; +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'; import 'dart:async'; @@ -35,6 +35,10 @@ class DateCellBloc extends Bloc { content: value.cell.content, )); }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(field: value.field)); + _loadCellData(); + }, ); }, ); @@ -58,7 +62,7 @@ class DateCellBloc extends Bloc { _fieldListener.updateFieldNotifier.addPublishListener((result) { result.fold( - (field) => _loadCellData(), + (field) => add(DateCellEvent.didReceiveFieldUpdate(field)), (err) => Log.error(err), ); }); @@ -97,6 +101,7 @@ class DateCellEvent with _$DateCellEvent { const factory DateCellEvent.initial() = _InitialCell; const factory DateCellEvent.selectDay(DateTime day) = _SelectDay; const factory DateCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; + const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; } @freezed @@ -104,11 +109,13 @@ class DateCellState with _$DateCellState { const factory DateCellState({ required CellData cellData, required String content, + required Field field, DateTime? selectedDay, }) = _DateCellState; factory DateCellState.initial(CellData cellData) => DateCellState( cellData: cellData, + field: cellData.field, content: cellData.cell?.content ?? "", ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index 743a441c7d..e1bed697c8 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -20,6 +20,15 @@ class FieldService { return GridEventSwitchToField(payload).send(); } + Future> getEditFieldContext(String fieldId, FieldType fieldType) { + final payload = GetEditFieldContextPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..fieldType = fieldType; + + return GridEventGetEditFieldContext(payload).send(); + } + Future> updateField({ required String fieldId, String? name, 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 40b282e717..804ffff685 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 @@ -40,7 +40,7 @@ class _GridPageState extends State { return state.loadingState.map( loading: (_) => const Center(child: CircularProgressIndicator.adaptive()), finish: (result) => result.successOrFail.fold( - (_) => const FlowyGrid(), + (_) => FlowyGrid(), (err) => FlowyErrorPage(err.toString()), ), ); @@ -65,64 +65,61 @@ class _GridPageState extends State { } } -class FlowyGrid extends StatefulWidget { - const FlowyGrid({Key? key}) : super(key: key); - - @override - _FlowyGridState createState() => _FlowyGridState(); -} - -class _FlowyGridState extends State { +class FlowyGrid extends StatelessWidget { final _scrollController = GridScrollController(); - final _key = GlobalKey(); - - @override - void dispose() { - _scrollController.dispose(); - super.dispose(); - } + FlowyGrid({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocBuilder( buildWhen: (previous, current) => previous.fields.length != current.fields.length, builder: (context, state) { - if (state.fields.isEmpty) { - return const Center(child: CircularProgressIndicator.adaptive()); - } - - final child = SizedBox( - width: GridLayout.headerWidth(state.fields), - child: ScrollConfiguration( - behavior: const ScrollBehavior().copyWith(scrollbars: false), - child: CustomScrollView( - physics: StyledScrollPhysics(), - controller: _scrollController.verticalController, - slivers: [ - const _GridToolbarAdaptor(), - GridHeader(gridId: state.gridId, fields: List.from(state.fields)), - _GridRows(), - const SliverToBoxAdapter(child: GridFooter()), - ], - ), - ), + final child = _wrapScrollView( + state.fields, + [ + _GridHeader(gridId: state.gridId, fields: List.from(state.fields)), + _GridRows(), + const _GridFooter(), + ], ); - return _wrapScrollbar(child); + return Column(children: [ + const _GridToolbarAdaptor(), + Flexible(child: child), + ]); }, ); } - Widget _wrapScrollbar(Widget child) { + Widget _wrapScrollView( + List fields, + List slivers, + ) { + final verticalScrollView = ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(scrollbars: false), + child: CustomScrollView( + physics: StyledScrollPhysics(), + controller: _scrollController.verticalController, + slivers: slivers, + ), + ); + + final sizedVerticalScrollView = SizedBox( + width: GridLayout.headerWidth(fields), + child: verticalScrollView, + ); + + final horizontalScrollView = StyledSingleChildScrollView( + controller: _scrollController.horizontalController, + axis: Axis.horizontal, + child: sizedVerticalScrollView, + ); + return ScrollbarListStack( axis: Axis.vertical, controller: _scrollController.verticalController, barSize: GridSize.scrollBarSize, - child: StyledSingleChildScrollView( - controller: _scrollController.horizontalController, - axis: Axis.horizontal, - child: child, - ), + child: horizontalScrollView, ); } } @@ -140,14 +137,27 @@ class _GridToolbarAdaptor extends StatelessWidget { ); }, builder: (context, toolbarContext) { - return SliverToBoxAdapter( - child: GridToolbar(toolbarContext: toolbarContext), - ); + return GridToolbar(toolbarContext: toolbarContext); }, ); } } +class _GridHeader extends StatelessWidget { + final String gridId; + final List fields; + const _GridHeader({Key? key, required this.gridId, required this.fields}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverPersistentHeader( + delegate: GridHeaderSliverAdaptor(gridId: gridId, fields: List.from(fields)), + floating: true, + pinned: true, + ); + } +} + class _GridRows extends StatelessWidget { final _key = GlobalKey(); _GridRows({Key? key}) : super(key: key); @@ -191,3 +201,28 @@ class _GridRows extends StatelessWidget { ); } } + +class _GridFooter extends StatelessWidget { + const _GridFooter({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SliverPadding( + padding: const EdgeInsets.only(bottom: 200), + sliver: SliverToBoxAdapter( + child: SizedBox( + height: GridSize.footerHeight, + child: Padding( + padding: GridSize.headerContentInsets, + child: Row( + children: [ + SizedBox(width: GridSize.leadingHeaderPadding), + const SizedBox(width: 120, child: GridAddRowButton()), + ], + ), + ), + ), + ), + ); + } +} 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 c5100df969..b913a09e4e 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 @@ -74,7 +74,13 @@ final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); class _CellCalendar extends StatefulWidget with FlowyOverlayDelegate { final void Function(DateTime) onSelected; final VoidCallback onDismissed; - const _CellCalendar({required this.onSelected, required this.onDismissed, Key? key}) : super(key: key); + final bool includeTime; + const _CellCalendar({ + required this.onSelected, + required this.onDismissed, + required this.includeTime, + Key? key, + }) : super(key: key); @override State<_CellCalendar> createState() => _CellCalendarState(); @@ -86,7 +92,11 @@ class _CellCalendar extends StatefulWidget with FlowyOverlayDelegate { }) async { _CellCalendar.remove(context); - final calendar = _CellCalendar(onSelected: onSelected, onDismissed: onDismissed); + final calendar = _CellCalendar( + onSelected: onSelected, + onDismissed: onDismissed, + includeTime: false, + ); // const size = Size(460, 400); // final window = await getWindowInfo(); // FlowyOverlay.of(context).insertWithRect( @@ -105,11 +115,11 @@ class _CellCalendar extends StatefulWidget with FlowyOverlayDelegate { FlowyOverlay.of(context).insertWithAnchor( widget: OverlayContainer( child: calendar, - constraints: BoxConstraints.loose(const Size(300, 320)), + constraints: BoxConstraints.tight(const Size(320, 320)), ), identifier: _CellCalendar.identifier(), anchorContext: context, - anchorDirection: AnchorDirection.bottomWithCenterAligned, + anchorDirection: AnchorDirection.leftWithCenterAligned, style: FlowyOverlayStyle(blur: false), delegate: calendar, ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart index 35d9ee1378..a99e87f5fa 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart @@ -7,28 +7,8 @@ import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -class GridFooter extends StatelessWidget { - const GridFooter({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return SizedBox( - height: GridSize.footerHeight, - child: Padding( - padding: GridSize.headerContentInsets, - child: Row( - children: [ - SizedBox(width: GridSize.leadingHeaderPadding), - const SizedBox(width: 120, child: _AddRowButton()), - ], - ), - ), - ); - } -} - -class _AddRowButton extends StatelessWidget { - const _AddRowButton({Key? key}) : super(key: key); +class GridAddRowButton extends StatelessWidget { + const GridAddRowButton({Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 44730f703d..c387ecd4e2 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -12,30 +12,32 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'field_editor.dart'; import 'field_cell.dart'; -class GridHeader extends StatelessWidget { - final String gridId; - final List fields; - const GridHeader({Key? key, required this.gridId, required this.fields}) : super(key: key); - - @override - Widget build(BuildContext context) { - return SliverPersistentHeader( - delegate: _GridHeaderDelegate(gridId: gridId, fields: List.from(fields)), - floating: true, - pinned: true, - ); - } -} - -class _GridHeaderDelegate extends SliverPersistentHeaderDelegate { +class GridHeaderSliverAdaptor extends SliverPersistentHeaderDelegate { final String gridId; final List fields; - _GridHeaderDelegate({required this.gridId, required this.fields}); + GridHeaderSliverAdaptor({required this.gridId, required this.fields}); @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - return _GridHeaderWidget(gridId: gridId, fields: fields, key: ObjectKey(fields)); + final cells = fields.map( + (field) => GridFieldCell( + GridFieldCellContext(gridId: gridId, field: field), + ), + ); + + return Container( + color: Colors.white, + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const _CellLeading(), + ...cells, + _CellTrailing(gridId: gridId), + ], + key: ObjectKey(fields), + ), + ); } @override @@ -46,40 +48,13 @@ class _GridHeaderDelegate extends SliverPersistentHeaderDelegate { @override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { - if (oldDelegate is _GridHeaderDelegate) { + if (oldDelegate is GridHeaderSliverAdaptor) { return fields.length != oldDelegate.fields.length; } return true; } } -class _GridHeaderWidget extends StatelessWidget { - final String gridId; - final List fields; - - const _GridHeaderWidget({required this.gridId, required this.fields, Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final cells = fields.map( - (field) => GridFieldCell( - GridFieldCellContext(gridId: gridId, field: field), - ), - ); - - return Row( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const _CellLeading(), - ...cells, - _CellTrailing(gridId: gridId), - ], - ); - - // return Container(height: GridSize.headerHeight, color: theme.surface, child: row); - } -} - class _CellLeading extends StatelessWidget { const _CellLeading({Key? key}) : super(key: key); From 2fa6adeee633942a6f3c0b29db114835feff4d97 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 13 Apr 2022 14:24:54 +0800 Subject: [PATCH 04/26] chore: move field --- .../application/grid/grid_listener.dart | 5 +- .../grid/setting/property_bloc.dart | 4 + .../src/widgets/toolbar/grid_property.dart | 16 +- .../dart_event/flowy-grid/dart_event.dart | 17 + .../flowy-grid-data-model/grid.pb.dart | 129 ++++- .../flowy-grid-data-model/grid.pbenum.dart | 15 + .../flowy-grid-data-model/grid.pbjson.dart | 35 +- .../protobuf/flowy-grid/event_map.pbenum.dart | 2 + .../protobuf/flowy-grid/event_map.pbjson.dart | 3 +- frontend/app_flowy/pubspec.lock | 7 + frontend/app_flowy/pubspec.yaml | 1 + .../rust-lib/flowy-grid/src/event_handler.rs | 11 + frontend/rust-lib/flowy-grid/src/event_map.rs | 9 +- .../src/protobuf/model/event_map.rs | 17 +- .../src/protobuf/proto/event_map.proto | 1 + .../src/services/block_meta_manager.rs | 14 +- .../flowy-grid/src/services/grid_editor.rs | 18 + .../src/entities/grid.rs | 65 ++- .../src/protobuf/model/grid.rs | 449 ++++++++++++++++-- .../src/protobuf/proto/grid.proto | 13 +- 20 files changed, 730 insertions(+), 101 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart index f36a630e1a..862cd95d74 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart @@ -9,8 +9,7 @@ import 'package:app_flowy/core/notification_helper.dart'; class GridListener { final String gridId; - PublishNotifier, FlowyError>> rowsUpdateNotifier = - PublishNotifier(comparable: null); + PublishNotifier, FlowyError>> rowsUpdateNotifier = PublishNotifier(comparable: null); GridNotificationListener? _listener; GridListener({required this.gridId}); @@ -26,7 +25,7 @@ class GridListener { switch (ty) { case GridNotification.DidUpdateGridBlock: result.fold( - (payload) => rowsUpdateNotifier.value = left([GridBlockOrderChangeset.fromBuffer(payload)]), + (payload) => rowsUpdateNotifier.value = left([GridRowsChangeset.fromBuffer(payload)]), (error) => rowsUpdateNotifier.value = right(error), ); break; diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index ab618b0fa9..66de503321 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -32,6 +32,9 @@ class GridPropertyBloc extends Bloc { didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { emit(state.copyWith(fields: value.fields)); }, + moveField: (_MoveField value) { + // + }, ); }, ); @@ -61,6 +64,7 @@ class GridPropertyEvent with _$GridPropertyEvent { const factory GridPropertyEvent.initial() = _Initial; const factory GridPropertyEvent.setFieldVisibility(String fieldId, bool visibility) = _SetFieldVisibility; const factory GridPropertyEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; + const factory GridPropertyEvent.moveField(int fromIndex, int toIndex) = _MoveField; } @freezed diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index a34682d204..0a9cddedd5 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -46,20 +46,16 @@ class GridPropertyList extends StatelessWidget with FlowyOverlayDelegate { getIt(param1: gridId, param2: fields)..add(const GridPropertyEvent.initial()), child: BlocBuilder( builder: (context, state) { - final cells = state.fields.map((field) { - return _GridPropertyCell(gridId: gridId, field: field); + final children = state.fields.map((field) { + return _GridPropertyCell(gridId: gridId, field: field, key: ValueKey(field.id)); }).toList(); - return ListView.separated( + return ReorderableListView( shrinkWrap: true, - controller: ScrollController(), - separatorBuilder: (context, index) { - return VSpace(GridSize.typeOptionSeparatorHeight); - }, - itemCount: cells.length, - itemBuilder: (BuildContext context, int index) { - return cells[index]; + onReorder: (int oldIndex, int newIndex) { + context.read().add(GridPropertyEvent.moveField(oldIndex, newIndex)); }, + children: children, ); }, ), diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart index a8fd9add65..33925ca955 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart @@ -154,6 +154,23 @@ class GridEventGetEditFieldContext { } } +class GridEventMoveItem { + MoveItemPayload request; + GridEventMoveItem(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.MoveItem.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + class GridEventNewSelectOption { SelectOptionName request; GridEventNewSelectOption(this.request); 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 fac1ee178a..1452679e63 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 @@ -857,8 +857,8 @@ class GridBlockOrder extends $pb.GeneratedMessage { $core.List get rowOrders => $_getList(1); } -class GridBlockOrderChangeset extends $pb.GeneratedMessage { - static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlockOrderChangeset', createEmptyInstance: create) +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) @@ -866,8 +866,8 @@ class GridBlockOrderChangeset extends $pb.GeneratedMessage { ..hasRequiredFields = false ; - GridBlockOrderChangeset._() : super(); - factory GridBlockOrderChangeset({ + GridRowsChangeset._() : super(); + factory GridRowsChangeset({ $core.String? blockId, $core.Iterable? insertedRows, $core.Iterable? deletedRows, @@ -888,26 +888,26 @@ class GridBlockOrderChangeset extends $pb.GeneratedMessage { } return _result; } - factory GridBlockOrderChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory GridBlockOrderChangeset.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory GridRowsChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridRowsChangeset.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') - GridBlockOrderChangeset clone() => GridBlockOrderChangeset()..mergeFromMessage(this); + GridRowsChangeset clone() => GridRowsChangeset()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - GridBlockOrderChangeset copyWith(void Function(GridBlockOrderChangeset) updates) => super.copyWith((message) => updates(message as GridBlockOrderChangeset)) as GridBlockOrderChangeset; // ignore: deprecated_member_use + GridRowsChangeset copyWith(void Function(GridRowsChangeset) updates) => super.copyWith((message) => updates(message as GridRowsChangeset)) as GridRowsChangeset; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static GridBlockOrderChangeset create() => GridBlockOrderChangeset._(); - GridBlockOrderChangeset createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static GridRowsChangeset create() => GridRowsChangeset._(); + GridRowsChangeset createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static GridBlockOrderChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static GridBlockOrderChangeset? _defaultInstance; + static GridRowsChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridRowsChangeset? _defaultInstance; @$pb.TagNumber(1) $core.String get blockId => $_getSZ(0); @@ -1950,6 +1950,109 @@ class FieldChangesetPayload extends $pb.GeneratedMessage { void clearTypeOptionData() => clearField(9); } +class MoveItemPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'MoveItemPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'itemId') + ..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fromIndex', $pb.PbFieldType.O3) + ..a<$core.int>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'toIndex', $pb.PbFieldType.O3) + ..e(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: MoveItemType.MoveField, valueOf: MoveItemType.valueOf, enumValues: MoveItemType.values) + ..hasRequiredFields = false + ; + + MoveItemPayload._() : super(); + factory MoveItemPayload({ + $core.String? gridId, + $core.String? itemId, + $core.int? fromIndex, + $core.int? toIndex, + MoveItemType? ty, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (itemId != null) { + _result.itemId = itemId; + } + if (fromIndex != null) { + _result.fromIndex = fromIndex; + } + if (toIndex != null) { + _result.toIndex = toIndex; + } + if (ty != null) { + _result.ty = ty; + } + return _result; + } + factory MoveItemPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory MoveItemPayload.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') + MoveItemPayload clone() => MoveItemPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + MoveItemPayload copyWith(void Function(MoveItemPayload) updates) => super.copyWith((message) => updates(message as MoveItemPayload)) as MoveItemPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static MoveItemPayload create() => MoveItemPayload._(); + MoveItemPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static MoveItemPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static MoveItemPayload? _defaultInstance; + + @$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 itemId => $_getSZ(1); + @$pb.TagNumber(2) + set itemId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasItemId() => $_has(1); + @$pb.TagNumber(2) + void clearItemId() => clearField(2); + + @$pb.TagNumber(3) + $core.int get fromIndex => $_getIZ(2); + @$pb.TagNumber(3) + set fromIndex($core.int v) { $_setSignedInt32(2, v); } + @$pb.TagNumber(3) + $core.bool hasFromIndex() => $_has(2); + @$pb.TagNumber(3) + void clearFromIndex() => clearField(3); + + @$pb.TagNumber(4) + $core.int get toIndex => $_getIZ(3); + @$pb.TagNumber(4) + set toIndex($core.int v) { $_setSignedInt32(3, v); } + @$pb.TagNumber(4) + $core.bool hasToIndex() => $_has(3); + @$pb.TagNumber(4) + void clearToIndex() => clearField(4); + + @$pb.TagNumber(5) + MoveItemType get ty => $_getN(4); + @$pb.TagNumber(5) + set ty(MoveItemType v) { setField(5, v); } + @$pb.TagNumber(5) + $core.bool hasTy() => $_has(4); + @$pb.TagNumber(5) + void clearTy() => clearField(5); +} + enum CellChangeset_OneOfData { data, notSet diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbenum.dart index 661b26532c..e6cb17314b 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbenum.dart @@ -9,6 +9,21 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; +class MoveItemType extends $pb.ProtobufEnum { + static const MoveItemType MoveField = MoveItemType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveField'); + static const MoveItemType MoveRow = MoveItemType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveRow'); + + static const $core.List values = [ + MoveField, + MoveRow, + ]; + + static final $core.Map<$core.int, MoveItemType> _byValue = $pb.ProtobufEnum.initByValue(values); + static MoveItemType? valueOf($core.int value) => _byValue[value]; + + const MoveItemType._($core.int v, $core.String n) : super(v, n); +} + class FieldType extends $pb.ProtobufEnum { static const FieldType RichText = FieldType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RichText'); static const FieldType Number = FieldType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Number'); 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 0f8165fb8d..09cac1722c 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 @@ -8,6 +8,17 @@ import 'dart:core' as $core; import 'dart:convert' as $convert; import 'dart:typed_data' as $typed_data; +@$core.Deprecated('Use moveItemTypeDescriptor instead') +const MoveItemType$json = const { + '1': 'MoveItemType', + '2': const [ + const {'1': 'MoveField', '2': 0}, + const {'1': 'MoveRow', '2': 1}, + ], +}; + +/// Descriptor for `MoveItemType`. Decode as a `google.protobuf.EnumDescriptorProto`. +final $typed_data.Uint8List moveItemTypeDescriptor = $convert.base64Decode('CgxNb3ZlSXRlbVR5cGUSDQoJTW92ZUZpZWxkEAASCwoHTW92ZVJvdxAB'); @$core.Deprecated('Use fieldTypeDescriptor instead') const FieldType$json = const { '1': 'FieldType', @@ -186,9 +197,9 @@ const GridBlockOrder$json = const { /// Descriptor for `GridBlockOrder`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List gridBlockOrderDescriptor = $convert.base64Decode('Cg5HcmlkQmxvY2tPcmRlchIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIoCgpyb3dfb3JkZXJzGAIgAygLMgkuUm93T3JkZXJSCXJvd09yZGVycw=='); -@$core.Deprecated('Use gridBlockOrderChangesetDescriptor instead') -const GridBlockOrderChangeset$json = const { - '1': 'GridBlockOrderChangeset', +@$core.Deprecated('Use gridRowsChangesetDescriptor instead') +const GridRowsChangeset$json = const { + '1': 'GridRowsChangeset', '2': 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'}, @@ -197,8 +208,8 @@ const GridBlockOrderChangeset$json = const { ], }; -/// Descriptor for `GridBlockOrderChangeset`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List gridBlockOrderChangesetDescriptor = $convert.base64Decode('ChdHcmlkQmxvY2tPcmRlckNoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIsCgx1cGRhdGVkX3Jvd3MYBCADKAsyCS5Sb3dPcmRlclILdXBkYXRlZFJvd3M='); +/// Descriptor for `GridRowsChangeset`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridRowsChangesetDescriptor = $convert.base64Decode('ChFHcmlkUm93c0NoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIsCgx1cGRhdGVkX3Jvd3MYBCADKAsyCS5Sb3dPcmRlclILdXBkYXRlZFJvd3M='); @$core.Deprecated('Use indexRowOrderDescriptor instead') const IndexRowOrder$json = const { '1': 'IndexRowOrder', @@ -370,6 +381,20 @@ const FieldChangesetPayload$json = const { /// Descriptor for `FieldChangesetPayload`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List fieldChangesetPayloadDescriptor = $convert.base64Decode('ChVGaWVsZENoYW5nZXNldFBheWxvYWQSGQoIZmllbGRfaWQYASABKAlSB2ZpZWxkSWQSFwoHZ3JpZF9pZBgCIAEoCVIGZ3JpZElkEhQKBG5hbWUYAyABKAlIAFIEbmFtZRIUCgRkZXNjGAQgASgJSAFSBGRlc2MSKwoKZmllbGRfdHlwZRgFIAEoDjIKLkZpZWxkVHlwZUgCUglmaWVsZFR5cGUSGAoGZnJvemVuGAYgASgISANSBmZyb3plbhIgCgp2aXNpYmlsaXR5GAcgASgISARSCnZpc2liaWxpdHkSFgoFd2lkdGgYCCABKAVIBVIFd2lkdGgSKgoQdHlwZV9vcHRpb25fZGF0YRgJIAEoDEgGUg50eXBlT3B0aW9uRGF0YUINCgtvbmVfb2ZfbmFtZUINCgtvbmVfb2ZfZGVzY0ITChFvbmVfb2ZfZmllbGRfdHlwZUIPCg1vbmVfb2ZfZnJvemVuQhMKEW9uZV9vZl92aXNpYmlsaXR5Qg4KDG9uZV9vZl93aWR0aEIZChdvbmVfb2ZfdHlwZV9vcHRpb25fZGF0YQ=='); +@$core.Deprecated('Use moveItemPayloadDescriptor instead') +const MoveItemPayload$json = const { + '1': 'MoveItemPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'item_id', '3': 2, '4': 1, '5': 9, '10': 'itemId'}, + const {'1': 'from_index', '3': 3, '4': 1, '5': 5, '10': 'fromIndex'}, + const {'1': 'to_index', '3': 4, '4': 1, '5': 5, '10': 'toIndex'}, + const {'1': 'ty', '3': 5, '4': 1, '5': 14, '6': '.MoveItemType', '10': 'ty'}, + ], +}; + +/// Descriptor for `MoveItemPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List moveItemPayloadDescriptor = $convert.base64Decode('Cg9Nb3ZlSXRlbVBheWxvYWQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEhcKB2l0ZW1faWQYAiABKAlSBml0ZW1JZBIdCgpmcm9tX2luZGV4GAMgASgFUglmcm9tSW5kZXgSGQoIdG9faW5kZXgYBCABKAVSB3RvSW5kZXgSHQoCdHkYBSABKA4yDS5Nb3ZlSXRlbVR5cGVSAnR5'); @$core.Deprecated('Use cellChangesetDescriptor instead') const CellChangeset$json = const { '1': 'CellChangeset', diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart index b4bde9790b..4c898182c7 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart @@ -19,6 +19,7 @@ class GridEvent extends $pb.ProtobufEnum { static const GridEvent SwitchToField = GridEvent._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SwitchToField'); static const GridEvent DuplicateField = GridEvent._(15, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField'); static const GridEvent GetEditFieldContext = GridEvent._(16, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetEditFieldContext'); + static const GridEvent MoveItem = GridEvent._(17, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem'); static const GridEvent NewSelectOption = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewSelectOption'); static const GridEvent GetSelectOptionContext = GridEvent._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetSelectOptionContext'); static const GridEvent UpdateSelectOption = GridEvent._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOption'); @@ -40,6 +41,7 @@ class GridEvent extends $pb.ProtobufEnum { SwitchToField, DuplicateField, GetEditFieldContext, + MoveItem, NewSelectOption, GetSelectOptionContext, UpdateSelectOption, diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart index 272b82e375..b03ea1cc64 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart @@ -21,6 +21,7 @@ const GridEvent$json = const { const {'1': 'SwitchToField', '2': 14}, const {'1': 'DuplicateField', '2': 15}, const {'1': 'GetEditFieldContext', '2': 16}, + const {'1': 'MoveItem', '2': 17}, const {'1': 'NewSelectOption', '2': 30}, const {'1': 'GetSelectOptionContext', '2': 31}, const {'1': 'UpdateSelectOption', '2': 32}, @@ -35,4 +36,4 @@ const GridEvent$json = const { }; /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtJbnNlcnRGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEQoNU3dpdGNoVG9GaWVsZBAOEhIKDkR1cGxpY2F0ZUZpZWxkEA8SFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAQEhMKD05ld1NlbGVjdE9wdGlvbhAeEhoKFkdldFNlbGVjdE9wdGlvbkNvbnRleHQQHxIWChJVcGRhdGVTZWxlY3RPcHRpb24QIBINCglDcmVhdGVSb3cQMhIKCgZHZXRSb3cQMxINCglEZWxldGVSb3cQNBIQCgxEdXBsaWNhdGVSb3cQNRILCgdHZXRDZWxsEEYSDgoKVXBkYXRlQ2VsbBBHEhoKFlVwZGF0ZUNlbGxTZWxlY3RPcHRpb24QSA=='); +final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtJbnNlcnRGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEQoNU3dpdGNoVG9GaWVsZBAOEhIKDkR1cGxpY2F0ZUZpZWxkEA8SFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAQEgwKCE1vdmVJdGVtEBESEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlQ2VsbFNlbGVjdE9wdGlvbhBI'); diff --git a/frontend/app_flowy/pubspec.lock b/frontend/app_flowy/pubspec.lock index 428982c60e..1a3a3172f4 100644 --- a/frontend/app_flowy/pubspec.lock +++ b/frontend/app_flowy/pubspec.lock @@ -947,6 +947,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1+1" + reorderables: + dependency: "direct main" + description: + name: reorderables + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.3" shared_preferences: dependency: transitive description: diff --git a/frontend/app_flowy/pubspec.yaml b/frontend/app_flowy/pubspec.yaml index 495e2482cd..bcc3303602 100644 --- a/frontend/app_flowy/pubspec.yaml +++ b/frontend/app_flowy/pubspec.yaml @@ -74,6 +74,7 @@ dependencies: device_info_plus: ^3.2.1 fluttertoast: ^8.0.8 table_calendar: ^3.0.5 + reorderables: dev_dependencies: flutter_lints: ^1.0.0 diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index e9f0bda61e..9efdf0d01f 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -130,6 +130,17 @@ pub(crate) async fn get_field_context_handler( data_result(edit_context) } +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn move_item_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: MoveItemParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor.move_item(params).await?; + Ok(()) +} + async fn make_field_edit_context( grid_id: &str, field_id: Option, diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index 08a2a25313..67cbebe2d9 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -17,6 +17,8 @@ pub fn create(grid_manager: Arc) -> Module { .event(GridEvent::DeleteField, delete_field_handler) .event(GridEvent::SwitchToField, switch_to_field_handler) .event(GridEvent::DuplicateField, duplicate_field_handler) + .event(GridEvent::GetEditFieldContext, get_field_context_handler) + .event(GridEvent::MoveItem, move_item_handler) // Row .event(GridEvent::CreateRow, create_row_handler) .event(GridEvent::GetRow, get_row_handler) @@ -29,9 +31,7 @@ pub fn create(grid_manager: Arc) -> Module { .event(GridEvent::NewSelectOption, new_select_option_handler) .event(GridEvent::UpdateSelectOption, update_select_option_handler) .event(GridEvent::GetSelectOptionContext, get_select_option_handler) - .event(GridEvent::UpdateCellSelectOption, update_cell_select_option_handler) - // - .event(GridEvent::GetEditFieldContext, get_field_context_handler); + .event(GridEvent::UpdateCellSelectOption, update_cell_select_option_handler); module } @@ -66,6 +66,9 @@ pub enum GridEvent { #[event(input = "GetEditFieldContextPayload", output = "EditFieldContext")] GetEditFieldContext = 16, + #[event(input = "MoveItemPayload")] + MoveItem = 17, + #[event(input = "SelectOptionName", output = "SelectOption")] NewSelectOption = 30, diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs index c474939b47..b4792931ae 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs @@ -34,6 +34,7 @@ pub enum GridEvent { SwitchToField = 14, DuplicateField = 15, GetEditFieldContext = 16, + MoveItem = 17, NewSelectOption = 30, GetSelectOptionContext = 31, UpdateSelectOption = 32, @@ -62,6 +63,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { 14 => ::std::option::Option::Some(GridEvent::SwitchToField), 15 => ::std::option::Option::Some(GridEvent::DuplicateField), 16 => ::std::option::Option::Some(GridEvent::GetEditFieldContext), + 17 => ::std::option::Option::Some(GridEvent::MoveItem), 30 => ::std::option::Option::Some(GridEvent::NewSelectOption), 31 => ::std::option::Option::Some(GridEvent::GetSelectOptionContext), 32 => ::std::option::Option::Some(GridEvent::UpdateSelectOption), @@ -87,6 +89,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { GridEvent::SwitchToField, GridEvent::DuplicateField, GridEvent::GetEditFieldContext, + GridEvent::MoveItem, GridEvent::NewSelectOption, GridEvent::GetSelectOptionContext, GridEvent::UpdateSelectOption, @@ -125,16 +128,16 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\xef\x02\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ + \n\x0fevent_map.proto*\xfd\x02\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\ \x0bUpdateField\x10\x0b\x12\x0f\n\x0bInsertField\x10\x0c\x12\x0f\n\x0bDe\ leteField\x10\r\x12\x11\n\rSwitchToField\x10\x0e\x12\x12\n\x0eDuplicateF\ - ield\x10\x0f\x12\x17\n\x13GetEditFieldContext\x10\x10\x12\x13\n\x0fNewSe\ - lectOption\x10\x1e\x12\x1a\n\x16GetSelectOptionContext\x10\x1f\x12\x16\n\ - \x12UpdateSelectOption\x10\x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\ - \x103\x12\r\n\tDeleteRow\x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\ - \x07GetCell\x10F\x12\x0e\n\nUpdateCell\x10G\x12\x1a\n\x16UpdateCellSelec\ - tOption\x10Hb\x06proto3\ + ield\x10\x0f\x12\x17\n\x13GetEditFieldContext\x10\x10\x12\x0c\n\x08MoveI\ + tem\x10\x11\x12\x13\n\x0fNewSelectOption\x10\x1e\x12\x1a\n\x16GetSelectO\ + ptionContext\x10\x1f\x12\x16\n\x12UpdateSelectOption\x10\x20\x12\r\n\tCr\ + eateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteRow\x104\x12\x10\n\ + \x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\nUpdateCell\ + \x10G\x12\x1a\n\x16UpdateCellSelectOption\x10Hb\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto index eb66389430..7f45db5761 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto @@ -10,6 +10,7 @@ enum GridEvent { SwitchToField = 14; DuplicateField = 15; GetEditFieldContext = 16; + MoveItem = 17; NewSelectOption = 30; GetSelectOptionContext = 31; UpdateSelectOption = 32; 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 b1817c85a6..0eda4615bf 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 @@ -8,8 +8,8 @@ use std::borrow::Cow; use dashmap::DashMap; use flowy_error::FlowyResult; use flowy_grid_data_model::entities::{ - CellChangeset, CellMeta, CellNotificationData, FieldMeta, GridBlockMeta, GridBlockMetaChangeset, - GridBlockOrderChangeset, IndexRowOrder, RowMeta, RowMetaChangeset, RowOrder, + CellChangeset, CellMeta, CellNotificationData, FieldMeta, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, + IndexRowOrder, RowMeta, RowMetaChangeset, RowOrder, }; use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; use flowy_revision::{RevisionManager, RevisionPersistence}; @@ -76,7 +76,7 @@ impl GridBlockMetaEditorManager { index_row_order.index = row_index; let _ = self - .notify_did_update_grid_rows(GridBlockOrderChangeset::from_insert(block_id, vec![index_row_order])) + .notify_did_update_grid_rows(GridRowsChangeset::insert(block_id, vec![index_row_order])) .await?; Ok(row_count) } @@ -98,7 +98,7 @@ impl GridBlockMetaEditorManager { changesets.push(GridBlockMetaChangeset::from_row_count(&block_id, row_count)); let _ = self - .notify_did_update_grid_rows(GridBlockOrderChangeset::from_insert(&block_id, inserted_row_orders)) + .notify_did_update_grid_rows(GridRowsChangeset::insert(&block_id, inserted_row_orders)) .await?; } @@ -116,7 +116,7 @@ impl GridBlockMetaEditorManager { { None => {} Some(row_order) => { - let block_order_changeset = GridBlockOrderChangeset::from_update(&editor.block_id, vec![row_order]); + let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]); let _ = self.notify_did_update_grid_rows(block_order_changeset).await?; } } @@ -131,7 +131,7 @@ impl GridBlockMetaEditorManager { 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_grid_rows(GridBlockOrderChangeset::from_delete(&block_id, row_orders)) + .notify_did_update_grid_rows(GridRowsChangeset::delete(&block_id, row_orders)) .await?; Ok(()) @@ -213,7 +213,7 @@ impl GridBlockMetaEditorManager { Ok(block_cell_metas) } - async fn notify_did_update_grid_rows(&self, changeset: GridBlockOrderChangeset) -> FlowyResult<()> { + async fn notify_did_update_grid_rows(&self, changeset: GridRowsChangeset) -> FlowyResult<()> { send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridBlock) .payload(changeset) .send(); 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 f78adda837..f65179ebd3 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -375,6 +375,24 @@ impl ClientGridEditor { Ok(snapshots) } + pub async fn move_item(&self, params: MoveItemParams) -> FlowyResult<()> { + match params.ty { + MoveItemType::MoveField => { + self.move_field(params.from_index, params.to_index, ¶ms.item_id) + .await + } + MoveItemType::MoveRow => self.move_row(params.from_index, params.to_index, ¶ms.item_id).await, + } + } + + pub async fn move_field(&self, from: i32, to: i32, field_id: &str) -> FlowyResult<()> { + todo!() + } + + pub async fn move_row(&self, from: i32, to: i32, row_id: &str) -> FlowyResult<()> { + todo!() + } + pub async fn delta_bytes(&self) -> Bytes { self.pad.read().await.delta_bytes() } 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 eddbc4b19f..0becd3d665 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -278,7 +278,7 @@ impl GridBlockOrder { } #[derive(Debug, Clone, Default, ProtoBuf)] -pub struct GridBlockOrderChangeset { +pub struct GridRowsChangeset { #[pb(index = 1)] pub block_id: String, @@ -314,8 +314,8 @@ impl std::convert::From<&RowMeta> for IndexRowOrder { } } -impl GridBlockOrderChangeset { - pub fn from_insert(block_id: &str, inserted_rows: Vec) -> Self { +impl GridRowsChangeset { + pub fn insert(block_id: &str, inserted_rows: Vec) -> Self { Self { block_id: block_id.to_owned(), inserted_rows, @@ -324,7 +324,7 @@ impl GridBlockOrderChangeset { } } - pub fn from_delete(block_id: &str, deleted_rows: Vec) -> Self { + pub fn delete(block_id: &str, deleted_rows: Vec) -> Self { Self { block_id: block_id.to_owned(), inserted_rows: vec![], @@ -333,7 +333,7 @@ impl GridBlockOrderChangeset { } } - pub fn from_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![], @@ -656,6 +656,61 @@ impl TryInto for FieldChangesetPayload { } } +#[derive(Debug, Clone, ProtoBuf_Enum)] +pub enum MoveItemType { + MoveField = 0, + MoveRow = 1, +} + +impl std::default::Default for MoveItemType { + fn default() -> Self { + MoveItemType::MoveField + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct MoveItemPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub item_id: String, + + #[pb(index = 3)] + pub from_index: i32, + + #[pb(index = 4)] + pub to_index: i32, + + #[pb(index = 5)] + pub ty: MoveItemType, +} + +#[derive(Clone)] +pub struct MoveItemParams { + pub grid_id: String, + pub item_id: String, + pub from_index: i32, + pub to_index: i32, + pub ty: MoveItemType, +} + +impl TryInto for MoveItemPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let item_id = NotEmptyStr::parse(self.item_id).map_err(|_| ErrorCode::InvalidData)?; + Ok(MoveItemParams { + grid_id: grid_id.0, + item_id: item_id.0, + from_index: self.from_index, + to_index: self.to_index, + ty: self.ty, + }) + } +} + #[derive( Debug, Clone, 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 6f2e7d1787..15e85282f8 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 @@ -2920,7 +2920,7 @@ impl ::protobuf::reflect::ProtobufValue for GridBlockOrder { } #[derive(PartialEq,Clone,Default)] -pub struct GridBlockOrderChangeset { +pub struct GridRowsChangeset { // message fields pub block_id: ::std::string::String, pub inserted_rows: ::protobuf::RepeatedField, @@ -2931,14 +2931,14 @@ pub struct GridBlockOrderChangeset { pub cached_size: ::protobuf::CachedSize, } -impl<'a> ::std::default::Default for &'a GridBlockOrderChangeset { - fn default() -> &'a GridBlockOrderChangeset { - ::default_instance() +impl<'a> ::std::default::Default for &'a GridRowsChangeset { + fn default() -> &'a GridRowsChangeset { + ::default_instance() } } -impl GridBlockOrderChangeset { - pub fn new() -> GridBlockOrderChangeset { +impl GridRowsChangeset { + pub fn new() -> GridRowsChangeset { ::std::default::Default::default() } @@ -3044,7 +3044,7 @@ impl GridBlockOrderChangeset { } } -impl ::protobuf::Message for GridBlockOrderChangeset { +impl ::protobuf::Message for GridRowsChangeset { fn is_initialized(&self) -> bool { for v in &self.inserted_rows { if !v.is_initialized() { @@ -3161,8 +3161,8 @@ impl ::protobuf::Message for GridBlockOrderChangeset { Self::descriptor_static() } - fn new() -> GridBlockOrderChangeset { - GridBlockOrderChangeset::new() + fn new() -> GridRowsChangeset { + GridRowsChangeset::new() } fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { @@ -3171,39 +3171,39 @@ impl ::protobuf::Message for GridBlockOrderChangeset { let mut fields = ::std::vec::Vec::new(); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( "block_id", - |m: &GridBlockOrderChangeset| { &m.block_id }, - |m: &mut GridBlockOrderChangeset| { &mut m.block_id }, + |m: &GridRowsChangeset| { &m.block_id }, + |m: &mut GridRowsChangeset| { &mut m.block_id }, )); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "inserted_rows", - |m: &GridBlockOrderChangeset| { &m.inserted_rows }, - |m: &mut GridBlockOrderChangeset| { &mut m.inserted_rows }, + |m: &GridRowsChangeset| { &m.inserted_rows }, + |m: &mut GridRowsChangeset| { &mut m.inserted_rows }, )); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "deleted_rows", - |m: &GridBlockOrderChangeset| { &m.deleted_rows }, - |m: &mut GridBlockOrderChangeset| { &mut m.deleted_rows }, + |m: &GridRowsChangeset| { &m.deleted_rows }, + |m: &mut GridRowsChangeset| { &mut m.deleted_rows }, )); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "updated_rows", - |m: &GridBlockOrderChangeset| { &m.updated_rows }, - |m: &mut GridBlockOrderChangeset| { &mut m.updated_rows }, + |m: &GridRowsChangeset| { &m.updated_rows }, + |m: &mut GridRowsChangeset| { &mut m.updated_rows }, )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "GridBlockOrderChangeset", + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GridRowsChangeset", fields, file_descriptor_proto() ) }) } - fn default_instance() -> &'static GridBlockOrderChangeset { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(GridBlockOrderChangeset::new) + fn default_instance() -> &'static GridRowsChangeset { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GridRowsChangeset::new) } } -impl ::protobuf::Clear for GridBlockOrderChangeset { +impl ::protobuf::Clear for GridRowsChangeset { fn clear(&mut self) { self.block_id.clear(); self.inserted_rows.clear(); @@ -3213,13 +3213,13 @@ impl ::protobuf::Clear for GridBlockOrderChangeset { } } -impl ::std::fmt::Debug for GridBlockOrderChangeset { +impl ::std::fmt::Debug for GridRowsChangeset { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for GridBlockOrderChangeset { +impl ::protobuf::reflect::ProtobufValue for GridRowsChangeset { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } @@ -6512,6 +6512,308 @@ impl ::protobuf::reflect::ProtobufValue for FieldChangesetPayload { } } +#[derive(PartialEq,Clone,Default)] +pub struct MoveItemPayload { + // message fields + pub grid_id: ::std::string::String, + pub item_id: ::std::string::String, + pub from_index: i32, + pub to_index: i32, + pub ty: MoveItemType, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a MoveItemPayload { + fn default() -> &'a MoveItemPayload { + ::default_instance() + } +} + +impl MoveItemPayload { + pub fn new() -> MoveItemPayload { + ::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 item_id = 2; + + + pub fn get_item_id(&self) -> &str { + &self.item_id + } + pub fn clear_item_id(&mut self) { + self.item_id.clear(); + } + + // Param is passed by value, moved + pub fn set_item_id(&mut self, v: ::std::string::String) { + self.item_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_item_id(&mut self) -> &mut ::std::string::String { + &mut self.item_id + } + + // Take field + pub fn take_item_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.item_id, ::std::string::String::new()) + } + + // int32 from_index = 3; + + + pub fn get_from_index(&self) -> i32 { + self.from_index + } + pub fn clear_from_index(&mut self) { + self.from_index = 0; + } + + // Param is passed by value, moved + pub fn set_from_index(&mut self, v: i32) { + self.from_index = v; + } + + // int32 to_index = 4; + + + pub fn get_to_index(&self) -> i32 { + self.to_index + } + pub fn clear_to_index(&mut self) { + self.to_index = 0; + } + + // Param is passed by value, moved + pub fn set_to_index(&mut self, v: i32) { + self.to_index = v; + } + + // .MoveItemType ty = 5; + + + pub fn get_ty(&self) -> MoveItemType { + self.ty + } + pub fn clear_ty(&mut self) { + self.ty = MoveItemType::MoveField; + } + + // Param is passed by value, moved + pub fn set_ty(&mut self, v: MoveItemType) { + self.ty = v; + } +} + +impl ::protobuf::Message for MoveItemPayload { + 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.item_id)?; + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.from_index = tmp; + }, + 4 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int32()?; + self.to_index = tmp; + }, + 5 => { + ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 5, &mut self.unknown_fields)? + }, + _ => { + ::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.item_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.item_id); + } + if self.from_index != 0 { + my_size += ::protobuf::rt::value_size(3, self.from_index, ::protobuf::wire_format::WireTypeVarint); + } + if self.to_index != 0 { + my_size += ::protobuf::rt::value_size(4, self.to_index, ::protobuf::wire_format::WireTypeVarint); + } + if self.ty != MoveItemType::MoveField { + my_size += ::protobuf::rt::enum_size(5, self.ty); + } + 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.item_id.is_empty() { + os.write_string(2, &self.item_id)?; + } + if self.from_index != 0 { + os.write_int32(3, self.from_index)?; + } + if self.to_index != 0 { + os.write_int32(4, self.to_index)?; + } + if self.ty != MoveItemType::MoveField { + os.write_enum(5, ::protobuf::ProtobufEnum::value(&self.ty))?; + } + 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() -> MoveItemPayload { + MoveItemPayload::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: &MoveItemPayload| { &m.grid_id }, + |m: &mut MoveItemPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "item_id", + |m: &MoveItemPayload| { &m.item_id }, + |m: &mut MoveItemPayload| { &mut m.item_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "from_index", + |m: &MoveItemPayload| { &m.from_index }, + |m: &mut MoveItemPayload| { &mut m.from_index }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( + "to_index", + |m: &MoveItemPayload| { &m.to_index }, + |m: &mut MoveItemPayload| { &mut m.to_index }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( + "ty", + |m: &MoveItemPayload| { &m.ty }, + |m: &mut MoveItemPayload| { &mut m.ty }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "MoveItemPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static MoveItemPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(MoveItemPayload::new) + } +} + +impl ::protobuf::Clear for MoveItemPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.item_id.clear(); + self.from_index = 0; + self.to_index = 0; + self.ty = MoveItemType::MoveField; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for MoveItemPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for MoveItemPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct CellChangeset { // message fields @@ -6837,6 +7139,56 @@ impl ::protobuf::reflect::ProtobufValue for CellChangeset { } } +#[derive(Clone,PartialEq,Eq,Debug,Hash)] +pub enum MoveItemType { + MoveField = 0, + MoveRow = 1, +} + +impl ::protobuf::ProtobufEnum for MoveItemType { + fn value(&self) -> i32 { + *self as i32 + } + + fn from_i32(value: i32) -> ::std::option::Option { + match value { + 0 => ::std::option::Option::Some(MoveItemType::MoveField), + 1 => ::std::option::Option::Some(MoveItemType::MoveRow), + _ => ::std::option::Option::None + } + } + + fn values() -> &'static [Self] { + static values: &'static [MoveItemType] = &[ + MoveItemType::MoveField, + MoveItemType::MoveRow, + ]; + values + } + + fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + ::protobuf::reflect::EnumDescriptor::new_pb_name::("MoveItemType", file_descriptor_proto()) + }) + } +} + +impl ::std::marker::Copy for MoveItemType { +} + +impl ::std::default::Default for MoveItemType { + fn default() -> Self { + MoveItemType::MoveField + } +} + +impl ::protobuf::reflect::ProtobufValue for MoveItemType { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self)) + } +} + #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum FieldType { RichText = 0, @@ -6932,19 +7284,19 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05items\x18\x01\ \x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\x12\x19\n\ \x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\x18\x02\ - \x20\x03(\x0b2\t.RowOrderR\trowOrders\"\xc5\x01\n\x17GridBlockOrderChang\ - eset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x123\n\rinsert\ - ed_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cinsertedRows\x12,\n\ - \x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bdeletedRows\x12,\n\ - \x0cupdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0bupdatedRows\"_\n\r\ - IndexRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08row\ - Order\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone\ - _of_index\"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\ + \x20\x03(\x0b2\t.RowOrderR\trowOrders\"\xbf\x01\n\x11GridRowsChangeset\ + \x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x123\n\rinserted_r\ + ows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cinsertedRows\x12,\n\x0cd\ + eleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bdeletedRows\x12,\n\x0cu\ + pdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0bupdatedRows\"_\n\rIndex\ + RowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\ + \x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_i\ + ndex\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nr\ + ow_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\"\x8f\x01\n\x14CellNotificationData\x12\ + \x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\ + \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\ @@ -6971,14 +7323,19 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \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\"\x7f\n\rCellChangese\ - t\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*d\n\tFieldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\ - \x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\ - \x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06prot\ - o3\ + \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\ "; 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 e5950858f0..eca5a5f0ea 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 @@ -58,7 +58,7 @@ message GridBlockOrder { string block_id = 1; repeated RowOrder row_orders = 2; } -message GridBlockOrderChangeset { +message GridRowsChangeset { string block_id = 1; repeated IndexRowOrder inserted_rows = 2; repeated RowOrder deleted_rows = 3; @@ -123,12 +123,23 @@ message FieldChangesetPayload { oneof one_of_width { int32 width = 8; }; oneof one_of_type_option_data { bytes type_option_data = 9; }; } +message MoveItemPayload { + string grid_id = 1; + string item_id = 2; + int32 from_index = 3; + int32 to_index = 4; + MoveItemType ty = 5; +} message CellChangeset { string grid_id = 1; string row_id = 2; string field_id = 3; oneof one_of_data { string data = 4; }; } +enum MoveItemType { + MoveField = 0; + MoveRow = 1; +} enum FieldType { RichText = 0; Number = 1; From 06af45a8ed8f92633de0a0d81a82a157b60526f2 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 13 Apr 2022 21:26:27 +0800 Subject: [PATCH 05/26] chore: udpate field notification --- .../flowy-grid-data-model/grid.pb.dart | 289 +++- .../flowy-grid-data-model/grid.pbjson.dart | 53 +- .../src/services/block_meta_manager.rs | 10 +- .../flowy-grid/src/services/grid_editor.rs | 21 +- .../src/entities/grid.rs | 71 +- .../src/protobuf/model/grid.rs | 1158 ++++++++++++----- .../src/protobuf/proto/grid.proto | 18 +- .../src/client_grid/grid_meta_pad.rs | 30 +- 8 files changed, 1227 insertions(+), 423 deletions(-) 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 1452679e63..1212cb506e 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 @@ -254,6 +254,153 @@ class FieldOrder extends $pb.GeneratedMessage { void clearFieldId() => clearField(1); } +class GridFieldChangeset extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridFieldChangeset', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertedFields', $pb.PbFieldType.PM, subBuilder: IndexField.create) + ..pc(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deletedFields', $pb.PbFieldType.PM, subBuilder: FieldOrder.create) + ..pc(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedFields', $pb.PbFieldType.PM, subBuilder: Field.create) + ..hasRequiredFields = false + ; + + GridFieldChangeset._() : super(); + factory GridFieldChangeset({ + $core.String? gridId, + $core.Iterable? insertedFields, + $core.Iterable? deletedFields, + $core.Iterable? updatedFields, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (insertedFields != null) { + _result.insertedFields.addAll(insertedFields); + } + if (deletedFields != null) { + _result.deletedFields.addAll(deletedFields); + } + if (updatedFields != null) { + _result.updatedFields.addAll(updatedFields); + } + return _result; + } + factory GridFieldChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridFieldChangeset.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') + GridFieldChangeset clone() => GridFieldChangeset()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GridFieldChangeset copyWith(void Function(GridFieldChangeset) updates) => super.copyWith((message) => updates(message as GridFieldChangeset)) as GridFieldChangeset; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GridFieldChangeset create() => GridFieldChangeset._(); + GridFieldChangeset createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GridFieldChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridFieldChangeset? _defaultInstance; + + @$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.List get insertedFields => $_getList(1); + + @$pb.TagNumber(3) + $core.List get deletedFields => $_getList(2); + + @$pb.TagNumber(4) + $core.List get updatedFields => $_getList(3); +} + +enum IndexField_OneOfIndex { + index_, + notSet +} + +class IndexField extends $pb.GeneratedMessage { + static const $core.Map<$core.int, IndexField_OneOfIndex> _IndexField_OneOfIndexByTag = { + 2 : IndexField_OneOfIndex.index_, + 0 : IndexField_OneOfIndex.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'IndexField', createEmptyInstance: create) + ..oo(0, [2]) + ..aOM(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'field', subBuilder: Field.create) + ..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'index', $pb.PbFieldType.O3) + ..hasRequiredFields = false + ; + + IndexField._() : super(); + factory IndexField({ + Field? field_1, + $core.int? index, + }) { + final _result = create(); + if (field_1 != null) { + _result.field_1 = field_1; + } + if (index != null) { + _result.index = index; + } + return _result; + } + factory IndexField.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory IndexField.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') + IndexField clone() => IndexField()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + IndexField copyWith(void Function(IndexField) updates) => super.copyWith((message) => updates(message as IndexField)) as IndexField; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static IndexField create() => IndexField._(); + IndexField createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static IndexField getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static IndexField? _defaultInstance; + + IndexField_OneOfIndex whichOneOfIndex() => _IndexField_OneOfIndexByTag[$_whichOneof(0)]!; + void clearOneOfIndex() => clearField($_whichOneof(0)); + + @$pb.TagNumber(1) + Field get field_1 => $_getN(0); + @$pb.TagNumber(1) + set field_1(Field v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasField_1() => $_has(0); + @$pb.TagNumber(1) + void clearField_1() => clearField(1); + @$pb.TagNumber(1) + Field ensureField_1() => $_ensure(0); + + @$pb.TagNumber(2) + $core.int get index => $_getIZ(1); + @$pb.TagNumber(2) + set index($core.int v) { $_setSignedInt32(1, v); } + @$pb.TagNumber(2) + $core.bool hasIndex() => $_has(1); + @$pb.TagNumber(2) + void clearIndex() => clearField(2); +} + enum GetEditFieldContextPayload_OneOfFieldId { fieldId, notSet @@ -857,77 +1004,6 @@ class GridBlockOrder extends $pb.GeneratedMessage { $core.List get rowOrders => $_getList(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) - ..hasRequiredFields = false - ; - - GridRowsChangeset._() : super(); - factory GridRowsChangeset({ - $core.String? blockId, - $core.Iterable? insertedRows, - $core.Iterable? deletedRows, - $core.Iterable? updatedRows, - }) { - final _result = create(); - if (blockId != null) { - _result.blockId = blockId; - } - if (insertedRows != null) { - _result.insertedRows.addAll(insertedRows); - } - if (deletedRows != null) { - _result.deletedRows.addAll(deletedRows); - } - if (updatedRows != null) { - _result.updatedRows.addAll(updatedRows); - } - return _result; - } - factory GridRowsChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory GridRowsChangeset.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') - GridRowsChangeset clone() => GridRowsChangeset()..mergeFromMessage(this); - @$core.Deprecated( - 'Using this can add significant overhead to your binary. ' - 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' - 'Will be removed in next major version') - GridRowsChangeset copyWith(void Function(GridRowsChangeset) updates) => super.copyWith((message) => updates(message as GridRowsChangeset)) as GridRowsChangeset; // ignore: deprecated_member_use - $pb.BuilderInfo get info_ => _i; - @$core.pragma('dart2js:noInline') - static GridRowsChangeset create() => GridRowsChangeset._(); - GridRowsChangeset createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); - @$core.pragma('dart2js:noInline') - static GridRowsChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static GridRowsChangeset? _defaultInstance; - - @$pb.TagNumber(1) - $core.String get blockId => $_getSZ(0); - @$pb.TagNumber(1) - set blockId($core.String v) { $_setString(0, v); } - @$pb.TagNumber(1) - $core.bool hasBlockId() => $_has(0); - @$pb.TagNumber(1) - void clearBlockId() => clearField(1); - - @$pb.TagNumber(2) - $core.List get insertedRows => $_getList(1); - - @$pb.TagNumber(3) - $core.List get deletedRows => $_getList(2); - - @$pb.TagNumber(4) - $core.List get updatedRows => $_getList(3); -} - enum IndexRowOrder_OneOfIndex { index_, notSet @@ -1004,6 +1080,77 @@ class IndexRowOrder extends $pb.GeneratedMessage { void clearIndex() => clearField(2); } +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) + ..hasRequiredFields = false + ; + + GridRowsChangeset._() : super(); + factory GridRowsChangeset({ + $core.String? blockId, + $core.Iterable? insertedRows, + $core.Iterable? deletedRows, + $core.Iterable? updatedRows, + }) { + final _result = create(); + if (blockId != null) { + _result.blockId = blockId; + } + if (insertedRows != null) { + _result.insertedRows.addAll(insertedRows); + } + if (deletedRows != null) { + _result.deletedRows.addAll(deletedRows); + } + if (updatedRows != null) { + _result.updatedRows.addAll(updatedRows); + } + return _result; + } + factory GridRowsChangeset.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory GridRowsChangeset.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') + GridRowsChangeset clone() => GridRowsChangeset()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + GridRowsChangeset copyWith(void Function(GridRowsChangeset) updates) => super.copyWith((message) => updates(message as GridRowsChangeset)) as GridRowsChangeset; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static GridRowsChangeset create() => GridRowsChangeset._(); + GridRowsChangeset createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static GridRowsChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static GridRowsChangeset? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get blockId => $_getSZ(0); + @$pb.TagNumber(1) + set blockId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasBlockId() => $_has(0); + @$pb.TagNumber(1) + void clearBlockId() => clearField(1); + + @$pb.TagNumber(2) + $core.List get insertedRows => $_getList(1); + + @$pb.TagNumber(3) + $core.List get deletedRows => $_getList(2); + + @$pb.TagNumber(4) + $core.List get updatedRows => $_getList(3); +} + class GridBlock extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlock', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') 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 09cac1722c..a5d8fab78f 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 @@ -72,6 +72,33 @@ const FieldOrder$json = const { /// Descriptor for `FieldOrder`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List fieldOrderDescriptor = $convert.base64Decode('CgpGaWVsZE9yZGVyEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElk'); +@$core.Deprecated('Use gridFieldChangesetDescriptor instead') +const GridFieldChangeset$json = const { + '1': 'GridFieldChangeset', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'inserted_fields', '3': 2, '4': 3, '5': 11, '6': '.IndexField', '10': 'insertedFields'}, + const {'1': 'deleted_fields', '3': 3, '4': 3, '5': 11, '6': '.FieldOrder', '10': 'deletedFields'}, + const {'1': 'updated_fields', '3': 4, '4': 3, '5': 11, '6': '.Field', '10': 'updatedFields'}, + ], +}; + +/// Descriptor for `GridFieldChangeset`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridFieldChangesetDescriptor = $convert.base64Decode('ChJHcmlkRmllbGRDaGFuZ2VzZXQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEjQKD2luc2VydGVkX2ZpZWxkcxgCIAMoCzILLkluZGV4RmllbGRSDmluc2VydGVkRmllbGRzEjIKDmRlbGV0ZWRfZmllbGRzGAMgAygLMgsuRmllbGRPcmRlclINZGVsZXRlZEZpZWxkcxItCg51cGRhdGVkX2ZpZWxkcxgEIAMoCzIGLkZpZWxkUg11cGRhdGVkRmllbGRz'); +@$core.Deprecated('Use indexFieldDescriptor instead') +const IndexField$json = const { + '1': 'IndexField', + '2': const [ + const {'1': 'field', '3': 1, '4': 1, '5': 11, '6': '.Field', '10': 'field'}, + const {'1': 'index', '3': 2, '4': 1, '5': 5, '9': 0, '10': 'index'}, + ], + '8': const [ + const {'1': 'one_of_index'}, + ], +}; + +/// Descriptor for `IndexField`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List indexFieldDescriptor = $convert.base64Decode('CgpJbmRleEZpZWxkEhwKBWZpZWxkGAEgASgLMgYuRmllbGRSBWZpZWxkEhYKBWluZGV4GAIgASgFSABSBWluZGV4Qg4KDG9uZV9vZl9pbmRleA=='); @$core.Deprecated('Use getEditFieldContextPayloadDescriptor instead') const GetEditFieldContextPayload$json = const { '1': 'GetEditFieldContextPayload', @@ -197,19 +224,6 @@ const GridBlockOrder$json = const { /// Descriptor for `GridBlockOrder`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List gridBlockOrderDescriptor = $convert.base64Decode('Cg5HcmlkQmxvY2tPcmRlchIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIoCgpyb3dfb3JkZXJzGAIgAygLMgkuUm93T3JkZXJSCXJvd09yZGVycw=='); -@$core.Deprecated('Use gridRowsChangesetDescriptor instead') -const GridRowsChangeset$json = const { - '1': 'GridRowsChangeset', - '2': 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'}, - ], -}; - -/// Descriptor for `GridRowsChangeset`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List gridRowsChangesetDescriptor = $convert.base64Decode('ChFHcmlkUm93c0NoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIsCgx1cGRhdGVkX3Jvd3MYBCADKAsyCS5Sb3dPcmRlclILdXBkYXRlZFJvd3M='); @$core.Deprecated('Use indexRowOrderDescriptor instead') const IndexRowOrder$json = const { '1': 'IndexRowOrder', @@ -224,6 +238,19 @@ const IndexRowOrder$json = const { /// Descriptor for `IndexRowOrder`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List indexRowOrderDescriptor = $convert.base64Decode('Cg1JbmRleFJvd09yZGVyEiYKCXJvd19vcmRlchgBIAEoCzIJLlJvd09yZGVyUghyb3dPcmRlchIWCgVpbmRleBgCIAEoBUgAUgVpbmRleEIOCgxvbmVfb2ZfaW5kZXg='); +@$core.Deprecated('Use gridRowsChangesetDescriptor instead') +const GridRowsChangeset$json = const { + '1': 'GridRowsChangeset', + '2': 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'}, + ], +}; + +/// Descriptor for `GridRowsChangeset`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List gridRowsChangesetDescriptor = $convert.base64Decode('ChFHcmlkUm93c0NoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIsCgx1cGRhdGVkX3Jvd3MYBCADKAsyCS5Sb3dPcmRlclILdXBkYXRlZFJvd3M='); @$core.Deprecated('Use gridBlockDescriptor instead') const GridBlock$json = const { '1': 'GridBlock', 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 0eda4615bf..b5a35b10cd 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 @@ -76,7 +76,7 @@ impl GridBlockMetaEditorManager { index_row_order.index = row_index; let _ = self - .notify_did_update_grid_rows(GridRowsChangeset::insert(block_id, vec![index_row_order])) + .notify_did_update_rows(GridRowsChangeset::insert(block_id, vec![index_row_order])) .await?; Ok(row_count) } @@ -98,7 +98,7 @@ impl GridBlockMetaEditorManager { changesets.push(GridBlockMetaChangeset::from_row_count(&block_id, row_count)); let _ = self - .notify_did_update_grid_rows(GridRowsChangeset::insert(&block_id, inserted_row_orders)) + .notify_did_update_rows(GridRowsChangeset::insert(&block_id, inserted_row_orders)) .await?; } @@ -117,7 +117,7 @@ impl GridBlockMetaEditorManager { None => {} Some(row_order) => { let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]); - let _ = self.notify_did_update_grid_rows(block_order_changeset).await?; + let _ = self.notify_did_update_rows(block_order_changeset).await?; } } @@ -131,7 +131,7 @@ impl GridBlockMetaEditorManager { 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_grid_rows(GridRowsChangeset::delete(&block_id, row_orders)) + .notify_did_update_rows(GridRowsChangeset::delete(&block_id, row_orders)) .await?; Ok(()) @@ -213,7 +213,7 @@ impl GridBlockMetaEditorManager { Ok(block_cell_metas) } - async fn notify_did_update_grid_rows(&self, changeset: GridRowsChangeset) -> FlowyResult<()> { + async fn notify_did_update_rows(&self, changeset: GridRowsChangeset) -> FlowyResult<()> { send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridBlock) .payload(changeset) .send(); 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 f65179ebd3..8425097f69 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -151,7 +151,15 @@ impl ClientGridEditor { } pub async fn duplicate_field(&self, field_id: &str) -> FlowyResult<()> { - let _ = self.modify(|grid| Ok(grid.duplicate_field(field_id)?)).await?; + let mut duplicated_field_meta = None; + let _ = self + .modify(|grid| { + let (changeset, field_meta) = grid.duplicate_field(field_id)?; + duplicated_field_meta = field_meta; + Ok(changeset) + }) + .await?; + let _ = self.notify_did_update_grid().await?; Ok(()) } @@ -386,10 +394,12 @@ impl ClientGridEditor { } pub async fn move_field(&self, from: i32, to: i32, field_id: &str) -> FlowyResult<()> { + // GridFieldChangeset todo!() } pub async fn move_row(&self, from: i32, to: i32, row_id: &str) -> FlowyResult<()> { + // GridRowsChangeset todo!() } @@ -436,6 +446,8 @@ impl ClientGridEditor { } async fn notify_did_update_grid(&self) -> FlowyResult<()> { + // GridFieldChangeset + let field_metas = self.get_field_metas::(None).await?; let repeated_field: RepeatedField = field_metas.into_iter().map(Field::from).collect::>().into(); send_dart_notification(&self.grid_id, GridNotification::DidUpdateGrid) @@ -444,6 +456,13 @@ impl ClientGridEditor { Ok(()) } + async fn notify_did_update_grid2(&self, changeset: GridFieldChangeset) -> FlowyResult<()> { + send_dart_notification(&self.grid_id, GridNotification::DidUpdateGrid) + .payload(changeset) + .send(); + Ok(()) + } + #[tracing::instrument(level = "trace", skip_all, err)] async fn notify_did_update_field(&self, field_id: &str) -> FlowyResult<()> { let mut field_metas = self.get_field_metas(Some(vec![field_id])).await?; 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 0becd3d665..f090cfdc5e 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -84,6 +84,59 @@ impl std::convert::From for FieldOrder { } } +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct GridFieldChangeset { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub inserted_fields: Vec, + + #[pb(index = 3)] + pub deleted_fields: Vec, + + #[pb(index = 4)] + pub updated_fields: Vec, +} + +impl GridFieldChangeset { + pub fn insert(grid_id: &str, inserted_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_owned(), + inserted_fields, + deleted_fields: vec![], + updated_fields: vec![], + } + } + + pub fn delete(grid_id: &str, deleted_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_string(), + inserted_fields: vec![], + deleted_fields, + updated_fields: vec![], + } + } + + pub fn update(grid_id: &str, updated_fields: Vec) -> Self { + Self { + grid_id: grid_id.to_string(), + inserted_fields: vec![], + deleted_fields: vec![], + updated_fields, + } + } +} + +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct IndexField { + #[pb(index = 1)] + pub field: Field, + + #[pb(index = 2, one_of)] + pub index: Option, +} + #[derive(Debug, Default, ProtoBuf)] pub struct GetEditFieldContextPayload { #[pb(index = 1)] @@ -277,6 +330,15 @@ impl GridBlockOrder { } } +#[derive(Debug, Clone, Default, ProtoBuf)] +pub struct IndexRowOrder { + #[pb(index = 1)] + pub row_order: RowOrder, + + #[pb(index = 2, one_of)] + pub index: Option, +} + #[derive(Debug, Clone, Default, ProtoBuf)] pub struct GridRowsChangeset { #[pb(index = 1)] @@ -292,15 +354,6 @@ pub struct GridRowsChangeset { pub updated_rows: Vec, } -#[derive(Debug, Clone, Default, ProtoBuf)] -pub struct IndexRowOrder { - #[pb(index = 1)] - pub row_order: RowOrder, - - #[pb(index = 2, one_of)] - pub index: Option, -} - impl std::convert::From for IndexRowOrder { fn from(row_order: RowOrder) -> Self { Self { row_order, index: None } 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 15e85282f8..46de6cf971 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 @@ -818,6 +818,544 @@ impl ::protobuf::reflect::ProtobufValue for FieldOrder { } } +#[derive(PartialEq,Clone,Default)] +pub struct GridFieldChangeset { + // message fields + pub grid_id: ::std::string::String, + pub inserted_fields: ::protobuf::RepeatedField, + pub deleted_fields: ::protobuf::RepeatedField, + pub updated_fields: ::protobuf::RepeatedField, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a GridFieldChangeset { + fn default() -> &'a GridFieldChangeset { + ::default_instance() + } +} + +impl GridFieldChangeset { + pub fn new() -> GridFieldChangeset { + ::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()) + } + + // repeated .IndexField inserted_fields = 2; + + + pub fn get_inserted_fields(&self) -> &[IndexField] { + &self.inserted_fields + } + pub fn clear_inserted_fields(&mut self) { + self.inserted_fields.clear(); + } + + // Param is passed by value, moved + pub fn set_inserted_fields(&mut self, v: ::protobuf::RepeatedField) { + self.inserted_fields = v; + } + + // Mutable pointer to the field. + pub fn mut_inserted_fields(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.inserted_fields + } + + // Take field + pub fn take_inserted_fields(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.inserted_fields, ::protobuf::RepeatedField::new()) + } + + // repeated .FieldOrder deleted_fields = 3; + + + pub fn get_deleted_fields(&self) -> &[FieldOrder] { + &self.deleted_fields + } + pub fn clear_deleted_fields(&mut self) { + self.deleted_fields.clear(); + } + + // Param is passed by value, moved + pub fn set_deleted_fields(&mut self, v: ::protobuf::RepeatedField) { + self.deleted_fields = v; + } + + // Mutable pointer to the field. + pub fn mut_deleted_fields(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.deleted_fields + } + + // Take field + pub fn take_deleted_fields(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.deleted_fields, ::protobuf::RepeatedField::new()) + } + + // repeated .Field updated_fields = 4; + + + pub fn get_updated_fields(&self) -> &[Field] { + &self.updated_fields + } + pub fn clear_updated_fields(&mut self) { + self.updated_fields.clear(); + } + + // Param is passed by value, moved + pub fn set_updated_fields(&mut self, v: ::protobuf::RepeatedField) { + self.updated_fields = v; + } + + // Mutable pointer to the field. + pub fn mut_updated_fields(&mut self) -> &mut ::protobuf::RepeatedField { + &mut self.updated_fields + } + + // Take field + pub fn take_updated_fields(&mut self) -> ::protobuf::RepeatedField { + ::std::mem::replace(&mut self.updated_fields, ::protobuf::RepeatedField::new()) + } +} + +impl ::protobuf::Message for GridFieldChangeset { + fn is_initialized(&self) -> bool { + for v in &self.inserted_fields { + if !v.is_initialized() { + return false; + } + }; + for v in &self.deleted_fields { + if !v.is_initialized() { + return false; + } + }; + for v in &self.updated_fields { + 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_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.inserted_fields)?; + }, + 3 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.deleted_fields)?; + }, + 4 => { + ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.updated_fields)?; + }, + _ => { + ::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); + } + for value in &self.inserted_fields { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.deleted_fields { + let len = value.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + }; + for value in &self.updated_fields { + let len = value.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 !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + for v in &self.inserted_fields { + os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.deleted_fields { + os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?; + os.write_raw_varint32(v.get_cached_size())?; + v.write_to_with_cached_sizes(os)?; + }; + for v in &self.updated_fields { + os.write_tag(4, ::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() -> GridFieldChangeset { + GridFieldChangeset::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: &GridFieldChangeset| { &m.grid_id }, + |m: &mut GridFieldChangeset| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "inserted_fields", + |m: &GridFieldChangeset| { &m.inserted_fields }, + |m: &mut GridFieldChangeset| { &mut m.inserted_fields }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "deleted_fields", + |m: &GridFieldChangeset| { &m.deleted_fields }, + |m: &mut GridFieldChangeset| { &mut m.deleted_fields }, + )); + fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "updated_fields", + |m: &GridFieldChangeset| { &m.updated_fields }, + |m: &mut GridFieldChangeset| { &mut m.updated_fields }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "GridFieldChangeset", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static GridFieldChangeset { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(GridFieldChangeset::new) + } +} + +impl ::protobuf::Clear for GridFieldChangeset { + fn clear(&mut self) { + self.grid_id.clear(); + self.inserted_fields.clear(); + self.deleted_fields.clear(); + self.updated_fields.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for GridFieldChangeset { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for GridFieldChangeset { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + +#[derive(PartialEq,Clone,Default)] +pub struct IndexField { + // message fields + pub field: ::protobuf::SingularPtrField, + // message oneof groups + pub one_of_index: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a IndexField { + fn default() -> &'a IndexField { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum IndexField_oneof_one_of_index { + index(i32), +} + +impl IndexField { + pub fn new() -> IndexField { + ::std::default::Default::default() + } + + // .Field field = 1; + + + pub fn get_field(&self) -> &Field { + self.field.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_field(&mut self) { + self.field.clear(); + } + + pub fn has_field(&self) -> bool { + self.field.is_some() + } + + // Param is passed by value, moved + pub fn set_field(&mut self, v: Field) { + self.field = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field(&mut self) -> &mut Field { + if self.field.is_none() { + self.field.set_default(); + } + self.field.as_mut().unwrap() + } + + // Take field + pub fn take_field(&mut self) -> Field { + self.field.take().unwrap_or_else(|| Field::new()) + } + + // int32 index = 2; + + + pub fn get_index(&self) -> i32 { + match self.one_of_index { + ::std::option::Option::Some(IndexField_oneof_one_of_index::index(v)) => v, + _ => 0, + } + } + pub fn clear_index(&mut self) { + self.one_of_index = ::std::option::Option::None; + } + + pub fn has_index(&self) -> bool { + match self.one_of_index { + ::std::option::Option::Some(IndexField_oneof_one_of_index::index(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_index(&mut self, v: i32) { + self.one_of_index = ::std::option::Option::Some(IndexField_oneof_one_of_index::index(v)) + } +} + +impl ::protobuf::Message for IndexField { + fn is_initialized(&self) -> bool { + for v in &self.field { + 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.field)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_index = ::std::option::Option::Some(IndexField_oneof_one_of_index::index(is.read_int32()?)); + }, + _ => { + ::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.field.as_ref() { + let len = v.compute_size(); + my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; + } + if let ::std::option::Option::Some(ref v) = self.one_of_index { + match v { + &IndexField_oneof_one_of_index::index(v) => { + my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); + }, + }; + } + 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.field.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 ::std::option::Option::Some(ref v) = self.one_of_index { + match v { + &IndexField_oneof_one_of_index::index(v) => { + os.write_int32(2, 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() -> IndexField { + IndexField::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>( + "field", + |m: &IndexField| { &m.field }, + |m: &mut IndexField| { &mut m.field }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_i32_accessor::<_>( + "index", + IndexField::has_index, + IndexField::get_index, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "IndexField", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static IndexField { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(IndexField::new) + } +} + +impl ::protobuf::Clear for IndexField { + fn clear(&mut self) { + self.field.clear(); + self.one_of_index = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for IndexField { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for IndexField { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct GetEditFieldContextPayload { // message fields @@ -2919,6 +3457,238 @@ impl ::protobuf::reflect::ProtobufValue for GridBlockOrder { } } +#[derive(PartialEq,Clone,Default)] +pub struct IndexRowOrder { + // message fields + pub row_order: ::protobuf::SingularPtrField, + // message oneof groups + pub one_of_index: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a IndexRowOrder { + fn default() -> &'a IndexRowOrder { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum IndexRowOrder_oneof_one_of_index { + index(i32), +} + +impl IndexRowOrder { + pub fn new() -> IndexRowOrder { + ::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()) + } + + // int32 index = 2; + + + pub fn get_index(&self) -> i32 { + match self.one_of_index { + ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(v)) => v, + _ => 0, + } + } + pub fn clear_index(&mut self) { + self.one_of_index = ::std::option::Option::None; + } + + pub fn has_index(&self) -> bool { + match self.one_of_index { + ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_index(&mut self, v: i32) { + self.one_of_index = ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(v)) + } +} + +impl ::protobuf::Message for IndexRowOrder { + fn is_initialized(&self) -> bool { + for v in &self.row_order { + 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 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_index = ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(is.read_int32()?)); + }, + _ => { + ::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 ::std::option::Option::Some(ref v) = self.one_of_index { + match v { + &IndexRowOrder_oneof_one_of_index::index(v) => { + my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); + }, + }; + } + 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 ::std::option::Option::Some(ref v) = self.one_of_index { + match v { + &IndexRowOrder_oneof_one_of_index::index(v) => { + os.write_int32(2, 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() -> IndexRowOrder { + IndexRowOrder::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: &IndexRowOrder| { &m.row_order }, + |m: &mut IndexRowOrder| { &mut m.row_order }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_i32_accessor::<_>( + "index", + IndexRowOrder::has_index, + IndexRowOrder::get_index, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "IndexRowOrder", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static IndexRowOrder { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(IndexRowOrder::new) + } +} + +impl ::protobuf::Clear for IndexRowOrder { + fn clear(&mut self) { + self.row_order.clear(); + self.one_of_index = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for IndexRowOrder { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for IndexRowOrder { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct GridRowsChangeset { // message fields @@ -3225,238 +3995,6 @@ impl ::protobuf::reflect::ProtobufValue for GridRowsChangeset { } } -#[derive(PartialEq,Clone,Default)] -pub struct IndexRowOrder { - // message fields - pub row_order: ::protobuf::SingularPtrField, - // message oneof groups - pub one_of_index: ::std::option::Option, - // special fields - pub unknown_fields: ::protobuf::UnknownFields, - pub cached_size: ::protobuf::CachedSize, -} - -impl<'a> ::std::default::Default for &'a IndexRowOrder { - fn default() -> &'a IndexRowOrder { - ::default_instance() - } -} - -#[derive(Clone,PartialEq,Debug)] -pub enum IndexRowOrder_oneof_one_of_index { - index(i32), -} - -impl IndexRowOrder { - pub fn new() -> IndexRowOrder { - ::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()) - } - - // int32 index = 2; - - - pub fn get_index(&self) -> i32 { - match self.one_of_index { - ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(v)) => v, - _ => 0, - } - } - pub fn clear_index(&mut self) { - self.one_of_index = ::std::option::Option::None; - } - - pub fn has_index(&self) -> bool { - match self.one_of_index { - ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(..)) => true, - _ => false, - } - } - - // Param is passed by value, moved - pub fn set_index(&mut self, v: i32) { - self.one_of_index = ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(v)) - } -} - -impl ::protobuf::Message for IndexRowOrder { - fn is_initialized(&self) -> bool { - for v in &self.row_order { - 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 => { - if wire_type != ::protobuf::wire_format::WireTypeVarint { - return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); - } - self.one_of_index = ::std::option::Option::Some(IndexRowOrder_oneof_one_of_index::index(is.read_int32()?)); - }, - _ => { - ::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 ::std::option::Option::Some(ref v) = self.one_of_index { - match v { - &IndexRowOrder_oneof_one_of_index::index(v) => { - my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); - }, - }; - } - 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 ::std::option::Option::Some(ref v) = self.one_of_index { - match v { - &IndexRowOrder_oneof_one_of_index::index(v) => { - os.write_int32(2, 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() -> IndexRowOrder { - IndexRowOrder::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: &IndexRowOrder| { &m.row_order }, - |m: &mut IndexRowOrder| { &mut m.row_order }, - )); - fields.push(::protobuf::reflect::accessor::make_singular_i32_accessor::<_>( - "index", - IndexRowOrder::has_index, - IndexRowOrder::get_index, - )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "IndexRowOrder", - fields, - file_descriptor_proto() - ) - }) - } - - fn default_instance() -> &'static IndexRowOrder { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(IndexRowOrder::new) - } -} - -impl ::protobuf::Clear for IndexRowOrder { - fn clear(&mut self) { - self.row_order.clear(); - self.one_of_index = ::std::option::Option::None; - self.unknown_fields.clear(); - } -} - -impl ::std::fmt::Debug for IndexRowOrder { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - ::protobuf::text_format::fmt(self, f) - } -} - -impl ::protobuf::reflect::ProtobufValue for IndexRowOrder { - fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { - ::protobuf::reflect::ReflectValueRef::Message(self) - } -} - #[derive(PartialEq,Clone,Default)] pub struct GridBlock { // message fields @@ -7261,81 +7799,87 @@ static file_descriptor_proto_data: &'static [u8] = b"\ FieldTypeR\tfieldType\x12\x16\n\x06frozen\x18\x05\x20\x01(\x08R\x06froze\ n\x12\x1e\n\nvisibility\x18\x06\x20\x01(\x08R\nvisibility\x12\x14\n\x05w\ idth\x18\x07\x20\x01(\x05R\x05width\"'\n\nFieldOrder\x12\x19\n\x08field_\ - id\x18\x01\x20\x01(\tR\x07fieldId\"\x90\x01\n\x1aGetEditFieldContextPayl\ - oad\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1b\n\x08fiel\ - d_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\n\nfield_type\x18\x03\x20\ - \x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field_id\"q\n\x10Edi\ - tFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\ - \n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12)\n\nfield_type\x18\x03\ - \x20\x01(\x0e2\n.FieldTypeR\tfieldType\"|\n\x10EditFieldContext\x12\x17\ - \n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngrid_field\x18\x02\ - \x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\x10type_option_data\x18\x03\ - \x20\x01(\x0cR\x0etypeOptionData\"-\n\rRepeatedField\x12\x1c\n\x05items\ - \x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12RepeatedFieldOrder\ - \x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05items\"T\n\x08\ - RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\x12\x19\n\x08b\ - lock_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06height\x18\x03\x20\ - \x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\ - \tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\x17.Row.CellB\ - yFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\ - \x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01\ - (\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\ - \x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\ - \x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05items\x18\x01\ - \x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\x12\x19\n\ - \x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\x18\x02\ - \x20\x03(\x0b2\t.RowOrderR\trowOrders\"\xbf\x01\n\x11GridRowsChangeset\ - \x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x123\n\rinserted_r\ - ows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cinsertedRows\x12,\n\x0cd\ - eleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bdeletedRows\x12,\n\x0cu\ - pdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0bupdatedRows\"_\n\rIndex\ - RowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\ - \x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_i\ - ndex\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nr\ - ow_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\"\x8f\x01\n\x14CellNotificationData\x12\ - \x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\ - \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\ + id\x18\x01\x20\x01(\tR\x07fieldId\"\xc6\x01\n\x12GridFieldChangeset\x12\ + \x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x124\n\x0finserted_field\ + s\x18\x02\x20\x03(\x0b2\x0b.IndexFieldR\x0einsertedFields\x122\n\x0edele\ + ted_fields\x18\x03\x20\x03(\x0b2\x0b.FieldOrderR\rdeletedFields\x12-\n\ + \x0eupdated_fields\x18\x04\x20\x03(\x0b2\x06.FieldR\rupdatedFields\"R\n\ + \nIndexField\x12\x1c\n\x05field\x18\x01\x20\x01(\x0b2\x06.FieldR\x05fiel\ + d\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_\ + index\"\x90\x01\n\x1aGetEditFieldContextPayload\x12\x17\n\x07grid_id\x18\ + \x01\x20\x01(\tR\x06gridId\x12\x1b\n\x08field_id\x18\x02\x20\x01(\tH\0R\ + \x07fieldId\x12)\n\nfield_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfield\ + TypeB\x11\n\x0fone_of_field_id\"q\n\x10EditFieldPayload\x12\x17\n\x07gri\ + d_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01\ + (\tR\x07fieldId\x12)\n\nfield_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tf\ + ieldType\"|\n\x10EditFieldContext\x12\x17\n\x07grid_id\x18\x01\x20\x01(\ + \tR\x06gridId\x12%\n\ngrid_field\x18\x02\x20\x01(\x0b2\x06.FieldR\tgridF\ + ield\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\ + \"-\n\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\ + \x05items\"7\n\x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\ + \x0b2\x0b.FieldOrderR\x05items\"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\ + \x01\x20\x01(\tR\x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07b\ + lockId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\ + \x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_fiel\ + d_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\rcellByFieldId\ + \x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\n\x12CellByFie\ + ldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\ + \x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\ + \x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11Repe\ + atedGridBlock\x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05i\ + tems\"U\n\x0eGridBlockOrder\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\ + \x07blockId\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrd\ + ers\"_\n\rIndexRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrd\ + erR\x08rowOrder\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\ + \x0e\n\x0cone_of_index\"\xbf\x01\n\x11GridRowsChangeset\x12\x19\n\x08blo\ + ck_id\x18\x01\x20\x01(\tR\x07blockId\x123\n\rinserted_rows\x18\x02\x20\ + \x03(\x0b2\x0e.IndexRowOrderR\x0cinsertedRows\x12,\n\x0cdeleted_rows\x18\ + \x03\x20\x03(\x0b2\t.RowOrderR\x0bdeletedRows\x12,\n\x0cupdated_rows\x18\ + \x04\x20\x03(\x0b2\t.RowOrderR\x0bupdatedRows\"E\n\tGridBlock\x12\x0e\n\ + \x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b\ + 2\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\ + \"\x8f\x01\n\x14CellNotificationData\x12\x17\n\x07grid_id\x18\x01\x20\ + \x01(\tR\x06gridId\x12\x19\n\x08field_id\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\x0cRepe\ + atedCell\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\ + \n\x11CreateGridPayload\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\x10\ + CreateRowPayload\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(\tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.\ + FieldR\x05field\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etype\ + OptionData\x12&\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartField\ + IdB\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\x16QueryGridB\ + locksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\ + \x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrder\ + s\"\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\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\nvisibi\ + lity\x12\x16\n\x05width\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10ty\ + pe_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_fro\ + zenB\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\x06i\ + temId\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\x06gridId\x12\x15\n\x06row_id\x18\x02\ + \x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07field\ + Id\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\x08DateTime\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 eca5a5f0ea..acf01a229c 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 @@ -17,6 +17,16 @@ message Field { message FieldOrder { string field_id = 1; } +message GridFieldChangeset { + string grid_id = 1; + repeated IndexField inserted_fields = 2; + repeated FieldOrder deleted_fields = 3; + repeated Field updated_fields = 4; +} +message IndexField { + Field field = 1; + oneof one_of_index { int32 index = 2; }; +} message GetEditFieldContextPayload { string grid_id = 1; oneof one_of_field_id { string field_id = 2; }; @@ -58,16 +68,16 @@ message GridBlockOrder { string block_id = 1; repeated RowOrder row_orders = 2; } +message IndexRowOrder { + RowOrder row_order = 1; + oneof one_of_index { int32 index = 2; }; +} message GridRowsChangeset { string block_id = 1; repeated IndexRowOrder inserted_rows = 2; repeated RowOrder deleted_rows = 3; repeated RowOrder updated_rows = 4; } -message IndexRowOrder { - RowOrder row_order = 1; - oneof one_of_index { int32 index = 2; }; -} message GridBlock { string id = 1; repeated RowOrder row_orders = 2; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index dc67e79d33..e39798a33a 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -82,19 +82,23 @@ impl GridMetaPad { ) } - pub fn duplicate_field(&mut self, field_id: &str) -> CollaborateResult> { - self.modify_grid( - |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { - None => Ok(None), - Some(index) => { - let mut duplicate_field_meta = grid_meta.fields[index].clone(); - duplicate_field_meta.id = gen_field_id(); - duplicate_field_meta.name = format!("{} (copy)", duplicate_field_meta.name); - grid_meta.fields.insert(index + 1, duplicate_field_meta); - Ok(Some(())) - } - }, - ) + pub fn duplicate_field(&mut self, field_id: &str) -> CollaborateResult<(Option, Option)> { + let mut field_meta = None; + let changeset = + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { + None => Ok(None), + Some(index) => { + let mut duplicate_field_meta = grid_meta.fields[index].clone(); + duplicate_field_meta.id = gen_field_id(); + duplicate_field_meta.name = format!("{} (copy)", duplicate_field_meta.name); + field_meta = Some(duplicate_field_meta.clone()); + grid_meta.fields.insert(index + 1, duplicate_field_meta); + Ok(Some(())) + } + }, + )?; + Ok((changeset, field_meta)) } pub fn switch_to_field( From fd9e13bf4b19c41e99768ff1b63975cbb3c7eb70 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 14 Apr 2022 13:29:42 +0800 Subject: [PATCH 06/26] chore: refactor grid field listener --- .../app_flowy/lib/startup/deps_resolver.dart | 11 +- .../lib/startup/tasks/app_widget.dart | 10 +- .../grid/cell_bloc/date_cell_bloc.dart | 4 +- .../grid/cell_bloc/number_cell_bloc.dart | 4 +- .../grid/cell_bloc/selection_cell_bloc.dart | 4 +- .../grid/cell_bloc/selection_editor_bloc.dart | 4 +- .../grid/field/field_cell_bloc.dart | 4 +- .../grid/field/field_listener.dart | 4 +- .../application/grid/field/grid_listenr.dart | 4 +- .../workspace/application/grid/grid_bloc.dart | 120 +++-------- .../application/grid/grid_header_bloc.dart | 76 +++++++ .../application/grid/grid_service.dart | 176 +++++++++++++++ .../workspace/application/grid/prelude.dart | 1 + .../application/grid/row/row_bloc.dart | 21 +- .../grid/setting/property_bloc.dart | 2 +- .../plugins/grid/src/grid_page.dart | 24 ++- .../grid/src/widgets/header/grid_header.dart | 84 ++++++-- .../grid/src/widgets/row/grid_row.dart | 5 +- .../flowy-grid-data-model/grid.pb.dart | 13 -- .../flowy-grid-data-model/grid.pbjson.dart | 7 +- .../src/services/folder_editor.rs | 28 +-- .../flowy-grid/src/services/grid_editor.rs | 112 +++++----- .../src/entities/grid.rs | 13 +- .../src/protobuf/model/grid.rs | 203 ++++++++---------- .../src/protobuf/proto/grid.proto | 2 +- .../src/client_grid/grid_meta_pad.rs | 53 ++--- 26 files changed, 609 insertions(+), 380 deletions(-) create mode 100644 frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 5c835ce217..cb685cd7b2 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -150,9 +150,16 @@ void _resolveGridDeps(GetIt getIt) { (view, _) => GridBloc(view: view), ); - getIt.registerFactoryParam( - (data, _) => RowBloc( + getIt.registerFactoryParam( + (data, fieldCache) => RowBloc( rowData: data, + fieldCache: fieldCache, + ), + ); + + getIt.registerFactoryParam>( + (gridId, fields) => GridHeaderBloc( + data: GridHeaderData(gridId: gridId, fields: fields), ), ); diff --git a/frontend/app_flowy/lib/startup/tasks/app_widget.dart b/frontend/app_flowy/lib/startup/tasks/app_widget.dart index 12e88949a0..1747cfd8ec 100644 --- a/frontend/app_flowy/lib/startup/tasks/app_widget.dart +++ b/frontend/app_flowy/lib/startup/tasks/app_widget.dart @@ -123,9 +123,9 @@ class ApplicationBlocObserver extends BlocObserver { super.onError(bloc, error, stackTrace); } - @override - void onEvent(Bloc bloc, Object? event) { - Log.debug("$event"); - super.onEvent(bloc, event); - } + // @override + // void onEvent(Bloc bloc, Object? event) { + // Log.debug("$event"); + // super.onEvent(bloc, event); + // } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart index ff8d7d012e..f235b47e4a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart @@ -13,12 +13,12 @@ part 'date_cell_bloc.freezed.dart'; class DateCellBloc extends Bloc { final CellService _service; final CellListener _cellListener; - final FieldListener _fieldListener; + final SingleFieldListener _fieldListener; DateCellBloc({required CellData cellData}) : _service = CellService(), _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - _fieldListener = FieldListener(fieldId: cellData.field.id), + _fieldListener = SingleFieldListener(fieldId: cellData.field.id), super(DateCellState.initial(cellData)) { on( (event, emit) async { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart index e61e8f96a6..a145305bbe 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart @@ -13,13 +13,13 @@ part 'number_cell_bloc.freezed.dart'; class NumberCellBloc extends Bloc { final CellService _service; final CellListener _cellListener; - final FieldListener _fieldListener; + final SingleFieldListener _fieldListener; NumberCellBloc({ required CellData cellData, }) : _service = CellService(), _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - _fieldListener = FieldListener(fieldId: cellData.field.id), + _fieldListener = SingleFieldListener(fieldId: cellData.field.id), super(NumberCellState.initial(cellData)) { on( (event, emit) async { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart index d77280085e..b7e472e181 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart @@ -13,13 +13,13 @@ part 'selection_cell_bloc.freezed.dart'; class SelectionCellBloc extends Bloc { final SelectOptionService _service; final CellListener _cellListener; - final FieldListener _fieldListener; + final SingleFieldListener _fieldListener; SelectionCellBloc({ required CellData cellData, }) : _service = SelectOptionService(), _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - _fieldListener = FieldListener(fieldId: cellData.field.id), + _fieldListener = SingleFieldListener(fieldId: cellData.field.id), super(SelectionCellState.initial(cellData)) { on( (event, emit) async { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart index 5b6ba78bd5..59510298a7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart @@ -13,7 +13,7 @@ part 'selection_editor_bloc.freezed.dart'; class SelectOptionEditorBloc extends Bloc { final SelectOptionService _selectOptionService; - final FieldListener _fieldListener; + final SingleFieldListener _fieldListener; final CellListener _cellListener; Timer? _delayOperation; @@ -22,7 +22,7 @@ class SelectOptionEditorBloc extends Bloc options, required List selectedOptions, }) : _selectOptionService = SelectOptionService(), - _fieldListener = FieldListener(fieldId: cellData.field.id), + _fieldListener = SingleFieldListener(fieldId: cellData.field.id), _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), super(SelectOptionEditorState.initial(cellData, options, selectedOptions)) { on( 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 376b98f19a..026be9a780 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 @@ -9,12 +9,12 @@ import 'dart:async'; part 'field_cell_bloc.freezed.dart'; class FieldCellBloc extends Bloc { - final FieldListener _fieldListener; + final SingleFieldListener _fieldListener; final FieldService _fieldService; FieldCellBloc({ required GridFieldCellContext cellContext, - }) : _fieldListener = FieldListener(fieldId: cellContext.field.id), + }) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id), _fieldService = FieldService(gridId: cellContext.gridId), super(FieldCellState.initial(cellContext)) { on( 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 ed09ca9b82..450d88fe18 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 @@ -9,12 +9,12 @@ import 'package:app_flowy/core/notification_helper.dart'; typedef UpdateFieldNotifiedValue = Either; -class FieldListener { +class SingleFieldListener { final String fieldId; PublishNotifier updateFieldNotifier = PublishNotifier(); GridNotificationListener? _listener; - FieldListener({required this.fieldId}); + SingleFieldListener({required this.fieldId}); void start() { _listener = GridNotificationListener( 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 434b343d8d..d823207f83 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/grid_listenr.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:app_flowy/core/notification_helper.dart'; -typedef UpdateFieldNotifiedValue = Either, FlowyError>; +typedef UpdateFieldNotifiedValue = Either; class GridFieldsListener { final String gridId; @@ -26,7 +26,7 @@ class GridFieldsListener { switch (ty) { case GridNotification.DidUpdateGrid: result.fold( - (payload) => updateFieldsNotifier.value = left(RepeatedField.fromBuffer(payload).items), + (payload) => updateFieldsNotifier.value = left(GridFieldChangeset.fromBuffer(payload)), (error) => updateFieldsNotifier.value = right(error), ); break; 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 30cb7c9a29..abdf73acbc 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -17,18 +17,22 @@ class GridBloc extends Bloc { final GridService _gridService; final GridListener _gridListener; final GridFieldsListener _fieldListener; + final GridFieldCache fieldCache; + final GridRowCache _rowCache; GridBloc({required View view}) : _fieldListener = GridFieldsListener(gridId: view.id), _gridService = GridService(gridId: view.id), _gridListener = GridListener(gridId: view.id), + fieldCache = GridFieldCache(), + _rowCache = GridRowCache(gridId: view.id), super(GridState.initial(view.id)) { on( (event, emit) async { await event.map( initial: (InitialGrid value) async { - await _initGrid(emit); _startListening(); + await _loadGrid(emit); }, createRow: (_CreateRow value) { _gridService.createRow(); @@ -37,11 +41,9 @@ class GridBloc extends Bloc { emit(state.copyWith(rows: value.rows, listState: value.listState)); }, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - final rows = state.rows.map((row) => row.copyWith(fields: value.fields)).toList(); emit(state.copyWith( - rows: rows, + rows: _rowCache.rows, fields: value.fields, - listState: const GridListState.reload(), )); }, ); @@ -57,35 +59,39 @@ class GridBloc extends Bloc { return super.close(); } - Future _initGrid(Emitter emit) async { + void _startListening() { + fieldCache.addListener((fields) { + _rowCache.updateFields(fields); + }); + _fieldListener.updateFieldsNotifier.addPublishListener((result) { result.fold( - (fields) => add(GridEvent.didReceiveFieldUpdate(fields)), + (changeset) { + fieldCache.applyChangeset(changeset); + add(GridEvent.didReceiveFieldUpdate(List.from(fieldCache.fields))); + }, (err) => Log.error(err), ); }); _fieldListener.start(); - await _loadGrid(emit); - } - - void _startListening() { _gridListener.rowsUpdateNotifier.addPublishListener((result) { - result.fold((gridBlockChangeset) { - for (final changeset in gridBlockChangeset) { - if (changeset.insertedRows.isNotEmpty) { - _insertRows(changeset.insertedRows); - } + result.fold( + (changesets) { + for (final changeset in changesets) { + _rowCache + .deleteRows(changeset.deletedRows) + .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(_rowCache.rows, listState))); - if (changeset.deletedRows.isNotEmpty) { - _deleteRows(changeset.deletedRows); - } + _rowCache + .insertRows(changeset.insertedRows) + .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(_rowCache.rows, listState))); - if (changeset.updatedRows.isNotEmpty) { - _updateRows(changeset.updatedRows); + _rowCache.updateRows(changeset.updatedRows); } - } - }, (err) => Log.error(err)); + }, + (err) => Log.error(err), + ); }); _gridListener.start(); } @@ -105,10 +111,13 @@ class GridBloc extends Bloc { return Future( () => result.fold( (fields) { + fieldCache.fields = fields.items; + _rowCache.updateWithBlock(grid.blockOrders); + emit(state.copyWith( grid: Some(grid), - fields: fields.items, - rows: _buildRows(grid.blockOrders, fields.items), + fields: fieldCache.fields, + rows: _rowCache.rows, loadingState: GridLoadingState.finish(left(unit)), )); }, @@ -116,60 +125,6 @@ class GridBloc extends Bloc { ), ); } - - void _deleteRows(List deletedRows) { - final List rows = []; - final List> deletedIndex = []; - final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; - state.rows.asMap().forEach((index, value) { - if (deletedRowMap[value.rowId] == null) { - rows.add(value); - } else { - deletedIndex.add(Tuple2(index, value)); - } - }); - - add(GridEvent.didReceiveRowUpdate(rows, GridListState.delete(deletedIndex))); - } - - void _insertRows(List createdRows) { - final List rows = List.from(state.rows); - List insertIndexs = []; - for (final newRow in createdRows) { - if (newRow.hasIndex()) { - insertIndexs.add(newRow.index); - rows.insert(newRow.index, _toRowData(newRow.rowOrder)); - } else { - insertIndexs.add(rows.length); - rows.add(_toRowData(newRow.rowOrder)); - } - } - add(GridEvent.didReceiveRowUpdate(rows, GridListState.insert(insertIndexs))); - } - - void _updateRows(List updatedRows) { - final List rows = List.from(state.rows); - final List updatedIndexs = []; - for (final updatedRow in updatedRows) { - final index = rows.indexWhere((row) => row.rowId == updatedRow.rowId); - if (index != -1) { - rows.removeAt(index); - rows.insert(index, _toRowData(updatedRow)); - updatedIndexs.add(index); - } - } - add(GridEvent.didReceiveRowUpdate(rows, const GridListState.reload())); - } - - List _buildRows(List blockOrders, List fields) { - return blockOrders.expand((blockOrder) => blockOrder.rowOrders).map((rowOrder) { - return RowData.fromBlockRow(state.gridId, rowOrder, fields); - }).toList(); - } - - RowData _toRowData(RowOrder rowOrder) { - return RowData.fromBlockRow(state.gridId, rowOrder, state.fields); - } } @freezed @@ -197,7 +152,7 @@ class GridState with _$GridState { grid: none(), gridId: gridId, loadingState: const _Loading(), - listState: const _Reload(), + listState: const InitialListState(), ); } @@ -206,10 +161,3 @@ class GridLoadingState with _$GridLoadingState { const factory GridLoadingState.loading() = _Loading; const factory GridLoadingState.finish(Either successOrFail) = _Finish; } - -@freezed -class GridListState with _$GridListState { - const factory GridListState.insert(List indexs) = _Insert; - const factory GridListState.delete(List> indexs) = _Delete; - const factory GridListState.reload() = _Reload; -} diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart new file mode 100644 index 0000000000..18086ce6d9 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -0,0 +1,76 @@ +import 'package:app_flowy/workspace/application/grid/data.dart'; +import 'package:app_flowy/workspace/application/grid/field/grid_listenr.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'; +import 'dart:async'; +import 'field/field_service.dart'; +import 'grid_service.dart'; + +part 'grid_header_bloc.freezed.dart'; + +class GridHeaderBloc extends Bloc { + final FieldService _fieldService; + final GridFieldCache _fieldCache; + final GridFieldsListener _fieldListener; + + GridHeaderBloc({ + required GridHeaderData data, + }) : _fieldListener = GridFieldsListener(gridId: data.gridId), + _fieldService = FieldService(gridId: data.gridId), + _fieldCache = GridFieldCache(), + super(GridHeaderState.initial(data.fields)) { + _fieldCache.fields = data.fields; + + on( + (event, emit) async { + await event.map( + initial: (_InitialHeader value) async { + _startListening(); + }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + value.fields.retainWhere((field) => field.visibility); + emit(state.copyWith(fields: value.fields)); + }, + ); + }, + ); + } + + Future _startListening() async { + _fieldListener.updateFieldsNotifier.addPublishListener((result) { + result.fold( + (changeset) { + _fieldCache.applyChangeset(changeset); + add(GridHeaderEvent.didReceiveFieldUpdate(List.from(_fieldCache.fields))); + }, + (err) => Log.error(err), + ); + }); + + _fieldListener.start(); + } + + @override + Future close() async { + await _fieldListener.stop(); + return super.close(); + } +} + +@freezed +class GridHeaderEvent with _$GridHeaderEvent { + const factory GridHeaderEvent.initial() = _InitialHeader; + const factory GridHeaderEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; +} + +@freezed +class GridHeaderState with _$GridHeaderState { + const factory GridHeaderState({required List fields}) = _GridHeaderState; + + factory GridHeaderState.initial(List fields) { + fields.retainWhere((field) => field.visibility); + return GridHeaderState(fields: fields); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index a150b234d0..f596d90be2 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -3,6 +3,11 @@ import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.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'; +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; + +part 'grid_service.freezed.dart'; class GridService { final String gridId; @@ -35,3 +40,174 @@ class GridService { return FolderEventCloseView(request).send(); } } + +class FieldsNotifier extends ChangeNotifier { + List _fields = []; + + set fields(List fields) { + _fields = fields; + notifyListeners(); + } + + List get fields => _fields; +} + +class GridFieldCache { + final FieldsNotifier _fieldNotifier = FieldsNotifier(); + GridFieldCache(); + + void applyChangeset(GridFieldChangeset changeset) { + _removeFields(changeset.deletedFields); + _insertFields(changeset.insertedFields); + _updateFields(changeset.updatedFields); + } + + List get fields => _fieldNotifier.fields; + + set fields(List fields) { + _fieldNotifier.fields = fields; + } + + set onFieldChanged(void Function(List) onChanged) { + _fieldNotifier.addListener(() => onChanged(fields)); + } + + void addListener(void Function(List) onFieldChanged) { + _fieldNotifier.addListener(() => onFieldChanged(fields)); + } + + void _removeFields(List deletedFields) { + if (deletedFields.isEmpty) { + return; + } + final List fields = List.from(_fieldNotifier.fields); + final Map deletedFieldMap = { + for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder + }; + + fields.retainWhere((field) => (deletedFieldMap[field.id] == null)); + _fieldNotifier.fields = fields; + } + + void _insertFields(List insertedFields) { + if (insertedFields.isEmpty) { + return; + } + final List fields = List.from(_fieldNotifier.fields); + for (final indexField in insertedFields) { + if (fields.length > indexField.index) { + fields.removeAt(indexField.index); + fields.insert(indexField.index, indexField.field_1); + } else { + fields.add(indexField.field_1); + } + } + _fieldNotifier.fields = fields; + } + + void _updateFields(List updatedFields) { + if (updatedFields.isEmpty) { + return; + } + final List fields = List.from(_fieldNotifier.fields); + for (final updatedField in updatedFields) { + final index = fields.indexWhere((field) => field.id == updatedField.id); + if (index != -1) { + fields.removeAt(index); + fields.insert(index, updatedField); + } + } + _fieldNotifier.fields = fields; + } +} + +class GridRowCache { + final String gridId; + List _fields = []; + List _rows = []; + + GridRowCache({required this.gridId}); + + List get rows => _rows; + + void updateWithBlock(List blocks) { + _rows = blocks.expand((block) => block.rowOrders).map((rowOrder) { + return RowData.fromBlockRow(gridId, rowOrder, _fields); + }).toList(); + } + + void updateFields(List fields) { + if (fields.isEmpty) { + return; + } + + _fields = fields; + _rows = _rows.map((row) => row.copyWith(fields: fields)).toList(); + } + + Option deleteRows(List deletedRows) { + if (deletedRows.isEmpty) { + return none(); + } + + final List newRows = []; + final List> deletedIndex = []; + final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; + _rows.asMap().forEach((index, value) { + if (deletedRowMap[value.rowId] == null) { + newRows.add(value); + } else { + deletedIndex.add(Tuple2(index, value)); + } + }); + _rows = newRows; + + return Some(GridListState.delete(deletedIndex)); + } + + Option insertRows(List createdRows) { + if (createdRows.isEmpty) { + return none(); + } + + List insertIndexs = []; + for (final newRow in createdRows) { + if (newRow.hasIndex()) { + insertIndexs.add(newRow.index); + _rows.insert(newRow.index, _toRowData(newRow.rowOrder)); + } else { + insertIndexs.add(_rows.length); + _rows.add(_toRowData(newRow.rowOrder)); + } + } + + return Some(GridListState.insert(insertIndexs)); + } + + void updateRows(List updatedRows) { + if (updatedRows.isEmpty) { + return; + } + + final List updatedIndexs = []; + for (final updatedRow in updatedRows) { + final index = _rows.indexWhere((row) => row.rowId == updatedRow.rowId); + if (index != -1) { + _rows.removeAt(index); + _rows.insert(index, _toRowData(updatedRow)); + updatedIndexs.add(index); + } + } + } + + RowData _toRowData(RowOrder rowOrder) { + return RowData.fromBlockRow(gridId, rowOrder, _fields); + } +} + +@freezed +class GridListState with _$GridListState { + const factory GridListState.insert(List indexs) = _Insert; + const factory GridListState.delete(List> indexs) = _Delete; + const factory GridListState.initial() = InitialListState; +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 3fd24f8785..7df38179ac 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -3,6 +3,7 @@ export 'row/row_bloc.dart'; export 'row/row_service.dart'; export 'grid_service.dart'; export 'data.dart'; +export 'grid_header_bloc.dart'; // Field export 'field/field_service.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 6c0037d289..ec9b8ff04d 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,6 +1,6 @@ import 'dart:collection'; -import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart'; +import 'package:app_flowy/workspace/application/grid/grid_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'; @@ -17,18 +17,18 @@ typedef CellDataMap = LinkedHashMap; class RowBloc extends Bloc { final RowService _rowService; final RowListener _rowlistener; - final GridFieldsListener _fieldListener; + final GridFieldCache _fieldCache; - RowBloc({required RowData rowData}) + RowBloc({required RowData rowData, required GridFieldCache fieldCache}) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), - _fieldListener = GridFieldsListener(gridId: rowData.gridId), + _fieldCache = fieldCache, _rowlistener = RowListener(rowId: rowData.rowId), super(RowState.initial(rowData)) { on( (event, emit) async { await event.map( initial: (_InitialRow value) async { - _startListening(); + await _startListening(); await _loadRow(emit); }, createRow: (_CreateRow value) { @@ -69,7 +69,6 @@ class RowBloc extends Bloc { @override Future close() async { await _rowlistener.stop(); - await _fieldListener.stop(); return super.close(); } @@ -81,15 +80,13 @@ class RowBloc extends Bloc { ); }); - _fieldListener.updateFieldsNotifier.addPublishListener((result) { - result.fold( - (fields) => add(RowEvent.didReceiveFieldUpdate(fields)), - (err) => Log.error(err), - ); + _fieldCache.addListener((fields) { + if (!isClosed) { + add(RowEvent.didReceiveFieldUpdate(fields)); + } }); _rowlistener.start(); - _fieldListener.start(); } Future _loadRow(Emitter emit) async { diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index 66de503321..140aa388cd 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -50,7 +50,7 @@ class GridPropertyBloc extends Bloc { _fieldListener.updateFieldsNotifier.addPublishListener((result) { result.fold( (fields) { - add(GridPropertyEvent.didReceiveFieldUpdate(fields)); + // add(GridPropertyEvent.didReceiveFieldUpdate(fields)); }, (err) => Log.error(err), ); 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 804ffff685..cb1cb1c888 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 @@ -150,11 +150,7 @@ class _GridHeader extends StatelessWidget { @override Widget build(BuildContext context) { - return SliverPersistentHeader( - delegate: GridHeaderSliverAdaptor(gridId: gridId, fields: List.from(fields)), - floating: true, - pinned: true, - ); + return GridHeaderSliverAdaptor(gridId: gridId, fields: fields); } } @@ -174,10 +170,13 @@ class _GridRows extends StatelessWidget { }, delete: (value) { for (final index in value.indexs) { - _key.currentState?.removeItem(index.value1, (context, animation) => _renderRow(index.value2, animation)); + _key.currentState?.removeItem( + index.value1, + (context, animation) => _renderRow(context, index.value2, animation), + ); } }, - reload: (updatedIndexs) {}, + initial: (updatedIndexs) {}, ); }, buildWhen: (previous, current) => false, @@ -187,17 +186,22 @@ class _GridRows extends StatelessWidget { initialItemCount: context.read().state.rows.length, itemBuilder: (BuildContext context, int index, Animation animation) { final rowData = context.read().state.rows[index]; - return _renderRow(rowData, animation); + return _renderRow(context, rowData, animation); }, ); }, ); } - Widget _renderRow(RowData rowData, Animation animation) { + Widget _renderRow(BuildContext context, RowData rowData, Animation animation) { + final fieldCache = context.read().fieldCache; return SizeTransition( sizeFactor: animation, - child: GridRowWidget(data: rowData, key: ValueKey(rowData.rowId)), + child: GridRowWidget( + data: rowData, + fieldCache: fieldCache, + key: ValueKey(rowData.rowId), + ), ); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index c387ecd4e2..3893ac7784 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -12,32 +12,38 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'field_editor.dart'; import 'field_cell.dart'; -class GridHeaderSliverAdaptor extends SliverPersistentHeaderDelegate { +class GridHeaderSliverAdaptor extends StatelessWidget { final String gridId; final List fields; - GridHeaderSliverAdaptor({required this.gridId, required this.fields}); + const GridHeaderSliverAdaptor({required this.gridId, required this.fields, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(param1: gridId, param2: fields)..add(const GridHeaderEvent.initial()), + child: BlocBuilder( + builder: (context, state) { + return SliverPersistentHeader( + delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: fields), + floating: true, + pinned: true, + ); + }, + ), + ); + } +} + +class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate { + final String gridId; + final List fields; + + SliverHeaderDelegateImplementation({required this.gridId, required this.fields}); @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - final cells = fields.map( - (field) => GridFieldCell( - GridFieldCellContext(gridId: gridId, field: field), - ), - ); - - return Container( - color: Colors.white, - child: Row( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const _CellLeading(), - ...cells, - _CellTrailing(gridId: gridId), - ], - key: ObjectKey(fields), - ), - ); + return _GridHeader(gridId: gridId, fields: fields, key: ObjectKey(fields)); } @override @@ -48,13 +54,49 @@ class GridHeaderSliverAdaptor extends SliverPersistentHeaderDelegate { @override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { - if (oldDelegate is GridHeaderSliverAdaptor) { + if (oldDelegate is SliverHeaderDelegateImplementation) { return fields.length != oldDelegate.fields.length; } return true; } } +class _GridHeader extends StatelessWidget { + final String gridId; + final List fields; + + const _GridHeader({ + Key? key, + required this.gridId, + required this.fields, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return BlocBuilder( + builder: (context, state) { + final cells = state.fields + .map((field) => GridFieldCellContext(gridId: gridId, field: field)) + .map((ctx) => GridFieldCell(ctx, key: ValueKey(ctx.field.id))) + .toList(); + + return Container( + color: theme.surface, + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const _CellLeading(), + ...cells, + _CellTrailing(gridId: gridId), + ], + ), + ); + }, + ); + } +} + class _CellLeading extends StatelessWidget { const _CellLeading({Key? key}) : super(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 baeed922d7..5528818a58 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 @@ -13,7 +13,8 @@ import 'row_action_sheet.dart'; class GridRowWidget extends StatefulWidget { final RowData data; - const GridRowWidget({required this.data, Key? key}) : super(key: key); + final GridFieldCache fieldCache; + const GridRowWidget({required this.data, required this.fieldCache, Key? key}) : super(key: key); @override State createState() => _GridRowWidgetState(); @@ -25,7 +26,7 @@ class _GridRowWidgetState extends State { @override void initState() { - _rowBloc = getIt(param1: widget.data)..add(const RowEvent.initial()); + _rowBloc = getIt(param1: widget.data, param2: widget.fieldCache)..add(const RowEvent.initial()); _rowStateNotifier = _RegionStateNotifier(); super.initState(); } 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 1212cb506e..8c01e7c1bc 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 @@ -325,18 +325,8 @@ class GridFieldChangeset extends $pb.GeneratedMessage { $core.List get updatedFields => $_getList(3); } -enum IndexField_OneOfIndex { - index_, - notSet -} - class IndexField extends $pb.GeneratedMessage { - static const $core.Map<$core.int, IndexField_OneOfIndex> _IndexField_OneOfIndexByTag = { - 2 : IndexField_OneOfIndex.index_, - 0 : IndexField_OneOfIndex.notSet - }; static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'IndexField', createEmptyInstance: create) - ..oo(0, [2]) ..aOM(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'field', subBuilder: Field.create) ..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'index', $pb.PbFieldType.O3) ..hasRequiredFields = false @@ -377,9 +367,6 @@ class IndexField extends $pb.GeneratedMessage { static IndexField getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static IndexField? _defaultInstance; - IndexField_OneOfIndex whichOneOfIndex() => _IndexField_OneOfIndexByTag[$_whichOneof(0)]!; - void clearOneOfIndex() => clearField($_whichOneof(0)); - @$pb.TagNumber(1) Field get field_1 => $_getN(0); @$pb.TagNumber(1) 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 a5d8fab78f..624e31c392 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 @@ -90,15 +90,12 @@ const IndexField$json = const { '1': 'IndexField', '2': const [ const {'1': 'field', '3': 1, '4': 1, '5': 11, '6': '.Field', '10': 'field'}, - const {'1': 'index', '3': 2, '4': 1, '5': 5, '9': 0, '10': 'index'}, - ], - '8': const [ - const {'1': 'one_of_index'}, + const {'1': 'index', '3': 2, '4': 1, '5': 5, '10': 'index'}, ], }; /// Descriptor for `IndexField`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List indexFieldDescriptor = $convert.base64Decode('CgpJbmRleEZpZWxkEhwKBWZpZWxkGAEgASgLMgYuRmllbGRSBWZpZWxkEhYKBWluZGV4GAIgASgFSABSBWluZGV4Qg4KDG9uZV9vZl9pbmRleA=='); +final $typed_data.Uint8List indexFieldDescriptor = $convert.base64Decode('CgpJbmRleEZpZWxkEhwKBWZpZWxkGAEgASgLMgYuRmllbGRSBWZpZWxkEhQKBWluZGV4GAIgASgFUgVpbmRleA=='); @$core.Deprecated('Use getEditFieldContextPayloadDescriptor instead') const GetEditFieldContextPayload$json = const { '1': 'GetEditFieldContextPayload', diff --git a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs index 99867fb484..b7c30919b6 100644 --- a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs +++ b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs @@ -24,7 +24,7 @@ pub struct ClientFolderEditor { pub(crate) folder_id: FolderId, pub(crate) folder: Arc>, rev_manager: Arc, - ws_manager: Arc, + // ws_manager: Arc, } impl ClientFolderEditor { @@ -40,14 +40,14 @@ impl ClientFolderEditor { }); let folder = Arc::new(RwLock::new(rev_manager.load::(Some(cloud)).await?)); let rev_manager = Arc::new(rev_manager); - let ws_manager = make_folder_ws_manager( - user_id, - folder_id.as_ref(), - rev_manager.clone(), - web_socket, - folder.clone(), - ) - .await; + // let ws_manager = make_folder_ws_manager( + // user_id, + // folder_id.as_ref(), + // rev_manager.clone(), + // web_socket, + // folder.clone(), + // ) + // .await; let user_id = user_id.to_owned(); let folder_id = folder_id.to_owned(); @@ -56,15 +56,15 @@ impl ClientFolderEditor { folder_id, folder, rev_manager, - ws_manager, + // ws_manager, }) } pub async fn receive_ws_data(&self, data: ServerRevisionWSData) -> FlowyResult<()> { - let _ = self.ws_manager.ws_passthrough_tx.send(data).await.map_err(|e| { - let err_msg = format!("{} passthrough error: {}", self.folder_id, e); - FlowyError::internal().context(err_msg) - })?; + // let _ = self.ws_manager.ws_passthrough_tx.send(data).await.map_err(|e| { + // let err_msg = format!("{} passthrough error: {}", self.folder_id, e); + // FlowyError::internal().context(err_msg) + // })?; 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 8425097f69..5cd4ebca87 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -59,9 +59,9 @@ impl ClientGridEditor { grid_id, } = params; let field_id = field.id.clone(); - let _ = self - .modify(|grid| { - if grid.contain_field(&field.id) { + if self.contain_field(&field_id).await { + let _ = self + .modify(|grid| { let deserializer = TypeOptionJsonDeserializer(field.field_type.clone()); let changeset = FieldChangesetParams { field_id: field.id, @@ -74,17 +74,22 @@ impl ClientGridEditor { width: Some(field.width), type_option_data: Some(type_option_data), }; - Ok(grid.update_field(changeset, deserializer)?) - } else { - // let type_option_json = type_option_json_str_from_bytes(type_option_data, &field.field_type); + Ok(grid.update_field_meta(changeset, deserializer)?) + }) + .await?; + let _ = self.notify_grid_did_update_field(&field_id).await?; + } else { + let _ = self + .modify(|grid| { let builder = type_option_builder_from_bytes(type_option_data, &field.field_type); let field_meta = FieldBuilder::from_field(field, builder).build(); - Ok(grid.create_field(field_meta, start_field_id)?) - } - }) - .await?; - let _ = self.notify_did_update_grid().await?; - let _ = self.notify_did_update_field(&field_id).await?; + + Ok(grid.create_field_meta(field_meta, start_field_id)?) + }) + .await?; + let _ = self.notify_grid_did_insert_field(&field_id).await?; + } + Ok(()) } @@ -100,29 +105,31 @@ impl ClientGridEditor { pub async fn update_field(&self, params: FieldChangesetParams) -> FlowyResult<()> { let field_id = params.field_id.clone(); - let json_deserializer = match self.pad.read().await.get_field(params.field_id.as_str()) { + let json_deserializer = match self.pad.read().await.get_field_meta(params.field_id.as_str()) { None => return Err(ErrorCode::FieldDoesNotExist.into()), - Some(field_meta) => TypeOptionJsonDeserializer(field_meta.field_type.clone()), + Some((_, field_meta)) => TypeOptionJsonDeserializer(field_meta.field_type.clone()), }; let _ = self - .modify(|grid| Ok(grid.update_field(params, json_deserializer)?)) + .modify(|grid| Ok(grid.update_field_meta(params, json_deserializer)?)) .await?; - let _ = self.notify_did_update_grid().await?; - let _ = self.notify_did_update_field(&field_id).await?; + + let _ = self.notify_grid_did_update_field(&field_id).await?; Ok(()) } pub async fn replace_field(&self, field_meta: FieldMeta) -> FlowyResult<()> { let field_id = field_meta.id.clone(); - let _ = self.modify(|pad| Ok(pad.replace_field(field_meta)?)).await?; - let _ = self.notify_did_update_field(&field_id).await?; + let _ = self.modify(|pad| Ok(pad.replace_field_meta(field_meta)?)).await?; + let _ = self.notify_grid_did_update_field(&field_id).await?; Ok(()) } pub async fn delete_field(&self, field_id: &str) -> FlowyResult<()> { - let _ = self.modify(|grid| Ok(grid.delete_field(field_id)?)).await?; - let _ = self.notify_did_update_grid().await?; + let _ = self.modify(|grid| Ok(grid.delete_field_meta(field_id)?)).await?; + let field_order = FieldOrder::from(field_id); + let notified_changeset = GridFieldChangeset::delete(&self.grid_id, vec![field_order]); + let _ = self.notify_did_update_grid(notified_changeset).await?; Ok(()) } @@ -145,27 +152,24 @@ impl ClientGridEditor { let _ = self .modify(|grid| Ok(grid.switch_to_field(field_id, field_type.clone(), type_option_json_builder)?)) .await?; - let _ = self.notify_did_update_grid().await?; - let _ = self.notify_did_update_field(field_id).await?; + + let _ = self.notify_grid_did_update_field(&field_id).await?; + Ok(()) } pub async fn duplicate_field(&self, field_id: &str) -> FlowyResult<()> { - let mut duplicated_field_meta = None; + let duplicated_field_id = gen_field_id(); let _ = self - .modify(|grid| { - let (changeset, field_meta) = grid.duplicate_field(field_id)?; - duplicated_field_meta = field_meta; - Ok(changeset) - }) + .modify(|grid| Ok(grid.duplicate_field_meta(field_id, &duplicated_field_id)?)) .await?; - let _ = self.notify_did_update_grid().await?; + let _ = self.notify_grid_did_insert_field(field_id).await?; Ok(()) } pub async fn get_field_meta(&self, field_id: &str) -> Option { - let field_meta = self.pad.read().await.get_field(field_id)?.clone(); + let field_meta = self.pad.read().await.get_field_meta(field_id)?.1.clone(); Some(field_meta) } @@ -310,12 +314,12 @@ impl ClientGridEditor { let cell_data_changeset = changeset.data.unwrap(); let cell_meta = self.get_cell_meta(&changeset.row_id, &changeset.field_id).await?; tracing::trace!("{}: {:?}", &changeset.field_id, cell_meta); - match self.pad.read().await.get_field(&changeset.field_id) { + match self.pad.read().await.get_field_meta(&changeset.field_id) { None => { let msg = format!("Field not found with id: {}", &changeset.field_id); Err(FlowyError::internal().context(msg)) } - Some(field_meta) => { + 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?; @@ -334,11 +338,6 @@ impl ClientGridEditor { Ok(grid_blocks) } - // pub async fn get_field_metas(&self, field_ids: Option>) -> FlowyResult> - // where - // T: Into, - // { - pub async fn delete_rows(&self, row_orders: Vec) -> FlowyResult<()> { let changesets = self.block_meta_manager.delete_rows(row_orders).await?; for changeset in changesets { @@ -445,37 +444,40 @@ impl ClientGridEditor { } } - async fn notify_did_update_grid(&self) -> FlowyResult<()> { - // GridFieldChangeset - - let field_metas = self.get_field_metas::(None).await?; - let repeated_field: RepeatedField = field_metas.into_iter().map(Field::from).collect::>().into(); - send_dart_notification(&self.grid_id, GridNotification::DidUpdateGrid) - .payload(repeated_field) - .send(); - Ok(()) - } - - async fn notify_did_update_grid2(&self, changeset: GridFieldChangeset) -> FlowyResult<()> { - send_dart_notification(&self.grid_id, GridNotification::DidUpdateGrid) - .payload(changeset) - .send(); + #[tracing::instrument(level = "trace", skip_all, err)] + async fn notify_grid_did_insert_field(&self, field_id: &str) -> FlowyResult<()> { + if let Some((index, field_meta)) = self.pad.read().await.get_field_meta(field_id) { + let index_field = IndexField::from_field_meta(field_meta, index); + let notified_changeset = GridFieldChangeset::insert(&self.grid_id, vec![index_field]); + let _ = self.notify_did_update_grid(notified_changeset).await?; + } Ok(()) } #[tracing::instrument(level = "trace", skip_all, err)] - async fn notify_did_update_field(&self, field_id: &str) -> FlowyResult<()> { + async fn notify_grid_did_update_field(&self, field_id: &str) -> FlowyResult<()> { let mut field_metas = self.get_field_metas(Some(vec![field_id])).await?; debug_assert!(field_metas.len() == 1); if let Some(field_meta) = field_metas.pop() { + let updated_field = Field::from(field_meta); + let notified_changeset = GridFieldChangeset::update(&self.grid_id, vec![updated_field.clone()]); + let _ = self.notify_did_update_grid(notified_changeset).await?; + send_dart_notification(field_id, GridNotification::DidUpdateField) - .payload(Field::from(field_meta)) + .payload(updated_field) .send(); } Ok(()) } + + async fn notify_did_update_grid(&self, changeset: GridFieldChangeset) -> FlowyResult<()> { + send_dart_notification(&self.grid_id, GridNotification::DidUpdateGrid) + .payload(changeset) + .send(); + Ok(()) + } } #[cfg(feature = "flowy_unit_test")] 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 f090cfdc5e..94f46919c1 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -133,8 +133,17 @@ pub struct IndexField { #[pb(index = 1)] pub field: Field, - #[pb(index = 2, one_of)] - pub index: Option, + #[pb(index = 2)] + pub index: i32, +} + +impl IndexField { + pub fn from_field_meta(field_meta: &FieldMeta, index: usize) -> Self { + Self { + field: Field::from(field_meta.clone()), + index: index as i32, + } + } } #[derive(Debug, Default, ProtoBuf)] 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 46de6cf971..d988ae90c2 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 @@ -1128,8 +1128,7 @@ impl ::protobuf::reflect::ProtobufValue for GridFieldChangeset { pub struct IndexField { // message fields pub field: ::protobuf::SingularPtrField, - // message oneof groups - pub one_of_index: ::std::option::Option, + pub index: i32, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -1141,11 +1140,6 @@ impl<'a> ::std::default::Default for &'a IndexField { } } -#[derive(Clone,PartialEq,Debug)] -pub enum IndexField_oneof_one_of_index { - index(i32), -} - impl IndexField { pub fn new() -> IndexField { ::std::default::Default::default() @@ -1188,25 +1182,15 @@ impl IndexField { pub fn get_index(&self) -> i32 { - match self.one_of_index { - ::std::option::Option::Some(IndexField_oneof_one_of_index::index(v)) => v, - _ => 0, - } + self.index } pub fn clear_index(&mut self) { - self.one_of_index = ::std::option::Option::None; - } - - pub fn has_index(&self) -> bool { - match self.one_of_index { - ::std::option::Option::Some(IndexField_oneof_one_of_index::index(..)) => true, - _ => false, - } + self.index = 0; } // Param is passed by value, moved pub fn set_index(&mut self, v: i32) { - self.one_of_index = ::std::option::Option::Some(IndexField_oneof_one_of_index::index(v)) + self.index = v; } } @@ -1231,7 +1215,8 @@ impl ::protobuf::Message for IndexField { if wire_type != ::protobuf::wire_format::WireTypeVarint { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } - self.one_of_index = ::std::option::Option::Some(IndexField_oneof_one_of_index::index(is.read_int32()?)); + let tmp = is.read_int32()?; + self.index = tmp; }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; @@ -1249,12 +1234,8 @@ impl ::protobuf::Message for IndexField { let len = v.compute_size(); my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; } - if let ::std::option::Option::Some(ref v) = self.one_of_index { - match v { - &IndexField_oneof_one_of_index::index(v) => { - my_size += ::protobuf::rt::value_size(2, v, ::protobuf::wire_format::WireTypeVarint); - }, - }; + if self.index != 0 { + my_size += ::protobuf::rt::value_size(2, self.index, ::protobuf::wire_format::WireTypeVarint); } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); @@ -1267,12 +1248,8 @@ impl ::protobuf::Message for IndexField { os.write_raw_varint32(v.get_cached_size())?; v.write_to_with_cached_sizes(os)?; } - if let ::std::option::Option::Some(ref v) = self.one_of_index { - match v { - &IndexField_oneof_one_of_index::index(v) => { - os.write_int32(2, v)?; - }, - }; + if self.index != 0 { + os.write_int32(2, self.index)?; } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) @@ -1317,10 +1294,10 @@ impl ::protobuf::Message for IndexField { |m: &IndexField| { &m.field }, |m: &mut IndexField| { &mut m.field }, )); - fields.push(::protobuf::reflect::accessor::make_singular_i32_accessor::<_>( + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>( "index", - IndexField::has_index, - IndexField::get_index, + |m: &IndexField| { &m.index }, + |m: &mut IndexField| { &mut m.index }, )); ::protobuf::reflect::MessageDescriptor::new_pb_name::( "IndexField", @@ -1339,7 +1316,7 @@ impl ::protobuf::Message for IndexField { impl ::protobuf::Clear for IndexField { fn clear(&mut self) { self.field.clear(); - self.one_of_index = ::std::option::Option::None; + self.index = 0; self.unknown_fields.clear(); } } @@ -7803,83 +7780,83 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x124\n\x0finserted_field\ s\x18\x02\x20\x03(\x0b2\x0b.IndexFieldR\x0einsertedFields\x122\n\x0edele\ ted_fields\x18\x03\x20\x03(\x0b2\x0b.FieldOrderR\rdeletedFields\x12-\n\ - \x0eupdated_fields\x18\x04\x20\x03(\x0b2\x06.FieldR\rupdatedFields\"R\n\ + \x0eupdated_fields\x18\x04\x20\x03(\x0b2\x06.FieldR\rupdatedFields\"@\n\ \nIndexField\x12\x1c\n\x05field\x18\x01\x20\x01(\x0b2\x06.FieldR\x05fiel\ - d\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_\ - index\"\x90\x01\n\x1aGetEditFieldContextPayload\x12\x17\n\x07grid_id\x18\ - \x01\x20\x01(\tR\x06gridId\x12\x1b\n\x08field_id\x18\x02\x20\x01(\tH\0R\ - \x07fieldId\x12)\n\nfield_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfield\ - TypeB\x11\n\x0fone_of_field_id\"q\n\x10EditFieldPayload\x12\x17\n\x07gri\ - d_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01\ - (\tR\x07fieldId\x12)\n\nfield_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tf\ - ieldType\"|\n\x10EditFieldContext\x12\x17\n\x07grid_id\x18\x01\x20\x01(\ - \tR\x06gridId\x12%\n\ngrid_field\x18\x02\x20\x01(\x0b2\x06.FieldR\tgridF\ - ield\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\ - \"-\n\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\ - \x05items\"7\n\x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\ - \x0b2\x0b.FieldOrderR\x05items\"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\ - \x01\x20\x01(\tR\x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07b\ - lockId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\ - \x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_fiel\ - d_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\rcellByFieldId\ - \x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\n\x12CellByFie\ - ldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\ - \x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\ - \x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11Repe\ - atedGridBlock\x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05i\ - tems\"U\n\x0eGridBlockOrder\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\ - \x07blockId\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrd\ - ers\"_\n\rIndexRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrd\ - erR\x08rowOrder\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\ - \x0e\n\x0cone_of_index\"\xbf\x01\n\x11GridRowsChangeset\x12\x19\n\x08blo\ - ck_id\x18\x01\x20\x01(\tR\x07blockId\x123\n\rinserted_rows\x18\x02\x20\ - \x03(\x0b2\x0e.IndexRowOrderR\x0cinsertedRows\x12,\n\x0cdeleted_rows\x18\ - \x03\x20\x03(\x0b2\t.RowOrderR\x0bdeletedRows\x12,\n\x0cupdated_rows\x18\ - \x04\x20\x03(\x0b2\t.RowOrderR\x0bupdatedRows\"E\n\tGridBlock\x12\x0e\n\ - \x02id\x18\x01\x20\x01(\tR\x02id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b\ - 2\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\ - \"\x8f\x01\n\x14CellNotificationData\x12\x17\n\x07grid_id\x18\x01\x20\ - \x01(\tR\x06gridId\x12\x19\n\x08field_id\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\x0cRepe\ - atedCell\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\ - \n\x11CreateGridPayload\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\x10\ - CreateRowPayload\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(\tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.\ - FieldR\x05field\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etype\ - OptionData\x12&\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartField\ - IdB\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\x16QueryGridB\ - locksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\ - \x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrder\ - s\"\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\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\nvisibi\ - lity\x12\x16\n\x05width\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10ty\ - pe_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_fro\ - zenB\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\x06i\ - temId\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\x06gridId\x12\x15\n\x06row_id\x18\x02\ - \x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07field\ - Id\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\x08DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\ - \x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ + d\x12\x14\n\x05index\x18\x02\x20\x01(\x05R\x05index\"\x90\x01\n\x1aGetEd\ + itFieldContextPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\ + \x12\x1b\n\x08field_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\n\nfield_t\ + ype\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field\ + _id\"q\n\x10EditFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\ + \x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12)\n\n\ + field_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldType\"|\n\x10EditFie\ + ldContext\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngri\ + d_field\x18\x02\x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\x10type_optio\ + n_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\"-\n\rRepeatedField\x12\ + \x1c\n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12Repeat\ + edFieldOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05it\ + ems\"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\ + \x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06heigh\ + t\x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\ + \x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\ + \x17.Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\ + \x20\x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\ + \x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05\ + .CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\ + \x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05\ + items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\ + \x12\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\ + \trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05i\ + ndex\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\x07blo\ + ckId\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0ci\ + nsertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0b\ + deletedRows\x12,\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\t.RowOrderR\x0b\ + updatedRows\"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\ + \x07content\x18\x02\x20\x01(\tR\x07content\"\x8f\x01\n\x14CellNotificati\ + onData\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08f\ + ield_id\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\x07content\ + B\x10\n\x0eone_of_content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\ + \x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\ + \n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05va\ + lue\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\x12Ins\ + ertFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\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_fie\ + ld_id\x18\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_fiel\ + d_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.RepeatedFiel\ + dOrderR\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\x15FieldChangesetPa\ + yload\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07\ + grid_id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\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\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\x0f\ + MoveItemPayload\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\ + \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\x08DateTime\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 acf01a229c..45a1af0518 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 @@ -25,7 +25,7 @@ message GridFieldChangeset { } message IndexField { Field field = 1; - oneof one_of_index { int32 index = 2; }; + int32 index = 2; } message GetEditFieldContextPayload { string grid_id = 1; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index e39798a33a..ebc5483b5b 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -4,11 +4,12 @@ use crate::util::{cal_diff, make_delta_from_revisions}; use bytes::Bytes; use flowy_grid_data_model::entities::{ gen_field_id, gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, - GridBlockMetaChangeset, GridMeta, + GridBlockMetaChangeset, GridMeta, IndexField, }; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use std::collections::HashMap; +use futures::StreamExt; use std::sync::Arc; pub type GridMetaDelta = PlainTextDelta; @@ -41,7 +42,7 @@ impl GridMetaPad { } #[tracing::instrument(level = "debug", skip_all, err)] - pub fn create_field( + pub fn create_field_meta( &mut self, new_field_meta: FieldMeta, start_field_id: Option, @@ -70,7 +71,7 @@ impl GridMetaPad { }) } - pub fn delete_field(&mut self, field_id: &str) -> CollaborateResult> { + pub fn delete_field_meta(&mut self, field_id: &str) -> CollaborateResult> { self.modify_grid( |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { None => Ok(None), @@ -82,23 +83,23 @@ impl GridMetaPad { ) } - pub fn duplicate_field(&mut self, field_id: &str) -> CollaborateResult<(Option, Option)> { - let mut field_meta = None; - let changeset = - self.modify_grid( - |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { - None => Ok(None), - Some(index) => { - let mut duplicate_field_meta = grid_meta.fields[index].clone(); - duplicate_field_meta.id = gen_field_id(); - duplicate_field_meta.name = format!("{} (copy)", duplicate_field_meta.name); - field_meta = Some(duplicate_field_meta.clone()); - grid_meta.fields.insert(index + 1, duplicate_field_meta); - Ok(Some(())) - } - }, - )?; - Ok((changeset, field_meta)) + pub fn duplicate_field_meta( + &mut self, + field_id: &str, + duplicated_field_id: &str, + ) -> CollaborateResult> { + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { + None => Ok(None), + Some(index) => { + let mut duplicate_field_meta = grid_meta.fields[index].clone(); + duplicate_field_meta.id = duplicated_field_id.to_string(); + duplicate_field_meta.name = format!("{} (copy)", duplicate_field_meta.name); + grid_meta.fields.insert(index + 1, duplicate_field_meta); + Ok(Some(())) + } + }, + ) } pub fn switch_to_field( @@ -130,7 +131,7 @@ impl GridMetaPad { }) } - pub fn update_field( + pub fn update_field_meta( &mut self, changeset: FieldChangesetParams, deserializer: T, @@ -185,11 +186,15 @@ impl GridMetaPad { }) } - pub fn get_field(&self, field_id: &str) -> Option<&FieldMeta> { - self.grid_meta.fields.iter().find(|field| field.id == field_id) + pub fn get_field_meta(&self, field_id: &str) -> Option<(usize, &FieldMeta)> { + self.grid_meta + .fields + .iter() + .enumerate() + .find(|(_, field)| field.id == field_id) } - pub fn replace_field(&mut self, field_meta: FieldMeta) -> CollaborateResult> { + pub fn replace_field_meta(&mut self, field_meta: FieldMeta) -> CollaborateResult> { self.modify_grid( |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_meta.id) { None => Ok(None), From b606c5ba7b19e19f2310dd9b1fa219c1bb8df1f4 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 14 Apr 2022 18:11:28 +0800 Subject: [PATCH 07/26] chore: fix some bugs --- .../app_flowy/lib/startup/deps_resolver.dart | 7 ++-- .../lib/startup/tasks/app_widget.dart | 12 +++---- .../grid/cell_bloc/date_cell_bloc.dart | 6 +++- .../grid/cell_bloc/selection_editor_bloc.dart | 6 +++- .../lib/workspace/application/grid/data.dart | 8 ----- .../grid/field/field_cell_bloc.dart | 6 +++- .../workspace/application/grid/grid_bloc.dart | 19 ++++------ .../application/grid/grid_header_bloc.dart | 36 ++++++------------- .../application/grid/grid_service.dart | 33 +++++++++-------- .../workspace/application/grid/prelude.dart | 1 - .../application/grid/row/row_bloc.dart | 4 +-- .../plugins/grid/src/grid_page.dart | 5 +-- .../grid/src/widgets/header/grid_header.dart | 10 +++--- 13 files changed, 72 insertions(+), 81 deletions(-) delete mode 100644 frontend/app_flowy/lib/workspace/application/grid/data.dart diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index cb685cd7b2..e35f8e7f96 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -157,9 +157,10 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam>( - (gridId, fields) => GridHeaderBloc( - data: GridHeaderData(gridId: gridId, fields: fields), + getIt.registerFactoryParam( + (gridId, fieldCache) => GridHeaderBloc( + gridId: gridId, + fieldCache: fieldCache, ), ); diff --git a/frontend/app_flowy/lib/startup/tasks/app_widget.dart b/frontend/app_flowy/lib/startup/tasks/app_widget.dart index 1747cfd8ec..3dba94ce0a 100644 --- a/frontend/app_flowy/lib/startup/tasks/app_widget.dart +++ b/frontend/app_flowy/lib/startup/tasks/app_widget.dart @@ -113,7 +113,7 @@ class ApplicationBlocObserver extends BlocObserver { // ignore: unnecessary_overrides void onTransition(Bloc bloc, Transition transition) { // Log.debug("[current]: ${transition.currentState} \n\n[next]: ${transition.nextState}"); - // Log.debug("${transition.nextState}"); + Log.debug("${transition.nextState}"); super.onTransition(bloc, transition); } @@ -123,9 +123,9 @@ class ApplicationBlocObserver extends BlocObserver { super.onError(bloc, error, stackTrace); } - // @override - // void onEvent(Bloc bloc, Object? event) { - // Log.debug("$event"); - // super.onEvent(bloc, event); - // } + @override + void onEvent(Bloc bloc, Object? event) { + // Log.debug("$event"); + super.onEvent(bloc, event); + } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart index f235b47e4a..7dd58bf5ac 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart @@ -62,7 +62,11 @@ class DateCellBloc extends Bloc { _fieldListener.updateFieldNotifier.addPublishListener((result) { result.fold( - (field) => add(DateCellEvent.didReceiveFieldUpdate(field)), + (field) { + if (!isClosed) { + add(DateCellEvent.didReceiveFieldUpdate(field)); + } + }, (err) => Log.error(err), ); }); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart index 59510298a7..5d2c52dc0e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart @@ -144,7 +144,11 @@ class SelectOptionEditorBloc extends Bloc add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)), + (field) { + if (!isClosed) { + add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)); + } + }, (err) => Log.error(err), ); }); diff --git a/frontend/app_flowy/lib/workspace/application/grid/data.dart b/frontend/app_flowy/lib/workspace/application/grid/data.dart deleted file mode 100644 index 7c508a6867..0000000000 --- a/frontend/app_flowy/lib/workspace/application/grid/data.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; - -class GridHeaderData { - final String gridId; - final List fields; - - GridHeaderData({required this.gridId, required this.fields}); -} 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 026be9a780..11dd1af530 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 @@ -47,7 +47,11 @@ class FieldCellBloc extends Bloc { void _startListening() { _fieldListener.updateFieldNotifier.addPublishListener((result) { result.fold( - (field) => add(FieldCellEvent.didReceiveFieldUpdate(field)), + (field) { + if (!isClosed) { + add(FieldCellEvent.didReceiveFieldUpdate(field)); + } + }, (err) => Log.error(err), ); }); 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 abdf73acbc..882b3eb5b4 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -41,10 +41,7 @@ class GridBloc extends Bloc { emit(state.copyWith(rows: value.rows, listState: value.listState)); }, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - emit(state.copyWith( - rows: _rowCache.rows, - fields: value.fields, - )); + emit(state.copyWith(rows: _rowCache.rows, fields: value.fields)); }, ); }, @@ -56,19 +53,17 @@ class GridBloc extends Bloc { await _gridService.closeGrid(); await _fieldListener.stop(); await _gridListener.stop(); + fieldCache.dispose(); return super.close(); } void _startListening() { - fieldCache.addListener((fields) { - _rowCache.updateFields(fields); - }); - _fieldListener.updateFieldsNotifier.addPublishListener((result) { result.fold( (changeset) { fieldCache.applyChangeset(changeset); - add(GridEvent.didReceiveFieldUpdate(List.from(fieldCache.fields))); + _rowCache.updateFields(fieldCache.unmodifiableFields); + add(GridEvent.didReceiveFieldUpdate(fieldCache.clonedFields)); }, (err) => Log.error(err), ); @@ -111,12 +106,12 @@ class GridBloc extends Bloc { return Future( () => result.fold( (fields) { - fieldCache.fields = fields.items; - _rowCache.updateWithBlock(grid.blockOrders); + fieldCache.clonedFields = fields.items; + _rowCache.updateWithBlock(grid.blockOrders, fieldCache.unmodifiableFields); emit(state.copyWith( grid: Some(grid), - fields: fieldCache.fields, + fields: fieldCache.clonedFields, rows: _rowCache.rows, loadingState: GridLoadingState.finish(left(unit)), )); diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index 18086ce6d9..c7ce6c21f1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -1,6 +1,3 @@ -import 'package:app_flowy/workspace/application/grid/data.dart'; -import 'package:app_flowy/workspace/application/grid/field/grid_listenr.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'; @@ -12,17 +9,13 @@ part 'grid_header_bloc.freezed.dart'; class GridHeaderBloc extends Bloc { final FieldService _fieldService; - final GridFieldCache _fieldCache; - final GridFieldsListener _fieldListener; + final GridFieldCache fieldCache; GridHeaderBloc({ - required GridHeaderData data, - }) : _fieldListener = GridFieldsListener(gridId: data.gridId), - _fieldService = FieldService(gridId: data.gridId), - _fieldCache = GridFieldCache(), - super(GridHeaderState.initial(data.fields)) { - _fieldCache.fields = data.fields; - + required String gridId, + required this.fieldCache, + }) : _fieldService = FieldService(gridId: gridId), + super(GridHeaderState.initial(fieldCache.clonedFields)) { on( (event, emit) async { await event.map( @@ -30,7 +23,6 @@ class GridHeaderBloc extends Bloc { _startListening(); }, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - value.fields.retainWhere((field) => field.visibility); emit(state.copyWith(fields: value.fields)); }, ); @@ -39,22 +31,15 @@ class GridHeaderBloc extends Bloc { } Future _startListening() async { - _fieldListener.updateFieldsNotifier.addPublishListener((result) { - result.fold( - (changeset) { - _fieldCache.applyChangeset(changeset); - add(GridHeaderEvent.didReceiveFieldUpdate(List.from(_fieldCache.fields))); - }, - (err) => Log.error(err), - ); + fieldCache.listenOnFieldChanged((fields) { + if (!isClosed) { + add(GridHeaderEvent.didReceiveFieldUpdate(fields)); + } }); - - _fieldListener.start(); } @override Future close() async { - await _fieldListener.stop(); return super.close(); } } @@ -70,7 +55,8 @@ class GridHeaderState with _$GridHeaderState { const factory GridHeaderState({required List fields}) = _GridHeaderState; factory GridHeaderState.initial(List fields) { - fields.retainWhere((field) => field.visibility); + // final List newFields = List.from(fields); + // newFields.retainWhere((field) => field.visibility); return GridHeaderState(fields: fields); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index f596d90be2..fc853ef8b7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -62,25 +62,23 @@ class GridFieldCache { _updateFields(changeset.updatedFields); } - List get fields => _fieldNotifier.fields; + UnmodifiableListView get unmodifiableFields => UnmodifiableListView(_fieldNotifier.fields); - set fields(List fields) { - _fieldNotifier.fields = fields; + List get clonedFields => [..._fieldNotifier.fields]; + + set clonedFields(List fields) { + _fieldNotifier.fields = [...fields]; } - set onFieldChanged(void Function(List) onChanged) { - _fieldNotifier.addListener(() => onChanged(fields)); - } - - void addListener(void Function(List) onFieldChanged) { - _fieldNotifier.addListener(() => onFieldChanged(fields)); + void listenOnFieldChanged(void Function(List) onFieldChanged) { + _fieldNotifier.addListener(() => onFieldChanged(clonedFields)); } void _removeFields(List deletedFields) { if (deletedFields.isEmpty) { return; } - final List fields = List.from(_fieldNotifier.fields); + final List fields = _fieldNotifier.fields; final Map deletedFieldMap = { for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder }; @@ -93,7 +91,7 @@ class GridFieldCache { if (insertedFields.isEmpty) { return; } - final List fields = List.from(_fieldNotifier.fields); + final List fields = _fieldNotifier.fields; for (final indexField in insertedFields) { if (fields.length > indexField.index) { fields.removeAt(indexField.index); @@ -109,7 +107,7 @@ class GridFieldCache { if (updatedFields.isEmpty) { return; } - final List fields = List.from(_fieldNotifier.fields); + final List fields = _fieldNotifier.fields; for (final updatedField in updatedFields) { final index = fields.indexWhere((field) => field.id == updatedField.id); if (index != -1) { @@ -119,24 +117,29 @@ class GridFieldCache { } _fieldNotifier.fields = fields; } + + void dispose() { + _fieldNotifier.dispose(); + } } class GridRowCache { final String gridId; - List _fields = []; + UnmodifiableListView _fields = UnmodifiableListView([]); List _rows = []; GridRowCache({required this.gridId}); List get rows => _rows; - void updateWithBlock(List blocks) { + void updateWithBlock(List blocks, UnmodifiableListView fields) { + _fields = fields; _rows = blocks.expand((block) => block.rowOrders).map((rowOrder) { return RowData.fromBlockRow(gridId, rowOrder, _fields); }).toList(); } - void updateFields(List fields) { + void updateFields(UnmodifiableListView fields) { if (fields.isEmpty) { return; } diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 7df38179ac..1308e1a67e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -2,7 +2,6 @@ export 'grid_bloc.dart'; export 'row/row_bloc.dart'; export 'row/row_service.dart'; export 'grid_service.dart'; -export 'data.dart'; export 'grid_header_bloc.dart'; // 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 ec9b8ff04d..d6bc43e50e 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 @@ -80,9 +80,9 @@ class RowBloc extends Bloc { ); }); - _fieldCache.addListener((fields) { + _fieldCache.listenOnFieldChanged((fields) { if (!isClosed) { - add(RowEvent.didReceiveFieldUpdate(fields)); + // add(RowEvent.didReceiveFieldUpdate(fields)); } }); 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 cb1cb1c888..5a772693c7 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 @@ -77,7 +77,7 @@ class FlowyGrid extends StatelessWidget { final child = _wrapScrollView( state.fields, [ - _GridHeader(gridId: state.gridId, fields: List.from(state.fields)), + _GridHeader(gridId: state.gridId, fields: state.fields), _GridRows(), const _GridFooter(), ], @@ -150,7 +150,8 @@ class _GridHeader extends StatelessWidget { @override Widget build(BuildContext context) { - return GridHeaderSliverAdaptor(gridId: gridId, fields: fields); + final fieldCache = context.read().fieldCache; + return GridHeaderSliverAdaptor(gridId: gridId, fieldCache: fieldCache); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 3893ac7784..15fb64f990 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -14,18 +14,19 @@ import 'field_cell.dart'; class GridHeaderSliverAdaptor extends StatelessWidget { final String gridId; - final List fields; + final GridFieldCache fieldCache; - const GridHeaderSliverAdaptor({required this.gridId, required this.fields, Key? key}) : super(key: key); + const GridHeaderSliverAdaptor({required this.gridId, required this.fieldCache, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => getIt(param1: gridId, param2: fields)..add(const GridHeaderEvent.initial()), + create: (context) => + getIt(param1: gridId, param2: fieldCache)..add(const GridHeaderEvent.initial()), child: BlocBuilder( builder: (context, state) { return SliverPersistentHeader( - delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: fields), + delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: state.fields), floating: true, pinned: true, ); @@ -77,6 +78,7 @@ class _GridHeader extends StatelessWidget { return BlocBuilder( builder: (context, state) { final cells = state.fields + .where((field) => field.visibility) .map((field) => GridFieldCellContext(gridId: gridId, field: field)) .map((ctx) => GridFieldCell(ctx, key: ValueKey(ctx.field.id))) .toList(); From ac766c0359387d65a70fbb919db23e8d7292c45b Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 14 Apr 2022 21:16:29 +0800 Subject: [PATCH 08/26] chore: fix row rebuild refresh issue --- .../lib/startup/tasks/app_widget.dart | 12 +++++----- .../application/grid/field/grid_listenr.dart | 2 +- .../application/grid/grid_header_bloc.dart | 8 +++---- .../application/grid/grid_service.dart | 11 +++++++++- .../application/grid/row/row_bloc.dart | 18 +++++++-------- .../plugins/grid/src/grid_page.dart | 22 ++++++++++++++----- .../flowy-grid/dart_notification.pbenum.dart | 4 ++-- .../flowy-grid/dart_notification.pbjson.dart | 4 ++-- .../flowy-grid/src/dart_notification.rs | 2 +- .../src/protobuf/model/dart_notification.rs | 12 +++++----- .../protobuf/proto/dart_notification.proto | 2 +- .../flowy-grid/src/services/grid_editor.rs | 2 +- 12 files changed, 59 insertions(+), 40 deletions(-) diff --git a/frontend/app_flowy/lib/startup/tasks/app_widget.dart b/frontend/app_flowy/lib/startup/tasks/app_widget.dart index 3dba94ce0a..1747cfd8ec 100644 --- a/frontend/app_flowy/lib/startup/tasks/app_widget.dart +++ b/frontend/app_flowy/lib/startup/tasks/app_widget.dart @@ -113,7 +113,7 @@ class ApplicationBlocObserver extends BlocObserver { // ignore: unnecessary_overrides void onTransition(Bloc bloc, Transition transition) { // Log.debug("[current]: ${transition.currentState} \n\n[next]: ${transition.nextState}"); - Log.debug("${transition.nextState}"); + // Log.debug("${transition.nextState}"); super.onTransition(bloc, transition); } @@ -123,9 +123,9 @@ class ApplicationBlocObserver extends BlocObserver { super.onError(bloc, error, stackTrace); } - @override - void onEvent(Bloc bloc, Object? event) { - // Log.debug("$event"); - super.onEvent(bloc, event); - } + // @override + // void onEvent(Bloc bloc, Object? event) { + // Log.debug("$event"); + // super.onEvent(bloc, event); + // } } 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 d823207f83..c257fe3c0d 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 @@ -24,7 +24,7 @@ class GridFieldsListener { void _handler(GridNotification ty, Either result) { switch (ty) { - case GridNotification.DidUpdateGrid: + case GridNotification.DidUpdateGridField: result.fold( (payload) => updateFieldsNotifier.value = left(GridFieldChangeset.fromBuffer(payload)), (error) => updateFieldsNotifier.value = right(error), diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index c7ce6c21f1..13f65ff4d6 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -2,20 +2,18 @@ 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'; import 'dart:async'; -import 'field/field_service.dart'; import 'grid_service.dart'; part 'grid_header_bloc.freezed.dart'; class GridHeaderBloc extends Bloc { - final FieldService _fieldService; + // final FieldService _fieldService; final GridFieldCache fieldCache; GridHeaderBloc({ required String gridId, required this.fieldCache, - }) : _fieldService = FieldService(gridId: gridId), - super(GridHeaderState.initial(fieldCache.clonedFields)) { + }) : super(GridHeaderState.initial(fieldCache.clonedFields)) { on( (event, emit) async { await event.map( @@ -31,7 +29,7 @@ class GridHeaderBloc extends Bloc { } Future _startListening() async { - fieldCache.listenOnFieldChanged((fields) { + fieldCache.addListener(() {}, onChanged: (fields) { if (!isClosed) { add(GridHeaderEvent.didReceiveFieldUpdate(fields)); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index fc853ef8b7..b79c2e5e59 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -74,6 +74,15 @@ class GridFieldCache { _fieldNotifier.addListener(() => onFieldChanged(clonedFields)); } + void addListener(VoidCallback listener, {void Function(List)? onChanged}) { + _fieldNotifier.addListener(() { + if (onChanged != null) { + onChanged(clonedFields); + } + listener(); + }); + } + void _removeFields(List deletedFields) { if (deletedFields.isEmpty) { return; @@ -130,7 +139,7 @@ class GridRowCache { GridRowCache({required this.gridId}); - List get rows => _rows; + List get rows => [..._rows]; void updateWithBlock(List blocks, UnmodifiableListView fields) { _fields = fields; 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 d6bc43e50e..dbbe9b054d 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 @@ -34,12 +34,12 @@ class RowBloc extends Bloc { createRow: (_CreateRow value) { _rowService.createRow(); }, - didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) async { - await _handleFieldUpdate(emit, value); - }, didUpdateRow: (_DidUpdateRow value) async { _handleRowUpdate(value, emit); }, + fieldsDidUpdate: (_FieldsDidUpdate value) async { + await _handleFieldUpdate(emit); + }, ); }, ); @@ -53,15 +53,15 @@ class RowBloc extends Bloc { )); } - Future _handleFieldUpdate(Emitter emit, _DidReceiveFieldUpdate value) async { + Future _handleFieldUpdate(Emitter emit) async { final optionRow = await state.row; final CellDataMap cellDataMap = optionRow.fold( () => CellDataMap.identity(), - (row) => _makeCellDatas(row, value.fields), + (row) => _makeCellDatas(row, _fieldCache.unmodifiableFields), ); emit(state.copyWith( - rowData: state.rowData.copyWith(fields: value.fields), + rowData: state.rowData.copyWith(fields: _fieldCache.unmodifiableFields), cellDataMap: Some(cellDataMap), )); } @@ -80,9 +80,9 @@ class RowBloc extends Bloc { ); }); - _fieldCache.listenOnFieldChanged((fields) { + _fieldCache.addListener(() { if (!isClosed) { - // add(RowEvent.didReceiveFieldUpdate(fields)); + add(const RowEvent.fieldsDidUpdate()); } }); @@ -118,7 +118,7 @@ class RowBloc extends Bloc { class RowEvent with _$RowEvent { const factory RowEvent.initial() = _InitialRow; const factory RowEvent.createRow() = _CreateRow; - const factory RowEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; + const factory RowEvent.fieldsDidUpdate() = _FieldsDidUpdate; const factory RowEvent.didUpdateRow(Row row) = _DidUpdateRow; } 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 5a772693c7..a3f8a3e064 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 @@ -40,7 +40,7 @@ class _GridPageState extends State { return state.loadingState.map( loading: (_) => const Center(child: CircularProgressIndicator.adaptive()), finish: (result) => result.successOrFail.fold( - (_) => FlowyGrid(), + (_) => const FlowyGrid(), (err) => FlowyErrorPage(err.toString()), ), ); @@ -65,9 +65,15 @@ class _GridPageState extends State { } } -class FlowyGrid extends StatelessWidget { +class FlowyGrid extends StatefulWidget { + const FlowyGrid({Key? key}) : super(key: key); + + @override + State createState() => _FlowyGridState(); +} + +class _FlowyGridState extends State { final _scrollController = GridScrollController(); - FlowyGrid({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -155,9 +161,15 @@ class _GridHeader extends StatelessWidget { } } -class _GridRows extends StatelessWidget { +class _GridRows extends StatefulWidget { + const _GridRows({Key? key}) : super(key: key); + + @override + State<_GridRows> createState() => _GridRowsState(); +} + +class _GridRowsState extends State<_GridRows> { final _key = GlobalKey(); - _GridRows({Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart index d39002e540..7b43def65e 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart @@ -15,7 +15,7 @@ class GridNotification extends $pb.ProtobufEnum { static const GridNotification DidUpdateGridBlock = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridBlock'); static const GridNotification DidUpdateRow = GridNotification._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateRow'); static const GridNotification DidUpdateCell = GridNotification._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateCell'); - static const GridNotification DidUpdateGrid = GridNotification._(40, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGrid'); + static const GridNotification DidUpdateGridField = GridNotification._(40, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridField'); static const GridNotification DidUpdateField = GridNotification._(41, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateField'); static const $core.List values = [ @@ -24,7 +24,7 @@ class GridNotification extends $pb.ProtobufEnum { DidUpdateGridBlock, DidUpdateRow, DidUpdateCell, - DidUpdateGrid, + DidUpdateGridField, DidUpdateField, ]; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart index 787a77ffa1..8c262092db 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart @@ -17,10 +17,10 @@ const GridNotification$json = const { const {'1': 'DidUpdateGridBlock', '2': 20}, const {'1': 'DidUpdateRow', '2': 30}, const {'1': 'DidUpdateCell', '2': 31}, - const {'1': 'DidUpdateGrid', '2': 40}, + const {'1': 'DidUpdateGridField', '2': 40}, const {'1': 'DidUpdateField', '2': 41}, ], }; /// Descriptor for `GridNotification`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhYKEkRpZFVwZGF0ZUdyaWRCbG9jaxAUEhAKDERpZFVwZGF0ZVJvdxAeEhEKDURpZFVwZGF0ZUNlbGwQHxIRCg1EaWRVcGRhdGVHcmlkECgSEgoORGlkVXBkYXRlRmllbGQQKQ=='); +final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhYKEkRpZFVwZGF0ZUdyaWRCbG9jaxAUEhAKDERpZFVwZGF0ZVJvdxAeEhEKDURpZFVwZGF0ZUNlbGwQHxIWChJEaWRVcGRhdGVHcmlkRmllbGQQKBISCg5EaWRVcGRhdGVGaWVsZBAp'); diff --git a/frontend/rust-lib/flowy-grid/src/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/dart_notification.rs index a2a1de0a9f..156ba9058a 100644 --- a/frontend/rust-lib/flowy-grid/src/dart_notification.rs +++ b/frontend/rust-lib/flowy-grid/src/dart_notification.rs @@ -9,7 +9,7 @@ pub enum GridNotification { DidUpdateGridBlock = 20, DidUpdateRow = 30, DidUpdateCell = 31, - DidUpdateGrid = 40, + DidUpdateGridField = 40, DidUpdateField = 41, } diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs index 326ae3ef4e..338737c643 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs @@ -30,7 +30,7 @@ pub enum GridNotification { DidUpdateGridBlock = 20, DidUpdateRow = 30, DidUpdateCell = 31, - DidUpdateGrid = 40, + DidUpdateGridField = 40, DidUpdateField = 41, } @@ -46,7 +46,7 @@ impl ::protobuf::ProtobufEnum for GridNotification { 20 => ::std::option::Option::Some(GridNotification::DidUpdateGridBlock), 30 => ::std::option::Option::Some(GridNotification::DidUpdateRow), 31 => ::std::option::Option::Some(GridNotification::DidUpdateCell), - 40 => ::std::option::Option::Some(GridNotification::DidUpdateGrid), + 40 => ::std::option::Option::Some(GridNotification::DidUpdateGridField), 41 => ::std::option::Option::Some(GridNotification::DidUpdateField), _ => ::std::option::Option::None } @@ -59,7 +59,7 @@ impl ::protobuf::ProtobufEnum for GridNotification { GridNotification::DidUpdateGridBlock, GridNotification::DidUpdateRow, GridNotification::DidUpdateCell, - GridNotification::DidUpdateGrid, + GridNotification::DidUpdateGridField, GridNotification::DidUpdateField, ]; values @@ -89,11 +89,11 @@ impl ::protobuf::reflect::ProtobufValue for GridNotification { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x17dart_notification.proto*\x97\x01\n\x10GridNotification\x12\x0b\n\ + \n\x17dart_notification.proto*\x9c\x01\n\x10GridNotification\x12\x0b\n\ \x07Unknown\x10\0\x12\x12\n\x0eDidCreateBlock\x10\x0b\x12\x16\n\x12DidUp\ dateGridBlock\x10\x14\x12\x10\n\x0cDidUpdateRow\x10\x1e\x12\x11\n\rDidUp\ - dateCell\x10\x1f\x12\x11\n\rDidUpdateGrid\x10(\x12\x12\n\x0eDidUpdateFie\ - ld\x10)b\x06proto3\ + dateCell\x10\x1f\x12\x16\n\x12DidUpdateGridField\x10(\x12\x12\n\x0eDidUp\ + dateField\x10)b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto index 20cf529f3e..a4e5188346 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto @@ -6,6 +6,6 @@ enum GridNotification { DidUpdateGridBlock = 20; DidUpdateRow = 30; DidUpdateCell = 31; - DidUpdateGrid = 40; + DidUpdateGridField = 40; DidUpdateField = 41; } 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 5cd4ebca87..357c38ba0e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -473,7 +473,7 @@ impl ClientGridEditor { } async fn notify_did_update_grid(&self, changeset: GridFieldChangeset) -> FlowyResult<()> { - send_dart_notification(&self.grid_id, GridNotification::DidUpdateGrid) + send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridField) .payload(changeset) .send(); Ok(()) From b282a14b58aa7a0e19aad5b9ff5386f6c7754c41 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 14 Apr 2022 21:57:00 +0800 Subject: [PATCH 09/26] chore: add sync feature --- frontend/rust-lib/dart-ffi/Cargo.toml | 2 +- frontend/rust-lib/flowy-folder/Cargo.toml | 3 +- .../src/services/folder_editor.rs | 43 ++++++++++++------- .../flowy-folder/src/services/web_socket.rs | 1 + .../field/type_options/date_type_option.rs | 2 +- .../flowy-grid/src/services/grid_editor.rs | 2 +- frontend/rust-lib/flowy-sdk/Cargo.toml | 3 +- frontend/rust-lib/flowy-sdk/src/lib.rs | 2 +- frontend/rust-lib/flowy-text-block/Cargo.toml | 3 +- .../rust-lib/flowy-text-block/src/editor.rs | 25 ++++++++--- .../flowy-text-block/src/web_socket.rs | 3 ++ frontend/rust-lib/flowy-user/Cargo.toml | 1 - .../src/client_grid/grid_meta_pad.rs | 6 +-- 13 files changed, 62 insertions(+), 34 deletions(-) diff --git a/frontend/rust-lib/dart-ffi/Cargo.toml b/frontend/rust-lib/dart-ffi/Cargo.toml index df26694331..bbc3c3f35b 100644 --- a/frontend/rust-lib/dart-ffi/Cargo.toml +++ b/frontend/rust-lib/dart-ffi/Cargo.toml @@ -31,7 +31,7 @@ flowy-derive = {path = "../../../shared-lib/flowy-derive" } [features] default = ["flowy-sdk/dart", "dart-notify/dart", "flutter"] flutter = [] -http_server = ["flowy-sdk/http_server", "flowy-sdk/use_bunyan"] +http_sync = ["flowy-sdk/http_sync", "flowy-sdk/use_bunyan"] #use_serde = ["bincode"] #use_protobuf= ["protobuf"] diff --git a/frontend/rust-lib/flowy-folder/Cargo.toml b/frontend/rust-lib/flowy-folder/Cargo.toml index 9605212726..ddc6f1f586 100644 --- a/frontend/rust-lib/flowy-folder/Cargo.toml +++ b/frontend/rust-lib/flowy-folder/Cargo.toml @@ -44,6 +44,7 @@ lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file [features] default = [] -http_server = [] +sync = [] +cloud_sync = ["sync"] flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-revision/flowy_unit_test"] dart = ["lib-infra/dart"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs index b7c30919b6..6ea1a7e2ec 100644 --- a/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs +++ b/frontend/rust-lib/flowy-folder/src/services/folder_editor.rs @@ -1,4 +1,3 @@ -use crate::services::web_socket::make_folder_ws_manager; use flowy_sync::{ client_folder::{FolderChange, FolderPad}, entities::{revision::Revision, ws_data::ServerRevisionWSData}, @@ -11,7 +10,6 @@ use flowy_sync::util::make_delta_from_revisions; use flowy_revision::{ RevisionCloudService, RevisionCompactor, RevisionManager, RevisionObjectBuilder, RevisionWebSocket, - RevisionWebSocketManager, }; use lib_infra::future::FutureResult; use lib_ot::core::PlainTextAttributes; @@ -21,13 +19,16 @@ use std::sync::Arc; pub struct ClientFolderEditor { user_id: String, + #[allow(dead_code)] pub(crate) folder_id: FolderId, pub(crate) folder: Arc>, rev_manager: Arc, - // ws_manager: Arc, + #[cfg(feature = "sync")] + ws_manager: Arc, } impl ClientFolderEditor { + #[allow(unused_variables)] pub async fn new( user_id: &str, folder_id: &FolderId, @@ -40,14 +41,16 @@ impl ClientFolderEditor { }); let folder = Arc::new(RwLock::new(rev_manager.load::(Some(cloud)).await?)); let rev_manager = Arc::new(rev_manager); - // let ws_manager = make_folder_ws_manager( - // user_id, - // folder_id.as_ref(), - // rev_manager.clone(), - // web_socket, - // folder.clone(), - // ) - // .await; + + #[cfg(feature = "sync")] + let ws_manager = crate::services::web_socket::make_folder_ws_manager( + user_id, + folder_id.as_ref(), + rev_manager.clone(), + web_socket, + folder.clone(), + ) + .await; let user_id = user_id.to_owned(); let folder_id = folder_id.to_owned(); @@ -56,15 +59,23 @@ impl ClientFolderEditor { folder_id, folder, rev_manager, - // ws_manager, + #[cfg(feature = "sync")] + ws_manager, }) } + #[cfg(feature = "sync")] pub async fn receive_ws_data(&self, data: ServerRevisionWSData) -> FlowyResult<()> { - // let _ = self.ws_manager.ws_passthrough_tx.send(data).await.map_err(|e| { - // let err_msg = format!("{} passthrough error: {}", self.folder_id, e); - // FlowyError::internal().context(err_msg) - // })?; + let _ = self.ws_manager.ws_passthrough_tx.send(data).await.map_err(|e| { + let err_msg = format!("{} passthrough error: {}", self.folder_id, e); + FlowyError::internal().context(err_msg) + })?; + + Ok(()) + } + + #[cfg(not(feature = "sync"))] + pub async fn receive_ws_data(&self, _data: ServerRevisionWSData) -> FlowyResult<()> { Ok(()) } diff --git a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs index c14db04d3f..75db905d63 100644 --- a/frontend/rust-lib/flowy-folder/src/services/web_socket.rs +++ b/frontend/rust-lib/flowy-folder/src/services/web_socket.rs @@ -14,6 +14,7 @@ use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta}; use parking_lot::RwLock; use std::{sync::Arc, time::Duration}; +#[allow(dead_code)] pub(crate) async fn make_folder_ws_manager( user_id: &str, folder_id: &str, diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index c4ef4614f1..81e77f2645 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -47,7 +47,7 @@ impl DateTypeOption { if self.include_time { format!("{} {}", self.date_format.format_str(), self.time_format.format_str()) } else { - format!("{}", self.date_format.format_str()) + self.date_format.format_str().to_string() } } } 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 357c38ba0e..41a70d8549 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -153,7 +153,7 @@ impl ClientGridEditor { .modify(|grid| Ok(grid.switch_to_field(field_id, field_type.clone(), type_option_json_builder)?)) .await?; - let _ = self.notify_grid_did_update_field(&field_id).await?; + let _ = self.notify_grid_did_update_field(field_id).await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-sdk/Cargo.toml b/frontend/rust-lib/flowy-sdk/Cargo.toml index 9ac3bef2f6..2ffb444962 100644 --- a/frontend/rust-lib/flowy-sdk/Cargo.toml +++ b/frontend/rust-lib/flowy-sdk/Cargo.toml @@ -38,6 +38,7 @@ tokio = { version = "1", features = ["full"]} futures-util = "0.3.15" [features] -http_server = ["flowy-user/http_server", "flowy-folder/http_server", "flowy-text-block/http_server"] +http_sync = ["flowy-folder/cloud_sync", "flowy-text-block/cloud_sync"] +native_sync = ["flowy-folder/cloud_sync", "flowy-text-block/cloud_sync"] use_bunyan = ["lib-log/use_bunyan"] dart = ["flowy-user/dart", "flowy-net/dart", "flowy-folder/dart", "flowy-sync/dart", "flowy-grid/dart", "flowy-text-block/dart"] diff --git a/frontend/rust-lib/flowy-sdk/src/lib.rs b/frontend/rust-lib/flowy-sdk/src/lib.rs index 06a140805e..b426b40550 100644 --- a/frontend/rust-lib/flowy-sdk/src/lib.rs +++ b/frontend/rust-lib/flowy-sdk/src/lib.rs @@ -193,7 +193,7 @@ fn mk_local_server( server_config: &ClientServerConfiguration, ) -> (Option>, Arc) { let ws_addr = server_config.ws_addr(); - if cfg!(feature = "http_server") { + if cfg!(feature = "http_sync") { let ws_conn = Arc::new(FlowyWebSocketConnect::new(ws_addr)); (None, ws_conn) } else { diff --git a/frontend/rust-lib/flowy-text-block/Cargo.toml b/frontend/rust-lib/flowy-text-block/Cargo.toml index 84c0cf9605..d9180a97bf 100644 --- a/frontend/rust-lib/flowy-text-block/Cargo.toml +++ b/frontend/rust-lib/flowy-text-block/Cargo.toml @@ -51,6 +51,7 @@ rand = "0.7.3" lib-infra = { path = "../../../shared-lib/lib-infra", features = ["protobuf_file_gen", "proto_gen"] } [features] -http_server = [] +sync = [] +cloud_sync = ["sync"] flowy_unit_test = ["lib-ot/flowy_unit_test", "flowy-revision/flowy_unit_test"] dart = ["lib-infra/dart"] \ No newline at end of file diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 215c3d079d..55160010bf 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -1,4 +1,4 @@ -use crate::web_socket::{make_block_ws_manager, EditorCommandSender}; +use crate::web_socket::EditorCommandSender; use crate::{ errors::FlowyError, queue::{EditBlockQueue, EditorCommand}, @@ -6,9 +6,7 @@ use crate::{ }; use bytes::Bytes; use flowy_error::{internal_error, FlowyResult}; -use flowy_revision::{ - RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket, RevisionWebSocketManager, -}; +use flowy_revision::{RevisionCloudService, RevisionManager, RevisionObjectBuilder, RevisionWebSocket}; use flowy_sync::entities::ws_data::ServerRevisionWSData; use flowy_sync::{ entities::{revision::Revision, text_block_info::TextBlockInfo}, @@ -27,6 +25,7 @@ pub struct ClientTextBlockEditor { pub doc_id: String, #[allow(dead_code)] rev_manager: Arc, + #[cfg(feature = "sync")] ws_manager: Arc, edit_cmd_tx: EditorCommandSender, } @@ -36,16 +35,17 @@ impl ClientTextBlockEditor { doc_id: &str, user: Arc, mut rev_manager: RevisionManager, - rev_web_socket: Arc, + _rev_web_socket: Arc, cloud_service: Arc, ) -> FlowyResult> { let document_info = rev_manager.load::(Some(cloud_service)).await?; let delta = document_info.delta()?; let rev_manager = Arc::new(rev_manager); let doc_id = doc_id.to_string(); - let user_id = user.user_id()?; + let _user_id = user.user_id()?; let edit_cmd_tx = spawn_edit_queue(user, rev_manager.clone(), delta); + #[cfg(feature = "sync")] let ws_manager = make_block_ws_manager( doc_id.clone(), user_id.clone(), @@ -57,6 +57,7 @@ impl ClientTextBlockEditor { let editor = Arc::new(Self { doc_id, rev_manager, + #[cfg(feature = "sync")] ws_manager, edit_cmd_tx, }); @@ -158,17 +159,29 @@ impl ClientTextBlockEditor { Ok(()) } + #[cfg(feature = "sync")] pub fn stop(&self) { self.ws_manager.stop(); } + #[cfg(not(feature = "sync"))] + pub fn stop(&self) {} + + #[cfg(feature = "sync")] pub(crate) async fn receive_ws_data(&self, data: ServerRevisionWSData) -> Result<(), FlowyError> { self.ws_manager.receive_ws_data(data).await } + #[cfg(not(feature = "sync"))] + pub(crate) async fn receive_ws_data(&self, _data: ServerRevisionWSData) -> Result<(), FlowyError> { + Ok(()) + } + #[cfg(feature = "sync")] pub(crate) fn receive_ws_state(&self, state: &WSConnectState) { self.ws_manager.connect_state_changed(state.clone()); } + #[cfg(not(feature = "sync"))] + pub(crate) fn receive_ws_state(&self, _state: &WSConnectState) {} } impl std::ops::Drop for ClientTextBlockEditor { diff --git a/frontend/rust-lib/flowy-text-block/src/web_socket.rs b/frontend/rust-lib/flowy-text-block/src/web_socket.rs index 8854acfd9f..a44214f4f2 100644 --- a/frontend/rust-lib/flowy-text-block/src/web_socket.rs +++ b/frontend/rust-lib/flowy-text-block/src/web_socket.rs @@ -23,6 +23,7 @@ use tokio::sync::{ pub(crate) type EditorCommandSender = Sender; pub(crate) type EditorCommandReceiver = Receiver; +#[allow(dead_code)] pub(crate) async fn make_block_ws_manager( doc_id: String, user_id: String, @@ -49,6 +50,7 @@ pub(crate) async fn make_block_ws_manager( ws_manager } +#[allow(dead_code)] fn listen_document_ws_state(_user_id: &str, _doc_id: &str, mut subscriber: broadcast::Receiver) { tokio::spawn(async move { while let Ok(state) = subscriber.recv().await { @@ -67,6 +69,7 @@ pub(crate) struct TextBlockRevisionWSDataStream { } impl TextBlockRevisionWSDataStream { + #[allow(dead_code)] pub fn new(conflict_controller: RichTextConflictController) -> Self { Self { conflict_controller: Arc::new(conflict_controller), diff --git a/frontend/rust-lib/flowy-user/Cargo.toml b/frontend/rust-lib/flowy-user/Cargo.toml index d6f52e6d73..96e6141ed6 100644 --- a/frontend/rust-lib/flowy-user/Cargo.toml +++ b/frontend/rust-lib/flowy-user/Cargo.toml @@ -37,7 +37,6 @@ futures = "0.3.15" nanoid = "0.4.0" [features] -http_server = [] dart = ["lib-infra/dart"] [build-dependencies] diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index ebc5483b5b..5c59437d4f 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -3,13 +3,11 @@ use crate::errors::{internal_error, CollaborateError, CollaborateResult}; use crate::util::{cal_diff, make_delta_from_revisions}; use bytes::Bytes; use flowy_grid_data_model::entities::{ - gen_field_id, gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, - GridBlockMetaChangeset, GridMeta, IndexField, + gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, GridBlockMetaChangeset, + GridMeta, }; use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder}; use std::collections::HashMap; - -use futures::StreamExt; use std::sync::Arc; pub type GridMetaDelta = PlainTextDelta; From a81db92ee1738274e919d9c7836f5cb105f41a34 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 14 Apr 2022 21:57:51 +0800 Subject: [PATCH 10/26] chore: fix warnings --- .../lib/workspace/presentation/plugins/grid/src/grid_page.dart | 2 +- .../plugins/grid/src/widgets/footer/grid_footer.dart | 1 - .../plugins/grid/src/widgets/header/field_cell.dart | 1 - .../plugins/grid/src/widgets/toolbar/grid_property.dart | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index a3f8a3e064..790dc0f83c 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 @@ -84,7 +84,7 @@ class _FlowyGridState extends State { state.fields, [ _GridHeader(gridId: state.gridId, fields: state.fields), - _GridRows(), + const _GridRows(), const _GridFooter(), ], ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart index a99e87f5fa..6ed8700cfc 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart @@ -1,5 +1,4 @@ import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index 83fcade362..e9fa11d883 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -6,7 +6,6 @@ import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/hover.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'; import 'field_type_extension.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index 0a9cddedd5..54e2d5e97a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -10,7 +10,6 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; From 676dffbf2131809808ec4979e195b1ee86cae1c9 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 15 Apr 2022 10:24:59 +0800 Subject: [PATCH 11/26] chore: reorder fields --- .../grid/setting/property_bloc.dart | 9 +++++-- .../grid/src/widgets/header/grid_header.dart | 27 ++++++++++++------- .../src/widgets/toolbar/grid_property.dart | 14 ++++++---- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index 140aa388cd..0ec31d08b6 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart'; +import 'package:app_flowy/workspace/application/grid/grid_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'; @@ -11,10 +12,12 @@ part 'property_bloc.freezed.dart'; class GridPropertyBloc extends Bloc { final FieldService _service; final GridFieldsListener _fieldListener; + final GridFieldCache _fieldCache; GridPropertyBloc({required String gridId, required List fields}) : _service = FieldService(gridId: gridId), _fieldListener = GridFieldsListener(gridId: gridId), + _fieldCache = GridFieldCache(), super(GridPropertyState.initial(gridId, fields)) { on( (event, emit) async { @@ -43,14 +46,16 @@ class GridPropertyBloc extends Bloc { @override Future close() async { await _fieldListener.stop(); + _fieldCache.dispose(); return super.close(); } void _startListening() { _fieldListener.updateFieldsNotifier.addPublishListener((result) { result.fold( - (fields) { - // add(GridPropertyEvent.didReceiveFieldUpdate(fields)); + (changeset) { + _fieldCache.applyChangeset(changeset); + add(GridPropertyEvent.didReceiveFieldUpdate(_fieldCache.clonedFields)); }, (err) => Log.error(err), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 15fb64f990..dcf5702f40 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -5,10 +5,11 @@ import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; - +import 'package:reorderables/reorderables.dart'; import 'field_editor.dart'; import 'field_cell.dart'; @@ -62,7 +63,7 @@ class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate } } -class _GridHeader extends StatelessWidget { +class _GridHeader extends StatefulWidget { final String gridId; final List fields; @@ -72,26 +73,34 @@ class _GridHeader extends StatelessWidget { required this.fields, }) : super(key: key); + @override + State<_GridHeader> createState() => _GridHeaderState(); +} + +class _GridHeaderState extends State<_GridHeader> { @override Widget build(BuildContext context) { final theme = context.watch(); return BlocBuilder( + buildWhen: (previous, current) => previous.fields != current.fields, builder: (context, state) { final cells = state.fields .where((field) => field.visibility) - .map((field) => GridFieldCellContext(gridId: gridId, field: field)) + .map((field) => GridFieldCellContext(gridId: widget.gridId, field: field)) .map((ctx) => GridFieldCell(ctx, key: ValueKey(ctx.field.id))) .toList(); return Container( color: theme.surface, - child: Row( + child: ReorderableRow( crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const _CellLeading(), - ...cells, - _CellTrailing(gridId: gridId), - ], + scrollController: ScrollController(), + header: const _CellLeading(), + footer: _CellTrailing(gridId: widget.gridId), + onReorder: (int oldIndex, int newIndex) { + Log.info("from $oldIndex to $newIndex"); + }, + children: cells, ), ); }, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index 54e2d5e97a..75898d5ba7 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -10,6 +10,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -45,16 +46,19 @@ class GridPropertyList extends StatelessWidget with FlowyOverlayDelegate { getIt(param1: gridId, param2: fields)..add(const GridPropertyEvent.initial()), child: BlocBuilder( builder: (context, state) { - final children = state.fields.map((field) { + final cells = state.fields.map((field) { return _GridPropertyCell(gridId: gridId, field: field, key: ValueKey(field.id)); }).toList(); - return ReorderableListView( + return ListView.separated( shrinkWrap: true, - onReorder: (int oldIndex, int newIndex) { - context.read().add(GridPropertyEvent.moveField(oldIndex, newIndex)); + itemCount: cells.length, + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + separatorBuilder: (BuildContext context, int index) { + return VSpace(GridSize.typeOptionSeparatorHeight); }, - children: children, ); }, ), From d71e0de8c32673071847eb9a804cc8313a94b4cf Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 15 Apr 2022 14:21:32 +0800 Subject: [PATCH 12/26] chore: set notifier to null after dispose --- .../application/grid/cell_bloc/cell_listener.dart | 9 +++++---- .../application/grid/cell_bloc/checkbox_cell_bloc.dart | 2 +- .../application/grid/cell_bloc/date_cell_bloc.dart | 4 ++-- .../application/grid/cell_bloc/number_cell_bloc.dart | 4 ++-- .../application/grid/cell_bloc/selection_cell_bloc.dart | 4 ++-- .../grid/cell_bloc/selection_editor_bloc.dart | 4 ++-- .../application/grid/field/field_cell_bloc.dart | 2 +- .../workspace/application/grid/field/field_listener.dart | 9 +++++---- .../workspace/application/grid/field/grid_listenr.dart | 9 +++++---- .../lib/workspace/application/grid/grid_bloc.dart | 2 +- .../lib/workspace/application/grid/row/row_bloc.dart | 2 +- .../lib/workspace/application/grid/row/row_listener.dart | 9 +++++---- .../application/grid/setting/property_bloc.dart | 2 +- .../plugins/grid/src/widgets/header/grid_header.dart | 3 ++- 14 files changed, 35 insertions(+), 30 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_listener.dart index d1fb0acc0c..314345017e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_listener.dart @@ -12,7 +12,7 @@ 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}); @@ -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(CellNotificationData.fromBuffer(payload)), + (error) => updateCellNotifier?.value = right(error), ); break; default: @@ -35,6 +35,7 @@ class CellListener { Future stop() async { await _listener?.stop(); - updateCellNotifier.dispose(); + updateCellNotifier?.dispose(); + updateCellNotifier = null; } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart index 0f56b9c53c..2d937b8cd2 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart @@ -43,7 +43,7 @@ class CheckboxCellBloc extends Bloc { } void _startListening() { - _listener.updateCellNotifier.addPublishListener((result) { + _listener.updateCellNotifier?.addPublishListener((result) { result.fold( (notificationData) async => await _loadCellData(), (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart index 7dd58bf5ac..b4b6d7e152 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart @@ -52,7 +52,7 @@ class DateCellBloc extends Bloc { } void _startListening() { - _cellListener.updateCellNotifier.addPublishListener((result) { + _cellListener.updateCellNotifier?.addPublishListener((result) { result.fold( (notificationData) => _loadCellData(), (err) => Log.error(err), @@ -60,7 +60,7 @@ class DateCellBloc extends Bloc { }); _cellListener.start(); - _fieldListener.updateFieldNotifier.addPublishListener((result) { + _fieldListener.updateFieldNotifier?.addPublishListener((result) { result.fold( (field) { if (!isClosed) { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart index a145305bbe..287d70b701 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart @@ -59,7 +59,7 @@ class NumberCellBloc extends Bloc { } void _startListening() { - _cellListener.updateCellNotifier.addPublishListener((result) { + _cellListener.updateCellNotifier?.addPublishListener((result) { result.fold( (notificationData) async { await _getCellData(); @@ -69,7 +69,7 @@ class NumberCellBloc extends Bloc { }); _cellListener.start(); - _fieldListener.updateFieldNotifier.addPublishListener((result) { + _fieldListener.updateFieldNotifier?.addPublishListener((result) { result.fold( (field) => _getCellData(), (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart index b7e472e181..dbca1b5ae3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart @@ -64,7 +64,7 @@ class SelectionCellBloc extends Bloc { } void _startListening() { - _cellListener.updateCellNotifier.addPublishListener((result) { + _cellListener.updateCellNotifier?.addPublishListener((result) { result.fold( (notificationData) => _loadOptions(), (err) => Log.error(err), @@ -72,7 +72,7 @@ class SelectionCellBloc extends Bloc { }); _cellListener.start(); - _fieldListener.updateFieldNotifier.addPublishListener((result) { + _fieldListener.updateFieldNotifier?.addPublishListener((result) { result.fold( (field) => _loadOptions(), (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart index 5d2c52dc0e..813b779646 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart @@ -134,7 +134,7 @@ class SelectOptionEditorBloc extends Bloc _loadOptions(), (err) => Log.error(err), @@ -142,7 +142,7 @@ class SelectOptionEditorBloc extends Bloc { } void _startListening() { - _fieldListener.updateFieldNotifier.addPublishListener((result) { + _fieldListener.updateFieldNotifier?.addPublishListener((result) { result.fold( (field) { if (!isClosed) { 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 450d88fe18..b31a9c3ff5 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,7 +11,7 @@ typedef UpdateFieldNotifiedValue = Either; class SingleFieldListener { final String fieldId; - PublishNotifier updateFieldNotifier = PublishNotifier(); + PublishNotifier? updateFieldNotifier = PublishNotifier(); GridNotificationListener? _listener; SingleFieldListener({required this.fieldId}); @@ -30,8 +30,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,6 +41,7 @@ class SingleFieldListener { Future stop() async { await _listener?.stop(); - updateFieldNotifier.dispose(); + 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 c257fe3c0d..6774205a5e 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 @@ -11,7 +11,7 @@ typedef UpdateFieldNotifiedValue = Either; class GridFieldsListener { final String gridId; - PublishNotifier updateFieldsNotifier = PublishNotifier(); + PublishNotifier? updateFieldsNotifier = PublishNotifier(); GridNotificationListener? _listener; GridFieldsListener({required this.gridId}); @@ -26,8 +26,8 @@ class GridFieldsListener { switch (ty) { case GridNotification.DidUpdateGridField: result.fold( - (payload) => updateFieldsNotifier.value = left(GridFieldChangeset.fromBuffer(payload)), - (error) => updateFieldsNotifier.value = right(error), + (payload) => updateFieldsNotifier?.value = left(GridFieldChangeset.fromBuffer(payload)), + (error) => updateFieldsNotifier?.value = right(error), ); break; default: @@ -37,6 +37,7 @@ class GridFieldsListener { Future stop() async { await _listener?.stop(); - updateFieldsNotifier.dispose(); + updateFieldsNotifier?.dispose(); + updateFieldsNotifier = null; } } 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 882b3eb5b4..c37c31ec46 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -58,7 +58,7 @@ class GridBloc extends Bloc { } void _startListening() { - _fieldListener.updateFieldsNotifier.addPublishListener((result) { + _fieldListener.updateFieldsNotifier?.addPublishListener((result) { result.fold( (changeset) { fieldCache.applyChangeset(changeset); 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 dbbe9b054d..b16d75dc92 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 @@ -73,7 +73,7 @@ class RowBloc extends Bloc { } Future _startListening() async { - _rowlistener.updateRowNotifier.addPublishListener((result) { + _rowlistener.updateRowNotifier?.addPublishListener((result) { result.fold( (row) => add(RowEvent.didUpdateRow(row)), (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart index 716d252802..7d947b8482 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_listener.dart @@ -12,7 +12,7 @@ typedef UpdateFieldNotifiedValue = Either, FlowyError>; class RowListener { final String rowId; - PublishNotifier updateRowNotifier = PublishNotifier(); + PublishNotifier? updateRowNotifier = PublishNotifier(); GridNotificationListener? _listener; RowListener({required this.rowId}); @@ -25,8 +25,8 @@ class RowListener { switch (ty) { case GridNotification.DidUpdateRow: result.fold( - (payload) => updateRowNotifier.value = left(Row.fromBuffer(payload)), - (error) => updateRowNotifier.value = right(error), + (payload) => updateRowNotifier?.value = left(Row.fromBuffer(payload)), + (error) => updateRowNotifier?.value = right(error), ); break; default: @@ -36,6 +36,7 @@ class RowListener { Future stop() async { await _listener?.stop(); - updateRowNotifier.dispose(); + updateRowNotifier?.dispose(); + updateRowNotifier = null; } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index 0ec31d08b6..634bb1e56d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -51,7 +51,7 @@ class GridPropertyBloc extends Bloc { } void _startListening() { - _fieldListener.updateFieldsNotifier.addPublishListener((result) { + _fieldListener.updateFieldsNotifier?.addPublishListener((result) { result.fold( (changeset) { _fieldCache.applyChangeset(changeset); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index dcf5702f40..a00b9e6295 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -25,6 +25,7 @@ class GridHeaderSliverAdaptor extends StatelessWidget { create: (context) => getIt(param1: gridId, param2: fieldCache)..add(const GridHeaderEvent.initial()), child: BlocBuilder( + buildWhen: (previous, current) => previous.fields.length != current.fields.length, builder: (context, state) { return SliverPersistentHeader( delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: state.fields), @@ -45,7 +46,7 @@ class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - return _GridHeader(gridId: gridId, fields: fields, key: ObjectKey(fields)); + return _GridHeader(gridId: gridId, fields: fields); } @override From 6dbb70899129fc7578bf9996d917a1d8c890cf8e Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 15 Apr 2022 15:41:55 +0800 Subject: [PATCH 13/26] chore: repalce sliver header with single scroll view --- .../application/grid/grid_header_bloc.dart | 8 ++- .../grid/src/controller/grid_scroll.dart | 27 +++++---- .../plugins/grid/src/grid_page.dart | 43 +++++++------ .../grid/src/widgets/header/grid_header.dart | 60 +++++++++++-------- frontend/app_flowy/pubspec.lock | 7 +++ frontend/app_flowy/pubspec.yaml | 1 + 6 files changed, 93 insertions(+), 53 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index 13f65ff4d6..8ea390d7ab 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -1,3 +1,4 @@ +import 'package:app_flowy/workspace/application/grid/field/field_service.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'; @@ -7,13 +8,14 @@ import 'grid_service.dart'; part 'grid_header_bloc.freezed.dart'; class GridHeaderBloc extends Bloc { - // final FieldService _fieldService; + final FieldService _fieldService; final GridFieldCache fieldCache; GridHeaderBloc({ required String gridId, required this.fieldCache, - }) : super(GridHeaderState.initial(fieldCache.clonedFields)) { + }) : _fieldService = FieldService(gridId: gridId), + super(GridHeaderState.initial(fieldCache.clonedFields)) { on( (event, emit) async { await event.map( @@ -23,6 +25,7 @@ class GridHeaderBloc extends Bloc { didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { emit(state.copyWith(fields: value.fields)); }, + moveField: (_MoveField value) {}, ); }, ); @@ -46,6 +49,7 @@ class GridHeaderBloc extends Bloc { class GridHeaderEvent with _$GridHeaderEvent { const factory GridHeaderEvent.initial() = _InitialHeader; const factory GridHeaderEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; + const factory GridHeaderEvent.moveField(int fromIndex, int toIndex) = _MoveField; } @freezed diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/grid_scroll.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/grid_scroll.dart index 213b16cfae..dddd93d175 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/grid_scroll.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/grid_scroll.dart @@ -1,21 +1,28 @@ import 'package:flutter/material.dart'; +import 'package:linked_scroll_controller/linked_scroll_controller.dart'; class GridScrollController { - final ScrollController _verticalController = ScrollController(); - final ScrollController _horizontalController = ScrollController(); + final LinkedScrollControllerGroup _scrollGroupContorller; + final ScrollController verticalController; + final ScrollController horizontalController; - ScrollController get verticalController => _verticalController; - ScrollController get horizontalController => _horizontalController; + final List _linkHorizontalControllers = []; - GridScrollController(); + GridScrollController({required LinkedScrollControllerGroup scrollGroupContorller}) + : _scrollGroupContorller = scrollGroupContorller, + verticalController = ScrollController(), + horizontalController = scrollGroupContorller.addAndGet(); - // final SelectionChangeCallback? onSelectionChanged; - - // final ShouldApplySelection? shouldApplySelection; - - // final ScrollCallback? onScroll; + ScrollController linkHorizontalController() { + final controller = _scrollGroupContorller.addAndGet(); + _linkHorizontalControllers.add(controller); + return controller; + } void dispose() { + for (final controller in _linkHorizontalControllers) { + controller.dispose(); + } verticalController.dispose(); horizontalController.dispose(); } 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 790dc0f83c..340f7c7026 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 @@ -9,6 +9,7 @@ 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 Field; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/material.dart'; +import 'package:linked_scroll_controller/linked_scroll_controller.dart'; import 'controller/grid_scroll.dart'; import 'layout/layout.dart'; import 'layout/sizes.dart'; @@ -73,17 +74,23 @@ class FlowyGrid extends StatefulWidget { } class _FlowyGridState extends State { - final _scrollController = GridScrollController(); + final _scrollController = GridScrollController(scrollGroupContorller: LinkedScrollControllerGroup()); + + @override + void dispose() { + _scrollController.dispose(); + super.dispose(); + } @override Widget build(BuildContext context) { return BlocBuilder( buildWhen: (previous, current) => previous.fields.length != current.fields.length, builder: (context, state) { + final contentWidth = GridLayout.headerWidth(state.fields); final child = _wrapScrollView( - state.fields, + contentWidth, [ - _GridHeader(gridId: state.gridId, fields: state.fields), const _GridRows(), const _GridFooter(), ], @@ -91,6 +98,7 @@ class _FlowyGridState extends State { return Column(children: [ const _GridToolbarAdaptor(), + _gridHeader(context, state.gridId, contentWidth), Flexible(child: child), ]); }, @@ -98,7 +106,7 @@ class _FlowyGridState extends State { } Widget _wrapScrollView( - List fields, + double contentWidth, List slivers, ) { final verticalScrollView = ScrollConfiguration( @@ -111,7 +119,7 @@ class _FlowyGridState extends State { ); final sizedVerticalScrollView = SizedBox( - width: GridLayout.headerWidth(fields), + width: contentWidth, child: verticalScrollView, ); @@ -128,6 +136,19 @@ class _FlowyGridState extends State { child: horizontalScrollView, ); } + + Widget _gridHeader(BuildContext context, String gridId, double contentWidth) { + final fieldCache = context.read().fieldCache; + + return SizedBox( + width: contentWidth, + child: GridHeaderSliverAdaptor( + gridId: gridId, + fieldCache: fieldCache, + anchorScrollController: _scrollController.linkHorizontalController(), + ), + ); + } } class _GridToolbarAdaptor extends StatelessWidget { @@ -149,18 +170,6 @@ class _GridToolbarAdaptor extends StatelessWidget { } } -class _GridHeader extends StatelessWidget { - final String gridId; - final List fields; - const _GridHeader({Key? key, required this.gridId, required this.fields}) : super(key: key); - - @override - Widget build(BuildContext context) { - final fieldCache = context.read().fieldCache; - return GridHeaderSliverAdaptor(gridId: gridId, fieldCache: fieldCache); - } -} - class _GridRows extends StatefulWidget { const _GridRows({Key? key}) : super(key: key); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index a00b9e6295..2ac5e5f673 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -13,25 +13,41 @@ import 'package:reorderables/reorderables.dart'; import 'field_editor.dart'; import 'field_cell.dart'; -class GridHeaderSliverAdaptor extends StatelessWidget { +class GridHeaderSliverAdaptor extends StatefulWidget { final String gridId; final GridFieldCache fieldCache; + final ScrollController anchorScrollController; + const GridHeaderSliverAdaptor({ + required this.gridId, + required this.fieldCache, + required this.anchorScrollController, + Key? key, + }) : super(key: key); - const GridHeaderSliverAdaptor({required this.gridId, required this.fieldCache, Key? key}) : super(key: key); + @override + State createState() => _GridHeaderSliverAdaptorState(); +} +class _GridHeaderSliverAdaptorState extends State { @override Widget build(BuildContext context) { return BlocProvider( create: (context) => - getIt(param1: gridId, param2: fieldCache)..add(const GridHeaderEvent.initial()), + getIt(param1: widget.gridId, param2: widget.fieldCache)..add(const GridHeaderEvent.initial()), child: BlocBuilder( buildWhen: (previous, current) => previous.fields.length != current.fields.length, builder: (context, state) { - return SliverPersistentHeader( - delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: state.fields), - floating: true, - pinned: true, + return SingleChildScrollView( + scrollDirection: Axis.horizontal, + controller: widget.anchorScrollController, + child: SizedBox(height: GridSize.headerHeight, child: _GridHeader(gridId: widget.gridId)), ); + + // return SliverPersistentHeader( + // delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: state.fields), + // floating: true, + // pinned: true, + // ); }, ), ); @@ -46,7 +62,7 @@ class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate @override Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - return _GridHeader(gridId: gridId, fields: fields); + return _GridHeader(gridId: gridId); } @override @@ -66,13 +82,7 @@ class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate class _GridHeader extends StatefulWidget { final String gridId; - final List fields; - - const _GridHeader({ - Key? key, - required this.gridId, - required this.fields, - }) : super(key: key); + const _GridHeader({Key? key, required this.gridId}) : super(key: key); @override State<_GridHeader> createState() => _GridHeaderState(); @@ -93,15 +103,17 @@ class _GridHeaderState extends State<_GridHeader> { return Container( color: theme.surface, - child: ReorderableRow( - crossAxisAlignment: CrossAxisAlignment.stretch, - scrollController: ScrollController(), - header: const _CellLeading(), - footer: _CellTrailing(gridId: widget.gridId), - onReorder: (int oldIndex, int newIndex) { - Log.info("from $oldIndex to $newIndex"); - }, - children: cells, + child: RepaintBoundary( + child: ReorderableRow( + crossAxisAlignment: CrossAxisAlignment.stretch, + scrollController: ScrollController(), + header: const _CellLeading(), + footer: _CellTrailing(gridId: widget.gridId), + onReorder: (int oldIndex, int newIndex) { + Log.info("from $oldIndex to $newIndex"); + }, + children: cells, + ), ), ); }, diff --git a/frontend/app_flowy/pubspec.lock b/frontend/app_flowy/pubspec.lock index 1a3a3172f4..8f7e6d6db2 100644 --- a/frontend/app_flowy/pubspec.lock +++ b/frontend/app_flowy/pubspec.lock @@ -653,6 +653,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.4.0" + linked_scroll_controller: + dependency: "direct main" + description: + name: linked_scroll_controller + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0" lint: dependency: transitive description: diff --git a/frontend/app_flowy/pubspec.yaml b/frontend/app_flowy/pubspec.yaml index bcc3303602..fd2b75b9e0 100644 --- a/frontend/app_flowy/pubspec.yaml +++ b/frontend/app_flowy/pubspec.yaml @@ -75,6 +75,7 @@ dependencies: fluttertoast: ^8.0.8 table_calendar: ^3.0.5 reorderables: + linked_scroll_controller: ^0.2.0 dev_dependencies: flutter_lints: ^1.0.0 From 0c8850503f953910824456d65b15741d0a5af2b5 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 15 Apr 2022 19:56:44 +0800 Subject: [PATCH 14/26] chore: reorder field --- .../application/grid/field/field_service.dart | 11 ++++++++++ .../application/grid/grid_header_bloc.dart | 8 +++++-- .../plugins/grid/src/grid_page.dart | 22 ++++++++++++++----- .../grid/src/widgets/header/grid_header.dart | 9 +++++++- .../flowy-grid/src/services/grid_editor.rs | 22 +++++++++++++++---- .../src/client_grid/grid_meta_pad.rs | 19 ++++++++++++++++ 6 files changed, 78 insertions(+), 13 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index e1bed697c8..c909bf1b31 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -29,6 +29,17 @@ class FieldService { return GridEventGetEditFieldContext(payload).send(); } + Future> moveField(String fieldId, int fromIndex, int toIndex) { + final payload = MoveItemPayload.create() + ..gridId = gridId + ..itemId = fieldId + ..ty = MoveItemType.MoveField + ..fromIndex = fromIndex + ..toIndex = toIndex; + + return GridEventMoveItem(payload).send(); + } + Future> updateField({ required String fieldId, String? name, diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index 8ea390d7ab..08cd01e316 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -1,4 +1,5 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -25,7 +26,10 @@ class GridHeaderBloc extends Bloc { didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { emit(state.copyWith(fields: value.fields)); }, - moveField: (_MoveField value) {}, + moveField: (_MoveField value) async { + final result = await _fieldService.moveField(value.field.id, value.fromIndex, value.toIndex); + result.fold((l) {}, (err) => Log.error(err)); + }, ); }, ); @@ -49,7 +53,7 @@ class GridHeaderBloc extends Bloc { class GridHeaderEvent with _$GridHeaderEvent { const factory GridHeaderEvent.initial() = _InitialHeader; const factory GridHeaderEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; - const factory GridHeaderEvent.moveField(int fromIndex, int toIndex) = _MoveField; + const factory GridHeaderEvent.moveField(Field field, int fromIndex, int toIndex) = _MoveField; } @freezed diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index 340f7c7026..127a39d024 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -75,6 +75,13 @@ class FlowyGrid extends StatefulWidget { class _FlowyGridState extends State { final _scrollController = GridScrollController(scrollGroupContorller: LinkedScrollControllerGroup()); + late ScrollController headerScrollController; + + @override + void initState() { + headerScrollController = _scrollController.linkHorizontalController(); + super.initState(); + } @override void dispose() { @@ -96,11 +103,14 @@ class _FlowyGridState extends State { ], ); - return Column(children: [ - const _GridToolbarAdaptor(), - _gridHeader(context, state.gridId, contentWidth), - Flexible(child: child), - ]); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const _GridToolbarAdaptor(), + _gridHeader(context, state.gridId, contentWidth), + Flexible(child: child), + ], + ); }, ); } @@ -145,7 +155,7 @@ class _FlowyGridState extends State { child: GridHeaderSliverAdaptor( gridId: gridId, fieldCache: fieldCache, - anchorScrollController: _scrollController.linkHorizontalController(), + anchorScrollController: headerScrollController, ), ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 2ac5e5f673..95abccc830 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -110,7 +110,7 @@ class _GridHeaderState extends State<_GridHeader> { header: const _CellLeading(), footer: _CellTrailing(gridId: widget.gridId), onReorder: (int oldIndex, int newIndex) { - Log.info("from $oldIndex to $newIndex"); + _onReorder(cells, oldIndex, context, newIndex); }, children: cells, ), @@ -119,6 +119,13 @@ class _GridHeaderState extends State<_GridHeader> { }, ); } + + void _onReorder(List cells, int oldIndex, BuildContext context, int newIndex) { + if (cells.length > oldIndex) { + final field = cells[oldIndex].cellContext.field; + context.read().add(GridHeaderEvent.moveField(field, oldIndex, newIndex)); + } + } } class _CellLeading extends StatelessWidget { diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 41a70d8549..e348d105d1 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -385,16 +385,30 @@ impl ClientGridEditor { pub async fn move_item(&self, params: MoveItemParams) -> FlowyResult<()> { match params.ty { MoveItemType::MoveField => { - self.move_field(params.from_index, params.to_index, ¶ms.item_id) + self.move_field(¶ms.item_id, params.from_index, params.to_index) .await } MoveItemType::MoveRow => self.move_row(params.from_index, params.to_index, ¶ms.item_id).await, } } - pub async fn move_field(&self, from: i32, to: i32, field_id: &str) -> FlowyResult<()> { - // GridFieldChangeset - todo!() + pub async fn move_field(&self, field_id: &str, from: i32, to: i32) -> FlowyResult<()> { + let _ = self + .modify(|grid_pad| Ok(grid_pad.move_field(field_id, from as usize, to as usize)?)) + .await?; + if let Some((index, field_meta)) = self.pad.read().await.get_field_meta(field_id) { + let delete_field_order = FieldOrder::from(field_id); + let insert_field = IndexField::from_field_meta(field_meta, index); + let notified_changeset = GridFieldChangeset { + grid_id: self.grid_id.clone(), + inserted_fields: vec![insert_field], + deleted_fields: vec![delete_field_order], + updated_fields: vec![], + }; + + let _ = self.notify_did_update_grid(notified_changeset).await?; + } + Ok(()) } pub async fn move_row(&self, from: i32, to: i32, row_id: &str) -> FlowyResult<()> { diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index 5c59437d4f..2cf56fd5f0 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -205,6 +205,25 @@ impl GridMetaPad { ) } + pub fn move_field( + &mut self, + field_id: &str, + from_index: usize, + to_index: usize, + ) -> CollaborateResult> { + self.modify_grid( + |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { + None => Ok(None), + Some(index) => { + debug_assert_eq!(index, from_index); + let field_meta = grid_meta.fields.remove(index); + grid_meta.fields.insert(to_index, field_meta); + Ok(Some(())) + } + }, + ) + } + pub fn contain_field(&self, field_id: &str) -> bool { self.grid_meta.fields.iter().any(|field| field.id == field_id) } From ea654b602c73a830ff776a448053a4e07340f9bf Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 15 Apr 2022 22:10:38 +0800 Subject: [PATCH 15/26] fix: listen on listState if changed --- .../lib/workspace/presentation/plugins/grid/src/grid_page.dart | 1 + 1 file changed, 1 insertion(+) 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 127a39d024..189027c277 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 @@ -193,6 +193,7 @@ class _GridRowsState extends State<_GridRows> { @override Widget build(BuildContext context) { return BlocConsumer( + listenWhen: (previous, current) => previous.listState != current.listState, listener: (context, state) { state.listState.map( insert: (value) { From f3c82f5c30a481eb2cba0ac9f61d4f48f5912502 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 15 Apr 2022 22:21:32 +0800 Subject: [PATCH 16/26] chore: insert without remove field on FieldCache --- .../app_flowy/lib/workspace/application/grid/grid_service.dart | 1 - 1 file changed, 1 deletion(-) 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 b79c2e5e59..42f6fa0694 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -103,7 +103,6 @@ class GridFieldCache { final List fields = _fieldNotifier.fields; for (final indexField in insertedFields) { if (fields.length > indexField.index) { - fields.removeAt(indexField.index); fields.insert(indexField.index, indexField.field_1); } else { fields.add(indexField.field_1); From d4de5767a66655541ee55c1ba4f5edf3f3af4fa8 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 16 Apr 2022 09:25:12 +0800 Subject: [PATCH 17/26] chore: auto resize row height --- .../application/grid/row/row_service.dart | 11 ++ .../plugins/grid/src/grid_page.dart | 16 +-- .../grid/src/widgets/cell/cell_container.dart | 4 +- .../grid/src/widgets/header/field_cell.dart | 105 ++++++++++++------ .../grid/src/widgets/header/grid_header.dart | 64 ++++++----- .../grid/src/widgets/row/grid_row.dart | 13 ++- .../src/services/block_meta_editor.rs | 23 ++-- .../src/services/block_meta_manager.rs | 26 +++++ .../flowy-grid/src/services/grid_editor.rs | 11 +- .../src/client_grid/grid_block_meta_pad.rs | 13 +++ 10 files changed, 192 insertions(+), 94 deletions(-) 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 643a2c649e..412dea9003 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart @@ -21,6 +21,17 @@ class RowService { return GridEventCreateRow(payload).send(); } + Future> moveRow(String rowId, int fromIndex, int toIndex) { + final payload = MoveItemPayload.create() + ..gridId = gridId + ..itemId = rowId + ..ty = MoveItemType.MoveRow + ..fromIndex = fromIndex + ..toIndex = toIndex; + + return GridEventMoveItem(payload).send(); + } + Future> getRow() { final payload = RowIdentifierPayload.create() ..gridId = gridId 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 189027c277..1c7707c8eb 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 @@ -107,7 +107,7 @@ class _FlowyGridState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ const _GridToolbarAdaptor(), - _gridHeader(context, state.gridId, contentWidth), + _gridHeader(context, state.gridId), Flexible(child: child), ], ); @@ -147,16 +147,12 @@ class _FlowyGridState extends State { ); } - Widget _gridHeader(BuildContext context, String gridId, double contentWidth) { + Widget _gridHeader(BuildContext context, String gridId) { final fieldCache = context.read().fieldCache; - - return SizedBox( - width: contentWidth, - child: GridHeaderSliverAdaptor( - gridId: gridId, - fieldCache: fieldCache, - anchorScrollController: headerScrollController, - ), + return GridHeaderSliverAdaptor( + gridId: gridId, + fieldCache: fieldCache, + anchorScrollController: headerScrollController, ); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart index 57f3610be2..0ff4ae71ab 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart @@ -33,9 +33,7 @@ class CellContainer extends StatelessWidget { child: Consumer( builder: (context, state, _) { return Container( - constraints: BoxConstraints( - maxWidth: width, - ), + constraints: BoxConstraints(maxWidth: width, maxHeight: 42), decoration: _makeBoxDecoration(context, state), padding: GridSize.cellContentInsets, child: Center(child: child), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index e9fa11d883..c6009b64af 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -6,6 +6,7 @@ import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/hover.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'; import 'field_type_extension.dart'; @@ -28,49 +29,19 @@ class GridFieldCell extends StatelessWidget { final button = FlowyButton( hoverColor: theme.shader6, onTap: () => _showActionSheet(context), - // rightIcon: svgWidget("editor/details", color: theme.iconColor), leftIcon: svgWidget(state.field.fieldType.iconName(), color: theme.iconColor), text: FlowyText.medium(state.field.name, fontSize: 12), padding: GridSize.cellContentInsets, ); - final line = InkWell( - onTap: () {}, - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onHorizontalDragCancel: () {}, - onHorizontalDragUpdate: (value) { - context.read().add(FieldCellEvent.updateWidth(value.delta.dx)); - }, - child: FlowyHover( - style: HoverStyle( - hoverColor: theme.main1, - borderRadius: BorderRadius.zero, - contentMargin: const EdgeInsets.only(left: 5), - ), - builder: (_, onHover) => const SizedBox(width: 2), - ), - ), - ); + const line = Positioned(top: 0, bottom: 0, right: 0, child: _DragToExpandLine()); - final borderSide = BorderSide(color: theme.shader4, width: 0.4); - final decoration = BoxDecoration( - border: Border( - top: borderSide, - right: borderSide, - bottom: borderSide, - )); - - return Container( + return _CellContainer( width: state.field.width.toDouble(), - decoration: decoration, - child: ConstrainedBox( - constraints: const BoxConstraints.expand(), - child: Stack( - alignment: Alignment.centerRight, - fit: StackFit.expand, - children: [button, Positioned(top: 0, bottom: 0, right: 0, child: line)], - ), + child: Stack( + alignment: Alignment.centerRight, + fit: StackFit.expand, + children: [button, line], ), ); }, @@ -98,3 +69,65 @@ class GridFieldCell extends StatelessWidget { ).show(context); } } + +class _CellContainer extends StatelessWidget { + final Widget child; + final double width; + const _CellContainer({ + required this.child, + required this.width, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + final borderSide = BorderSide(color: theme.shader4, width: 0.4); + final decoration = BoxDecoration( + border: Border( + top: borderSide, + right: borderSide, + bottom: borderSide, + )); + + return Container( + width: width, + decoration: decoration, + child: ConstrainedBox(constraints: const BoxConstraints.expand(), child: child), + ); + } +} + +class _DragToExpandLine extends StatelessWidget { + const _DragToExpandLine({ + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + return InkWell( + onTap: () {}, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onHorizontalDragCancel: () {}, + onHorizontalDragUpdate: (value) { + // context.read().add(FieldCellEvent.updateWidth(value.delta.dx)); + Log.info(value); + }, + onHorizontalDragEnd: (end) { + Log.info(end); + }, + child: FlowyHover( + style: HoverStyle( + hoverColor: theme.main1, + borderRadius: BorderRadius.zero, + contentMargin: const EdgeInsets.only(left: 5), + ), + builder: (_, onHover) => const SizedBox(width: 2), + ), + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 95abccc830..22bd59eb4d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -32,15 +32,21 @@ class _GridHeaderSliverAdaptorState extends State { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => - getIt(param1: widget.gridId, param2: widget.fieldCache)..add(const GridHeaderEvent.initial()), + create: (context) { + final bloc = getIt(param1: widget.gridId, param2: widget.fieldCache); + bloc.add(const GridHeaderEvent.initial()); + return bloc; + }, child: BlocBuilder( buildWhen: (previous, current) => previous.fields.length != current.fields.length, builder: (context, state) { return SingleChildScrollView( scrollDirection: Axis.horizontal, controller: widget.anchorScrollController, - child: SizedBox(height: GridSize.headerHeight, child: _GridHeader(gridId: widget.gridId)), + child: SizedBox( + height: GridSize.headerHeight, + child: _GridHeader(gridId: widget.gridId), + ), ); // return SliverPersistentHeader( @@ -54,32 +60,6 @@ class _GridHeaderSliverAdaptorState extends State { } } -class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate { - final String gridId; - final List fields; - - SliverHeaderDelegateImplementation({required this.gridId, required this.fields}); - - @override - Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { - return _GridHeader(gridId: gridId); - } - - @override - double get maxExtent => GridSize.headerHeight; - - @override - double get minExtent => GridSize.headerHeight; - - @override - bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { - if (oldDelegate is SliverHeaderDelegateImplementation) { - return fields.length != oldDelegate.fields.length; - } - return true; - } -} - class _GridHeader extends StatefulWidget { final String gridId; const _GridHeader({Key? key, required this.gridId}) : super(key: key); @@ -177,3 +157,29 @@ class CreateFieldButton extends StatelessWidget { ); } } + +class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate { + final String gridId; + final List fields; + + SliverHeaderDelegateImplementation({required this.gridId, required this.fields}); + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + return _GridHeader(gridId: gridId); + } + + @override + double get maxExtent => GridSize.headerHeight; + + @override + double get minExtent => GridSize.headerHeight; + + @override + bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { + if (oldDelegate is SliverHeaderDelegateImplementation) { + return fields.length != oldDelegate.fields.length; + } + return true; + } +} 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 5528818a58..b63f79f5b0 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 @@ -44,10 +44,11 @@ class _GridRowWidgetState extends State { child: BlocBuilder( buildWhen: (p, c) => p.rowData.height != c.rowData.height, builder: (context, state) { - return SizedBox( - height: _rowBloc.state.rowData.height, + return LimitedBox( + maxHeight: 200, child: Row( - crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.center, children: const [ _RowLeading(), _RowCells(), @@ -147,7 +148,11 @@ class _RowCells extends StatelessWidget { buildWhen: (previous, current) => previous.cellDataMap != current.cellDataMap, builder: (context, state) { final List children = state.cellDataMap.fold(() => [], _toCells); - return Row(children: children); + return Row( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: children, + ); }, ); } 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 652617146b..977ccccb3d 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 @@ -51,16 +51,16 @@ impl ClientGridBlockMetaEditor { let mut row_count = 0; let mut row_index = None; let _ = self - .modify(|pad| { + .modify(|block_pad| { if let Some(start_row_id) = start_row_id.as_ref() { - match pad.index_of_row(start_row_id) { + match block_pad.index_of_row(start_row_id) { None => {} Some(index) => row_index = Some(index + 1), } } - let change = pad.add_row_meta(row, start_row_id)?; - row_count = pad.number_of_rows(); + let change = block_pad.add_row_meta(row, start_row_id)?; + row_count = block_pad.number_of_rows(); Ok(change) }) .await?; @@ -71,9 +71,9 @@ impl ClientGridBlockMetaEditor { pub async fn delete_rows(&self, ids: Vec>) -> FlowyResult { let mut row_count = 0; let _ = self - .modify(|pad| { - let changeset = pad.delete_rows(ids)?; - row_count = pad.number_of_rows(); + .modify(|block_pad| { + let changeset = block_pad.delete_rows(ids)?; + row_count = block_pad.number_of_rows(); Ok(changeset) }) .await?; @@ -81,7 +81,14 @@ impl ClientGridBlockMetaEditor { } pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { - let _ = self.modify(|pad| Ok(pad.update_row(changeset)?)).await?; + let _ = self.modify(|block_pad| Ok(block_pad.update_row(changeset)?)).await?; + Ok(()) + } + + pub async fn move_row(&self, row_id: &str, from: usize, to: usize) -> FlowyResult<()> { + let _ = self + .modify(|block_pad| Ok(block_pad.move_row(row_id, from, to)?)) + .await?; Ok(()) } 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 b5a35b10cd..2a8eae4497 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 @@ -154,6 +154,32 @@ impl GridBlockMetaEditorManager { Ok(changesets) } + pub(crate) async fn move_row(&self, row_id: &str, from: usize, to: usize) -> FlowyResult<()> { + let editor = self.get_editor_from_row_id(row_id).await?; + let _ = editor.move_row(row_id, from, to).await?; + + match editor.get_row_metas(Some(vec![Cow::Borrowed(row_id)])).await?.pop() { + None => {} + Some(row_meta) => { + let row_order = RowOrder::from(&row_meta); + let insert_row = IndexRowOrder { + row_order: row_order.clone(), + index: Some(to as i32), + }; + let notified_changeset = GridRowsChangeset { + block_id: editor.block_id.clone(), + inserted_rows: vec![insert_row], + deleted_rows: vec![row_order], + updated_rows: vec![], + }; + + let _ = self.notify_did_update_rows(notified_changeset).await?; + } + } + + Ok(()) + } + pub async fn update_cell(&self, changeset: CellChangeset) -> FlowyResult<()> { let row_id = changeset.row_id.clone(); let editor = self.get_editor_from_row_id(&row_id).await?; diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index e348d105d1..b34e0fea65 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -388,7 +388,7 @@ impl ClientGridEditor { self.move_field(¶ms.item_id, params.from_index, params.to_index) .await } - MoveItemType::MoveRow => self.move_row(params.from_index, params.to_index, ¶ms.item_id).await, + MoveItemType::MoveRow => self.move_row(¶ms.item_id, params.from_index, params.to_index).await, } } @@ -411,9 +411,12 @@ impl ClientGridEditor { Ok(()) } - pub async fn move_row(&self, from: i32, to: i32, row_id: &str) -> FlowyResult<()> { - // GridRowsChangeset - todo!() + pub async fn move_row(&self, row_id: &str, from: i32, to: i32) -> FlowyResult<()> { + let _ = self + .block_meta_manager + .move_row(row_id, from as usize, to as usize) + .await?; + Ok(()) } pub async fn delta_bytes(&self) -> Bytes { diff --git a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs index 1a51b1bebb..3f727faf59 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_block_meta_pad.rs @@ -149,6 +149,19 @@ impl GridBlockMetaPad { }) } + pub fn move_row(&mut self, row_id: &str, from: usize, to: usize) -> CollaborateResult> { + self.modify(|row_metas| { + if let Some(position) = row_metas.iter().position(|row_meta| row_meta.id == row_id) { + debug_assert_eq!(from, position); + let row_meta = row_metas.remove(position); + row_metas.insert(to, row_meta); + Ok(Some(())) + } else { + Ok(None) + } + }) + } + pub fn modify(&mut self, f: F) -> CollaborateResult> where F: for<'a> FnOnce(&'a mut Vec>) -> CollaborateResult>, From 792f8b95aaf219ec8abd77563b76406de807b333 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 16 Apr 2022 16:58:26 +0800 Subject: [PATCH 18/26] fix: triger rowbloc event after it was closed --- .../application/grid/grid_service.dart | 15 +++++++----- .../application/grid/row/row_bloc.dart | 24 ++++++++++++++----- .../plugins/grid/src/grid_page.dart | 12 +++++----- .../grid/src/widgets/cell/cell_container.dart | 2 +- .../grid/src/widgets/row/grid_row.dart | 4 ++-- 5 files changed, 36 insertions(+), 21 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 42f6fa0694..0f2118fea1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -162,7 +162,7 @@ class GridRowCache { } final List newRows = []; - final List> deletedIndex = []; + final DeletedIndex deletedIndex = []; final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; _rows.asMap().forEach((index, value) { if (deletedRowMap[value.rowId] == null) { @@ -181,13 +181,13 @@ class GridRowCache { return none(); } - List insertIndexs = []; + InsertedIndexs insertIndexs = []; for (final newRow in createdRows) { if (newRow.hasIndex()) { - insertIndexs.add(newRow.index); + insertIndexs.add(Tuple2(newRow.index, newRow.rowOrder.rowId)); _rows.insert(newRow.index, _toRowData(newRow.rowOrder)); } else { - insertIndexs.add(_rows.length); + insertIndexs.add(Tuple2(newRow.index, newRow.rowOrder.rowId)); _rows.add(_toRowData(newRow.rowOrder)); } } @@ -216,9 +216,12 @@ class GridRowCache { } } +typedef InsertedIndexs = List>; +typedef DeletedIndex = List>; + @freezed class GridListState with _$GridListState { - const factory GridListState.insert(List indexs) = _Insert; - const factory GridListState.delete(List> indexs) = _Delete; + const factory GridListState.insert(InsertedIndexs items) = _Insert; + const factory GridListState.delete(DeletedIndex items) = _Delete; const factory GridListState.initial() = InitialListState; } 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 b16d75dc92..81bb8b190c 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 @@ -35,20 +35,23 @@ class RowBloc extends Bloc { _rowService.createRow(); }, didUpdateRow: (_DidUpdateRow value) async { - _handleRowUpdate(value, emit); + _handleRowUpdate(value.row, emit); }, fieldsDidUpdate: (_FieldsDidUpdate value) async { await _handleFieldUpdate(emit); }, + didLoadRow: (_DidLoadRow value) { + _handleRowUpdate(value.row, emit); + }, ); }, ); } - void _handleRowUpdate(_DidUpdateRow value, Emitter emit) { - final CellDataMap cellDataMap = _makeCellDatas(value.row, state.rowData.fields); + void _handleRowUpdate(Row row, Emitter emit) { + final CellDataMap cellDataMap = _makeCellDatas(row, state.rowData.fields); emit(state.copyWith( - row: Future(() => Some(value.row)), + row: Future(() => Some(row)), cellDataMap: Some(cellDataMap), )); } @@ -75,7 +78,11 @@ class RowBloc extends Bloc { Future _startListening() async { _rowlistener.updateRowNotifier?.addPublishListener((result) { result.fold( - (row) => add(RowEvent.didUpdateRow(row)), + (row) { + if (!isClosed) { + add(RowEvent.didUpdateRow(row)); + } + }, (err) => Log.error(err), ); }); @@ -92,7 +99,11 @@ class RowBloc extends Bloc { Future _loadRow(Emitter emit) async { _rowService.getRow().then((result) { return result.fold( - (row) => add(RowEvent.didUpdateRow(row)), + (row) { + if (!isClosed) { + add(RowEvent.didLoadRow(row)); + } + }, (err) => Log.error(err), ); }); @@ -119,6 +130,7 @@ class RowEvent with _$RowEvent { const factory RowEvent.initial() = _InitialRow; const factory RowEvent.createRow() = _CreateRow; const factory RowEvent.fieldsDidUpdate() = _FieldsDidUpdate; + const factory RowEvent.didLoadRow(Row row) = _DidLoadRow; const factory RowEvent.didUpdateRow(Row row) = _DidUpdateRow; } 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 1c7707c8eb..74215f4b80 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 @@ -6,7 +6,6 @@ import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scrollview.dart'; import 'package:flowy_infra_ui/widget/error_page.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 Field; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/material.dart'; import 'package:linked_scroll_controller/linked_scroll_controller.dart'; @@ -193,15 +192,15 @@ class _GridRowsState extends State<_GridRows> { listener: (context, state) { state.listState.map( insert: (value) { - for (final index in value.indexs) { - _key.currentState?.insertItem(index); + for (final item in value.items) { + _key.currentState?.insertItem(item.value1); } }, delete: (value) { - for (final index in value.indexs) { + for (final item in value.items) { _key.currentState?.removeItem( - index.value1, - (context, animation) => _renderRow(context, index.value2, animation), + item.value1, + (context, animation) => _renderRow(context, item.value2, animation), ); } }, @@ -224,6 +223,7 @@ class _GridRowsState extends State<_GridRows> { Widget _renderRow(BuildContext context, RowData rowData, Animation animation) { final fieldCache = context.read().fieldCache; + return SizeTransition( sizeFactor: animation, child: GridRowWidget( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart index 0ff4ae71ab..c9af10c2b8 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart @@ -33,7 +33,7 @@ class CellContainer extends StatelessWidget { child: Consumer( builder: (context, state, _) { return Container( - constraints: BoxConstraints(maxWidth: width, maxHeight: 42), + constraints: BoxConstraints(maxWidth: width), decoration: _makeBoxDecoration(context, state), padding: GridSize.cellContentInsets, child: Center(child: child), 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 b63f79f5b0..edac8bc2fe 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 @@ -44,8 +44,8 @@ class _GridRowWidgetState extends State { child: BlocBuilder( buildWhen: (p, c) => p.rowData.height != c.rowData.height, builder: (context, state) { - return LimitedBox( - maxHeight: 200, + return SizedBox( + height: 42, child: Row( mainAxisSize: MainAxisSize.max, crossAxisAlignment: CrossAxisAlignment.center, From 3cc7c8e6de67ba642bd90d202c4ad834e479f9be Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 16 Apr 2022 20:20:00 +0800 Subject: [PATCH 19/26] chore: cache row data --- .../app_flowy/lib/startup/deps_resolver.dart | 7 - .../grid/cell_bloc/checkbox_cell_bloc.dart | 9 +- .../grid/cell_bloc/date_cell_bloc.dart | 19 +-- .../grid/cell_bloc/number_cell_bloc.dart | 10 +- .../grid/cell_bloc/selection_cell_bloc.dart | 15 +- .../grid/cell_bloc/selection_editor_bloc.dart | 23 ++- .../grid/field/field_cell_bloc.dart | 8 +- .../workspace/application/grid/grid_bloc.dart | 26 ++-- .../application/grid/grid_header_bloc.dart | 10 +- .../application/grid/grid_service.dart | 105 +------------- .../grid/row/row_action_sheet_bloc.dart | 6 +- .../application/grid/row/row_bloc.dart | 58 ++++---- .../application/grid/row/row_service.dart | 136 +++++++++++++++++- .../plugins/grid/src/grid_page.dart | 14 +- .../grid/src/widgets/row/grid_row.dart | 12 +- .../src/widgets/row/row_action_sheet.dart | 2 +- .../packages/flowy_infra/lib/notifier.dart | 12 +- 17 files changed, 247 insertions(+), 225 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index e35f8e7f96..47267cc2c9 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -150,13 +150,6 @@ void _resolveGridDeps(GetIt getIt) { (view, _) => GridBloc(view: view), ); - getIt.registerFactoryParam( - (data, fieldCache) => RowBloc( - rowData: data, - fieldCache: fieldCache, - ), - ); - getIt.registerFactoryParam( (gridId, fieldCache) => GridHeaderBloc( gridId: gridId, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart index 2d937b8cd2..3a4500eb45 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart @@ -58,12 +58,11 @@ class CheckboxCellBloc extends Bloc { fieldId: state.cellData.field.id, rowId: state.cellData.rowId, ); + if (isClosed) { + return; + } result.fold( - (cell) { - if (!isClosed) { - add(CheckboxCellEvent.didReceiveCellUpdate(cell)); - } - }, + (cell) => add(CheckboxCellEvent.didReceiveCellUpdate(cell)), (err) => Log.error(err), ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart index b4b6d7e152..d7e0c078aa 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart @@ -57,19 +57,15 @@ class DateCellBloc extends Bloc { (notificationData) => _loadCellData(), (err) => Log.error(err), ); - }); + }, listenWhen: () => !isClosed); _cellListener.start(); _fieldListener.updateFieldNotifier?.addPublishListener((result) { result.fold( - (field) { - if (!isClosed) { - add(DateCellEvent.didReceiveFieldUpdate(field)); - } - }, + (field) => add(DateCellEvent.didReceiveFieldUpdate(field)), (err) => Log.error(err), ); - }); + }, listenWhen: () => !isClosed); _fieldListener.start(); } @@ -79,12 +75,11 @@ class DateCellBloc extends Bloc { fieldId: state.cellData.field.id, rowId: state.cellData.rowId, ); + if (isClosed) { + return; + } result.fold( - (cell) { - if (!isClosed) { - add(DateCellEvent.didReceiveCellUpdate(cell)); - } - }, + (cell) => add(DateCellEvent.didReceiveCellUpdate(cell)), (err) => Log.error(err), ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart index 287d70b701..fbc432c557 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart @@ -84,12 +84,12 @@ class NumberCellBloc extends Bloc { fieldId: state.cellData.field.id, rowId: state.cellData.rowId, ); + + if (isClosed) { + return; + } result.fold( - (cell) { - if (!isClosed) { - add(NumberCellEvent.didReceiveCellUpdate(cell)); - } - }, + (cell) => add(NumberCellEvent.didReceiveCellUpdate(cell)), (err) => Log.error(err), ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart index dbca1b5ae3..ae7c48d81f 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart @@ -49,16 +49,15 @@ class SelectionCellBloc extends Bloc { fieldId: state.cellData.field.id, rowId: state.cellData.rowId, ); + if (isClosed) { + return; + } result.fold( - (selectOptionContext) { - if (!isClosed) { - add(SelectionCellEvent.didReceiveOptions( - selectOptionContext.options, - selectOptionContext.selectOptions, - )); - } - }, + (selectOptionContext) => add(SelectionCellEvent.didReceiveOptions( + selectOptionContext.options, + selectOptionContext.selectOptions, + )), (err) => Log.error(err), ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart index 813b779646..0d1b2705e3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart @@ -117,16 +117,15 @@ class SelectOptionEditorBloc extends Bloc add(SelectOptionEditorEvent.didReceiveOptions( + selectOptionContext.options, + selectOptionContext.selectOptions, + )), (err) => Log.error(err), ); }, @@ -144,14 +143,10 @@ class SelectOptionEditorBloc extends Bloc add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)), (err) => Log.error(err), ); - }); + }, listenWhen: () => !isClosed); _fieldListener.start(); } } 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 2c148ae452..576e62e3b1 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 @@ -47,14 +47,10 @@ class FieldCellBloc extends Bloc { void _startListening() { _fieldListener.updateFieldNotifier?.addPublishListener((result) { result.fold( - (field) { - if (!isClosed) { - add(FieldCellEvent.didReceiveFieldUpdate(field)); - } - }, + (field) => add(FieldCellEvent.didReceiveFieldUpdate(field)), (err) => Log.error(err), ); - }); + }, listenWhen: () => !isClosed); _fieldListener.start(); } } 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 c37c31ec46..5782371e7a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -18,14 +18,14 @@ class GridBloc extends Bloc { final GridListener _gridListener; final GridFieldsListener _fieldListener; final GridFieldCache fieldCache; - final GridRowCache _rowCache; + final GridRowCache rowCache; GridBloc({required View view}) : _fieldListener = GridFieldsListener(gridId: view.id), _gridService = GridService(gridId: view.id), _gridListener = GridListener(gridId: view.id), fieldCache = GridFieldCache(), - _rowCache = GridRowCache(gridId: view.id), + rowCache = GridRowCache(gridId: view.id), super(GridState.initial(view.id)) { on( (event, emit) async { @@ -41,7 +41,7 @@ class GridBloc extends Bloc { emit(state.copyWith(rows: value.rows, listState: value.listState)); }, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - emit(state.copyWith(rows: _rowCache.rows, fields: value.fields)); + emit(state.copyWith(rows: rowCache.rows, fields: value.fields)); }, ); }, @@ -62,7 +62,7 @@ class GridBloc extends Bloc { result.fold( (changeset) { fieldCache.applyChangeset(changeset); - _rowCache.updateFields(fieldCache.unmodifiableFields); + rowCache.updateFields(fieldCache.unmodifiableFields); add(GridEvent.didReceiveFieldUpdate(fieldCache.clonedFields)); }, (err) => Log.error(err), @@ -74,15 +74,15 @@ class GridBloc extends Bloc { result.fold( (changesets) { for (final changeset in changesets) { - _rowCache + rowCache .deleteRows(changeset.deletedRows) - .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(_rowCache.rows, listState))); + .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(rowCache.rows, listState))); - _rowCache + rowCache .insertRows(changeset.insertedRows) - .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(_rowCache.rows, listState))); + .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(rowCache.rows, listState))); - _rowCache.updateRows(changeset.updatedRows); + rowCache.updateRows(changeset.updatedRows); } }, (err) => Log.error(err), @@ -107,12 +107,12 @@ class GridBloc extends Bloc { () => result.fold( (fields) { fieldCache.clonedFields = fields.items; - _rowCache.updateWithBlock(grid.blockOrders, fieldCache.unmodifiableFields); + rowCache.updateWithBlock(grid.blockOrders, fieldCache.unmodifiableFields); emit(state.copyWith( grid: Some(grid), fields: fieldCache.clonedFields, - rows: _rowCache.rows, + rows: rowCache.rows, loadingState: GridLoadingState.finish(left(unit)), )); }, @@ -126,7 +126,7 @@ class GridBloc extends Bloc { class GridEvent with _$GridEvent { const factory GridEvent.initial() = InitialGrid; const factory GridEvent.createRow() = _CreateRow; - const factory GridEvent.didReceiveRowUpdate(List rows, GridListState listState) = _DidReceiveRowUpdate; + const factory GridEvent.didReceiveRowUpdate(List rows, GridListState listState) = _DidReceiveRowUpdate; const factory GridEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; } @@ -136,7 +136,7 @@ class GridState with _$GridState { required String gridId, required Option grid, required List fields, - required List rows, + required List rows, required GridLoadingState loadingState, required GridListState listState, }) = _GridState; diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index 08cd01e316..aa4d7343b9 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -36,11 +36,11 @@ class GridHeaderBloc extends Bloc { } Future _startListening() async { - fieldCache.addListener(() {}, onChanged: (fields) { - if (!isClosed) { - add(GridHeaderEvent.didReceiveFieldUpdate(fields)); - } - }); + fieldCache.addListener( + () {}, + onChanged: (fields) => add(GridHeaderEvent.didReceiveFieldUpdate(fields)), + listenWhen: () => !isClosed, + ); } @override 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 0f2118fea1..441ce4c963 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -5,9 +5,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; 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 'package:app_flowy/workspace/application/grid/row/row_service.dart'; - -part 'grid_service.freezed.dart'; class GridService { final String gridId; @@ -74,11 +71,16 @@ class GridFieldCache { _fieldNotifier.addListener(() => onFieldChanged(clonedFields)); } - void addListener(VoidCallback listener, {void Function(List)? onChanged}) { + void addListener(VoidCallback listener, {void Function(List)? onChanged, bool Function()? listenWhen}) { _fieldNotifier.addListener(() { if (onChanged != null) { onChanged(clonedFields); } + + if (listenWhen != null && listenWhen() == false) { + return; + } + listener(); }); } @@ -130,98 +132,3 @@ class GridFieldCache { _fieldNotifier.dispose(); } } - -class GridRowCache { - final String gridId; - UnmodifiableListView _fields = UnmodifiableListView([]); - List _rows = []; - - GridRowCache({required this.gridId}); - - List get rows => [..._rows]; - - void updateWithBlock(List blocks, UnmodifiableListView fields) { - _fields = fields; - _rows = blocks.expand((block) => block.rowOrders).map((rowOrder) { - return RowData.fromBlockRow(gridId, rowOrder, _fields); - }).toList(); - } - - void updateFields(UnmodifiableListView fields) { - if (fields.isEmpty) { - return; - } - - _fields = fields; - _rows = _rows.map((row) => row.copyWith(fields: fields)).toList(); - } - - Option deleteRows(List deletedRows) { - if (deletedRows.isEmpty) { - return none(); - } - - final List newRows = []; - final DeletedIndex deletedIndex = []; - final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; - _rows.asMap().forEach((index, value) { - if (deletedRowMap[value.rowId] == null) { - newRows.add(value); - } else { - deletedIndex.add(Tuple2(index, value)); - } - }); - _rows = newRows; - - return Some(GridListState.delete(deletedIndex)); - } - - Option insertRows(List createdRows) { - if (createdRows.isEmpty) { - return none(); - } - - InsertedIndexs insertIndexs = []; - for (final newRow in createdRows) { - if (newRow.hasIndex()) { - insertIndexs.add(Tuple2(newRow.index, newRow.rowOrder.rowId)); - _rows.insert(newRow.index, _toRowData(newRow.rowOrder)); - } else { - insertIndexs.add(Tuple2(newRow.index, newRow.rowOrder.rowId)); - _rows.add(_toRowData(newRow.rowOrder)); - } - } - - return Some(GridListState.insert(insertIndexs)); - } - - void updateRows(List updatedRows) { - if (updatedRows.isEmpty) { - return; - } - - final List updatedIndexs = []; - for (final updatedRow in updatedRows) { - final index = _rows.indexWhere((row) => row.rowId == updatedRow.rowId); - if (index != -1) { - _rows.removeAt(index); - _rows.insert(index, _toRowData(updatedRow)); - updatedIndexs.add(index); - } - } - } - - RowData _toRowData(RowOrder rowOrder) { - return RowData.fromBlockRow(gridId, rowOrder, _fields); - } -} - -typedef InsertedIndexs = List>; -typedef DeletedIndex = List>; - -@freezed -class GridListState with _$GridListState { - const factory GridListState.insert(InsertedIndexs items) = _Insert; - const factory GridListState.delete(DeletedIndex items) = _Delete; - const factory GridListState.initial() = InitialListState; -} diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart index 93ee70afa0..16f8679b2c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_action_sheet_bloc.dart @@ -11,7 +11,7 @@ part 'row_action_sheet_bloc.freezed.dart'; class RowActionSheetBloc extends Bloc { final RowService _rowService; - RowActionSheetBloc({required RowData rowData}) + RowActionSheetBloc({required GridRow rowData}) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), super(RowActionSheetState.initial(rowData)) { on( @@ -49,10 +49,10 @@ class RowActionSheetEvent with _$RowActionSheetEvent { @freezed class RowActionSheetState with _$RowActionSheetState { const factory RowActionSheetState({ - required RowData rowData, + required GridRow rowData, }) = _RowActionSheetState; - factory RowActionSheetState.initial(RowData rowData) => RowActionSheetState( + factory RowActionSheetState.initial(GridRow rowData) => RowActionSheetState( rowData: rowData, ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 81bb8b190c..e27c3a7b29 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 @@ -18,11 +18,16 @@ class RowBloc extends Bloc { final RowService _rowService; final RowListener _rowlistener; final GridFieldCache _fieldCache; + final GridRowCache _rowCache; - RowBloc({required RowData rowData, required GridFieldCache fieldCache}) - : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), - _fieldCache = fieldCache, + RowBloc({ + required GridRow rowData, + required GridFieldCache fieldCache, + required GridRowCache rowCache, + }) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), _rowlistener = RowListener(rowId: rowData.rowId), + _fieldCache = fieldCache, + _rowCache = rowCache, super(RowState.initial(rowData)) { on( (event, emit) async { @@ -76,37 +81,30 @@ class RowBloc extends Bloc { } Future _startListening() async { - _rowlistener.updateRowNotifier?.addPublishListener((result) { - result.fold( - (row) { - if (!isClosed) { - add(RowEvent.didUpdateRow(row)); - } - }, - (err) => Log.error(err), - ); - }); + _rowlistener.updateRowNotifier?.addPublishListener( + (result) { + result.fold( + (row) => add(RowEvent.didUpdateRow(row)), + (err) => Log.error(err), + ); + }, + listenWhen: () => !isClosed, + ); - _fieldCache.addListener(() { - if (!isClosed) { - add(const RowEvent.fieldsDidUpdate()); - } - }); + _fieldCache.addListener( + () => add(const RowEvent.fieldsDidUpdate()), + listenWhen: () => !isClosed, + ); _rowlistener.start(); } Future _loadRow(Emitter emit) async { - _rowService.getRow().then((result) { - return result.fold( - (row) { - if (!isClosed) { - add(RowEvent.didLoadRow(row)); - } - }, - (err) => Log.error(err), - ); - }); + final data = await _rowCache.getRowData(state.rowData.rowId); + if (isClosed) { + return; + } + data.foldRight(null, (data, _) => add(RowEvent.didLoadRow(data))); } CellDataMap _makeCellDatas(Row row, List fields) { @@ -137,12 +135,12 @@ class RowEvent with _$RowEvent { @freezed class RowState with _$RowState { const factory RowState({ - required RowData rowData, + required GridRow rowData, required Future> row, required Option cellDataMap, }) = _RowState; - factory RowState.initial(RowData rowData) => RowState( + factory RowState.initial(GridRow rowData) => RowState( rowData: rowData, row: Future(() => none()), cellDataMap: none(), 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 412dea9003..25985cb924 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,8 @@ +import 'dart:collection'; + 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/row_entities.pb.dart'; @@ -57,6 +60,115 @@ class RowService { } } +class GridRowCache { + final String gridId; + UnmodifiableListView _fields = UnmodifiableListView([]); + HashMap rowDataMap = HashMap(); + + List _rows = []; + + GridRowCache({required this.gridId}); + + List get rows => [..._rows]; + + Future> getRowData(String rowId) async { + final Row? data = rowDataMap[rowId]; + if (data != null) { + return Future(() => Some(data)); + } + + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + final result = await GridEventGetRow(payload).send(); + return Future(() { + return result.fold( + (data) { + data.freeze(); + rowDataMap[data.id] = data; + return Some(data); + }, + (err) { + Log.error(err); + return none(); + }, + ); + }); + } + + void updateWithBlock(List blocks, UnmodifiableListView fields) { + _fields = fields; + _rows = blocks.expand((block) => block.rowOrders).map((rowOrder) { + return GridRow.fromBlockRow(gridId, rowOrder, _fields); + }).toList(); + } + + void updateFields(UnmodifiableListView fields) { + if (fields.isEmpty) { + return; + } + + _fields = fields; + _rows = _rows.map((row) => row.copyWith(fields: fields)).toList(); + } + + Option deleteRows(List deletedRows) { + if (deletedRows.isEmpty) { + return none(); + } + + final List newRows = []; + final DeletedIndex deletedIndex = []; + final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; + _rows.asMap().forEach((index, value) { + if (deletedRowMap[value.rowId] == null) { + newRows.add(value); + } else { + deletedIndex.add(Tuple2(index, value)); + } + }); + _rows = newRows; + + return Some(GridListState.delete(deletedIndex)); + } + + Option insertRows(List createdRows) { + if (createdRows.isEmpty) { + return none(); + } + + InsertedIndexs insertIndexs = []; + for (final createdRow in createdRows) { + final gridRow = GridRow.fromBlockRow(gridId, createdRow.rowOrder, _fields); + insertIndexs.add(Tuple2(createdRow.index, gridRow.rowId)); + _rows.insert(createdRow.index, gridRow); + } + + return Some(GridListState.insert(insertIndexs)); + } + + void updateRows(List updatedRows) { + if (updatedRows.isEmpty) { + return; + } + + final List updatedIndexs = []; + for (final updatedRow in updatedRows) { + final index = _rows.indexWhere((row) => row.rowId == updatedRow.rowId); + if (index != -1) { + _rows.removeAt(index); + _rows.insert(index, _toRowData(updatedRow)); + updatedIndexs.add(index); + } + } + } + + GridRow _toRowData(RowOrder rowOrder) { + return GridRow.fromBlockRow(gridId, rowOrder, _fields); + } +} + @freezed class CellData with _$CellData { const factory CellData({ @@ -68,20 +180,32 @@ class CellData with _$CellData { } @freezed -class RowData with _$RowData { - const factory RowData({ +class GridRow with _$GridRow { + const factory GridRow({ required String gridId, required String rowId, required List fields, required double height, - }) = _RowData; + required Future> data, + }) = _GridRow; - factory RowData.fromBlockRow(String gridId, RowOrder row, List fields) { - return RowData( + factory GridRow.fromBlockRow(String gridId, RowOrder row, List fields) { + return GridRow( gridId: gridId, - rowId: row.rowId, fields: fields, + rowId: row.rowId, + data: Future(() => none()), height: row.height.toDouble(), ); } } + +typedef InsertedIndexs = List>; +typedef DeletedIndex = List>; + +@freezed +class GridListState with _$GridListState { + const factory GridListState.insert(InsertedIndexs items) = _Insert; + const factory GridListState.delete(DeletedIndex items) = _Delete; + const factory GridListState.initial() = InitialListState; +} 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 74215f4b80..1acdf5db2f 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/row/row_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; @@ -221,14 +222,19 @@ class _GridRowsState extends State<_GridRows> { ); } - Widget _renderRow(BuildContext context, RowData rowData, Animation animation) { - final fieldCache = context.read().fieldCache; + Widget _renderRow(BuildContext context, GridRow rowData, Animation animation) { + final bloc = context.read(); + final fieldCache = bloc.fieldCache; + final rowCache = bloc.rowCache; return SizeTransition( sizeFactor: animation, child: GridRowWidget( - data: rowData, - fieldCache: fieldCache, + blocBuilder: () => RowBloc( + rowData: rowData, + fieldCache: fieldCache, + rowCache: rowCache, + ), key: ValueKey(rowData.rowId), ), ); 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 edac8bc2fe..6a22c88ca5 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 @@ -12,9 +12,12 @@ import 'package:provider/provider.dart'; import 'row_action_sheet.dart'; class GridRowWidget extends StatefulWidget { - final RowData data; - final GridFieldCache fieldCache; - const GridRowWidget({required this.data, required this.fieldCache, Key? key}) : super(key: key); + final RowBloc Function() blocBuilder; + + const GridRowWidget({ + required this.blocBuilder, + Key? key, + }) : super(key: key); @override State createState() => _GridRowWidgetState(); @@ -26,7 +29,8 @@ class _GridRowWidgetState extends State { @override void initState() { - _rowBloc = getIt(param1: widget.data, param2: widget.fieldCache)..add(const RowEvent.initial()); + _rowBloc = widget.blocBuilder(); + _rowBloc.add(const RowEvent.initial()); _rowStateNotifier = _RegionStateNotifier(); super.initState(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart index 458e934756..40e77d9c43 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_action_sheet.dart @@ -14,7 +14,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class GridRowActionSheet extends StatelessWidget { - final RowData rowData; + final GridRow rowData; const GridRowActionSheet({required this.rowData, Key? key}) : super(key: key); @override diff --git a/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart b/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart index 0079ba51a1..7eaf139f0c 100644 --- a/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart +++ b/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart @@ -31,12 +31,18 @@ class PublishNotifier extends ChangeNotifier { T? get currentValue => _value; - void addPublishListener(void Function(T) callback) { + void addPublishListener(void Function(T) callback, {bool Function()? listenWhen}) { super.addListener( () { - if (_value != null) { - callback(_value!); + if (_value == null) { + return; } + + if (listenWhen != null && listenWhen() == false) { + return; + } + + callback(_value!); }, ); } From c82754f284ea15bb3fd61e02150e8ed5246090a7 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 16 Apr 2022 22:26:34 +0800 Subject: [PATCH 20/26] chore: refactor row cache with row listener --- .../workspace/application/grid/grid_bloc.dart | 63 +++------ .../application/grid/grid_header_bloc.dart | 1 - .../application/grid/grid_listener.dart | 4 +- .../application/grid/grid_service.dart | 56 ++++---- .../application/grid/row/row_bloc.dart | 2 +- .../application/grid/row/row_service.dart | 123 ++++++++++++------ .../grid/setting/property_bloc.dart | 22 +--- .../plugins/grid/src/grid_page.dart | 3 +- .../grid/src/widgets/header/grid_header.dart | 1 - .../grid/src/widgets/row/grid_row.dart | 1 - .../src/client_grid/grid_meta_pad.rs | 2 +- 11 files changed, 148 insertions(+), 130 deletions(-) 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 5782371e7a..4d54081980 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -1,13 +1,10 @@ import 'dart:async'; import 'package:dartz/dartz.dart'; -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; 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 'field/grid_listenr.dart'; -import 'grid_listener.dart'; import 'grid_service.dart'; import 'row/row_service.dart'; @@ -15,16 +12,12 @@ part 'grid_bloc.freezed.dart'; class GridBloc extends Bloc { final GridService _gridService; - final GridListener _gridListener; - final GridFieldsListener _fieldListener; final GridFieldCache fieldCache; final GridRowCache rowCache; GridBloc({required View view}) - : _fieldListener = GridFieldsListener(gridId: view.id), - _gridService = GridService(gridId: view.id), - _gridListener = GridListener(gridId: view.id), - fieldCache = GridFieldCache(), + : _gridService = GridService(gridId: view.id), + fieldCache = GridFieldCache(gridId: view.id), rowCache = GridRowCache(gridId: view.id), super(GridState.initial(view.id)) { on( @@ -41,7 +34,7 @@ class GridBloc extends Bloc { emit(state.copyWith(rows: value.rows, listState: value.listState)); }, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - emit(state.copyWith(rows: rowCache.rows, fields: value.fields)); + emit(state.copyWith(rows: rowCache.clonedRows, fields: value.fields)); }, ); }, @@ -51,44 +44,22 @@ class GridBloc extends Bloc { @override Future close() async { await _gridService.closeGrid(); - await _fieldListener.stop(); - await _gridListener.stop(); + await fieldCache.dispose(); + await rowCache.dispose(); fieldCache.dispose(); return super.close(); } void _startListening() { - _fieldListener.updateFieldsNotifier?.addPublishListener((result) { - result.fold( - (changeset) { - fieldCache.applyChangeset(changeset); - rowCache.updateFields(fieldCache.unmodifiableFields); - add(GridEvent.didReceiveFieldUpdate(fieldCache.clonedFields)); - }, - (err) => Log.error(err), - ); - }); - _fieldListener.start(); + fieldCache.addListener( + onChanged: (fields) => add(GridEvent.didReceiveFieldUpdate(fields)), + listenWhen: () => !isClosed, + ); - _gridListener.rowsUpdateNotifier.addPublishListener((result) { - result.fold( - (changesets) { - for (final changeset in changesets) { - rowCache - .deleteRows(changeset.deletedRows) - .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(rowCache.rows, listState))); - - rowCache - .insertRows(changeset.insertedRows) - .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(rowCache.rows, listState))); - - rowCache.updateRows(changeset.updatedRows); - } - }, - (err) => Log.error(err), - ); - }); - _gridListener.start(); + rowCache.addListener( + onChanged: (rows, listState) => add(GridEvent.didReceiveRowUpdate(rowCache.clonedRows, listState)), + listenWhen: () => !isClosed, + ); } Future _loadGrid(Emitter emit) async { @@ -106,13 +77,13 @@ class GridBloc extends Bloc { return Future( () => result.fold( (fields) { - fieldCache.clonedFields = fields.items; + fieldCache.fields = fields.items; rowCache.updateWithBlock(grid.blockOrders, fieldCache.unmodifiableFields); emit(state.copyWith( grid: Some(grid), fields: fieldCache.clonedFields, - rows: rowCache.rows, + rows: rowCache.clonedRows, loadingState: GridLoadingState.finish(left(unit)), )); }, @@ -126,7 +97,7 @@ class GridBloc extends Bloc { class GridEvent with _$GridEvent { const factory GridEvent.initial() = InitialGrid; const factory GridEvent.createRow() = _CreateRow; - const factory GridEvent.didReceiveRowUpdate(List rows, GridListState listState) = _DidReceiveRowUpdate; + const factory GridEvent.didReceiveRowUpdate(List rows, GridRowChangeReason listState) = _DidReceiveRowUpdate; const factory GridEvent.didReceiveFieldUpdate(List fields) = _DidReceiveFieldUpdate; } @@ -138,7 +109,7 @@ class GridState with _$GridState { required List fields, required List rows, required GridLoadingState loadingState, - required GridListState listState, + required GridRowChangeReason listState, }) = _GridState; factory GridState.initial(String gridId) => GridState( diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index aa4d7343b9..90007ba8c2 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -37,7 +37,6 @@ class GridHeaderBloc extends Bloc { Future _startListening() async { fieldCache.addListener( - () {}, onChanged: (fields) => add(GridHeaderEvent.didReceiveFieldUpdate(fields)), listenWhen: () => !isClosed, ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart index 862cd95d74..fcff6fa15f 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart @@ -7,12 +7,12 @@ import 'dart:async'; import 'dart:typed_data'; import 'package:app_flowy/core/notification_helper.dart'; -class GridListener { +class GridRowListener { final String gridId; PublishNotifier, FlowyError>> rowsUpdateNotifier = PublishNotifier(comparable: null); GridNotificationListener? _listener; - GridListener({required this.gridId}); + GridRowListener({required this.gridId}); void start() { _listener = GridNotificationListener( 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 441ce4c963..0d24e9974c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -1,5 +1,7 @@ +import 'package:app_flowy/workspace/application/grid/field/grid_listenr.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-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; @@ -50,42 +52,56 @@ class FieldsNotifier extends ChangeNotifier { } class GridFieldCache { + final String gridId; + late final GridFieldsListener _fieldListener; final FieldsNotifier _fieldNotifier = FieldsNotifier(); - GridFieldCache(); - - void applyChangeset(GridFieldChangeset changeset) { - _removeFields(changeset.deletedFields); - _insertFields(changeset.insertedFields); - _updateFields(changeset.updatedFields); + GridFieldCache({required this.gridId}) { + _fieldListener = GridFieldsListener(gridId: gridId); + _fieldListener.updateFieldsNotifier?.addPublishListener((result) { + result.fold( + (changeset) { + _deleteFields(changeset.deletedFields); + _insertFields(changeset.insertedFields); + _updateFields(changeset.updatedFields); + }, + (err) => Log.error(err), + ); + }); + _fieldListener.start(); } + Future dispose() async { + await _fieldListener.stop(); + _fieldNotifier.dispose(); + } + + void applyChangeset(GridFieldChangeset changeset) {} + UnmodifiableListView get unmodifiableFields => UnmodifiableListView(_fieldNotifier.fields); List get clonedFields => [..._fieldNotifier.fields]; - set clonedFields(List fields) { + set fields(List fields) { _fieldNotifier.fields = [...fields]; } - void listenOnFieldChanged(void Function(List) onFieldChanged) { - _fieldNotifier.addListener(() => onFieldChanged(clonedFields)); - } - - void addListener(VoidCallback listener, {void Function(List)? onChanged, bool Function()? listenWhen}) { + void addListener({VoidCallback? listener, void Function(List)? onChanged, bool Function()? listenWhen}) { _fieldNotifier.addListener(() { - if (onChanged != null) { - onChanged(clonedFields); - } - if (listenWhen != null && listenWhen() == false) { return; } - listener(); + if (onChanged != null) { + onChanged(clonedFields); + } + + if (listener != null) { + listener(); + } }); } - void _removeFields(List deletedFields) { + void _deleteFields(List deletedFields) { if (deletedFields.isEmpty) { return; } @@ -127,8 +143,4 @@ class GridFieldCache { } _fieldNotifier.fields = fields; } - - void dispose() { - _fieldNotifier.dispose(); - } } 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 e27c3a7b29..4ec7ce3a17 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 @@ -92,7 +92,7 @@ class RowBloc extends Bloc { ); _fieldCache.addListener( - () => add(const RowEvent.fieldsDidUpdate()), + listener: () => add(const RowEvent.fieldsDidUpdate()), listenWhen: () => !isClosed, ); 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 25985cb924..23cecb1489 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,11 +1,13 @@ import 'dart:collection'; +import 'package:app_flowy/workspace/application/grid/grid_listener.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/row_entities.pb.dart'; +import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'row_service.freezed.dart'; @@ -60,19 +62,71 @@ class RowService { } } +class RowsNotifier extends ChangeNotifier { + List _rows = []; + GridRowChangeReason _changeReason = const InitialListState(); + + void updateRows(List rows, GridRowChangeReason changeReason) { + _rows = rows; + _changeReason = changeReason; + + changeReason.map( + insert: (_) => notifyListeners(), + delete: (_) => notifyListeners(), + update: (_) => notifyListeners(), + initial: (_) {}, + ); + } + + List get rows => _rows; +} + class GridRowCache { final String gridId; + late GridRowListener _rowsListener; + final HashMap _rowDataMap = HashMap(); + UnmodifiableListView _fields = UnmodifiableListView([]); - HashMap rowDataMap = HashMap(); + final RowsNotifier _rowNotifier = RowsNotifier(); - List _rows = []; + GridRowCache({required this.gridId}) { + _rowsListener = GridRowListener(gridId: gridId); + _rowsListener.rowsUpdateNotifier.addPublishListener((result) { + result.fold( + (changesets) { + for (final changeset in changesets) { + _deleteRows(changeset.deletedRows); + _insertRows(changeset.insertedRows); + _updateRows(changeset.updatedRows); + } + }, + (err) => Log.error(err), + ); + }); + _rowsListener.start(); + } - GridRowCache({required this.gridId}); + List get clonedRows => [..._rowNotifier.rows]; - List get rows => [..._rows]; + Future dispose() async { + await _rowsListener.stop(); + _rowNotifier.dispose(); + } + + void addListener({void Function(List, GridRowChangeReason)? onChanged, bool Function()? listenWhen}) { + _rowNotifier.addListener(() { + if (listenWhen != null && listenWhen() == false) { + return; + } + + if (onChanged != null) { + onChanged(clonedRows, _rowNotifier._changeReason); + } + }); + } Future> getRowData(String rowId) async { - final Row? data = rowDataMap[rowId]; + final Row? data = _rowDataMap[rowId]; if (data != null) { return Future(() => Some(data)); } @@ -86,7 +140,7 @@ class GridRowCache { return result.fold( (data) { data.freeze(); - rowDataMap[data.id] = data; + _rowDataMap[data.id] = data; return Some(data); }, (err) { @@ -99,73 +153,65 @@ class GridRowCache { void updateWithBlock(List blocks, UnmodifiableListView fields) { _fields = fields; - _rows = blocks.expand((block) => block.rowOrders).map((rowOrder) { + final newRows = blocks.expand((block) => block.rowOrders).map((rowOrder) { return GridRow.fromBlockRow(gridId, rowOrder, _fields); }).toList(); + + _rowNotifier.updateRows(newRows, const GridRowChangeReason.initial()); } - void updateFields(UnmodifiableListView fields) { - if (fields.isEmpty) { - return; - } - - _fields = fields; - _rows = _rows.map((row) => row.copyWith(fields: fields)).toList(); - } - - Option deleteRows(List deletedRows) { + void _deleteRows(List deletedRows) { if (deletedRows.isEmpty) { - return none(); + return; } final List newRows = []; final DeletedIndex deletedIndex = []; final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; - _rows.asMap().forEach((index, value) { + + _rowNotifier.rows.asMap().forEach((index, value) { if (deletedRowMap[value.rowId] == null) { newRows.add(value); } else { deletedIndex.add(Tuple2(index, value)); } }); - _rows = newRows; - return Some(GridListState.delete(deletedIndex)); + _rowNotifier.updateRows(newRows, GridRowChangeReason.delete(deletedIndex)); } - Option insertRows(List createdRows) { + void _insertRows(List createdRows) { if (createdRows.isEmpty) { - return none(); + return; } InsertedIndexs insertIndexs = []; + final List newRows = _rowNotifier.rows; for (final createdRow in createdRows) { final gridRow = GridRow.fromBlockRow(gridId, createdRow.rowOrder, _fields); insertIndexs.add(Tuple2(createdRow.index, gridRow.rowId)); - _rows.insert(createdRow.index, gridRow); + newRows.insert(createdRow.index, gridRow); } - - return Some(GridListState.insert(insertIndexs)); + _rowNotifier.updateRows(newRows, GridRowChangeReason.insert(insertIndexs)); } - void updateRows(List updatedRows) { + void _updateRows(List updatedRows) { if (updatedRows.isEmpty) { return; } final List updatedIndexs = []; - for (final updatedRow in updatedRows) { - final index = _rows.indexWhere((row) => row.rowId == updatedRow.rowId); + final List newRows = _rowNotifier.rows; + for (final rowOrder in updatedRows) { + final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId); if (index != -1) { - _rows.removeAt(index); - _rows.insert(index, _toRowData(updatedRow)); + newRows.removeAt(index); + newRows.insert(index, GridRow.fromBlockRow(gridId, rowOrder, _fields)); updatedIndexs.add(index); } } - } - GridRow _toRowData(RowOrder rowOrder) { - return GridRow.fromBlockRow(gridId, rowOrder, _fields); + _rowNotifier.updateRows(newRows, GridRowChangeReason.update(updatedIndexs)); } } @@ -204,8 +250,9 @@ typedef InsertedIndexs = List>; typedef DeletedIndex = List>; @freezed -class GridListState with _$GridListState { - const factory GridListState.insert(InsertedIndexs items) = _Insert; - const factory GridListState.delete(DeletedIndex items) = _Delete; - const factory GridListState.initial() = InitialListState; +class GridRowChangeReason with _$GridRowChangeReason { + const factory GridRowChangeReason.insert(InsertedIndexs items) = _Insert; + const factory GridRowChangeReason.delete(DeletedIndex items) = _Delete; + const factory GridRowChangeReason.update(List indexs) = _Update; + const factory GridRowChangeReason.initial() = InitialListState; } diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index 634bb1e56d..bf87851ebb 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -1,5 +1,4 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; -import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart'; import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; @@ -11,13 +10,11 @@ part 'property_bloc.freezed.dart'; class GridPropertyBloc extends Bloc { final FieldService _service; - final GridFieldsListener _fieldListener; final GridFieldCache _fieldCache; GridPropertyBloc({required String gridId, required List fields}) : _service = FieldService(gridId: gridId), - _fieldListener = GridFieldsListener(gridId: gridId), - _fieldCache = GridFieldCache(), + _fieldCache = GridFieldCache(gridId: gridId), super(GridPropertyState.initial(gridId, fields)) { on( (event, emit) async { @@ -45,22 +42,15 @@ class GridPropertyBloc extends Bloc { @override Future close() async { - await _fieldListener.stop(); - _fieldCache.dispose(); + await _fieldCache.dispose(); return super.close(); } void _startListening() { - _fieldListener.updateFieldsNotifier?.addPublishListener((result) { - result.fold( - (changeset) { - _fieldCache.applyChangeset(changeset); - add(GridPropertyEvent.didReceiveFieldUpdate(_fieldCache.clonedFields)); - }, - (err) => Log.error(err), - ); - }); - _fieldListener.start(); + _fieldCache.addListener( + onChanged: (fields) => add(GridPropertyEvent.didReceiveFieldUpdate(_fieldCache.clonedFields)), + listenWhen: () => !isClosed, + ); } } 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 1acdf5db2f..1a5f64c03a 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 @@ -205,7 +205,8 @@ class _GridRowsState extends State<_GridRows> { ); } }, - initial: (updatedIndexs) {}, + initial: (_) {}, + update: (_) {}, ); }, buildWhen: (previous, current) => false, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 22bd59eb4d..63a397710c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -5,7 +5,6 @@ import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; 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 6a22c88ca5..7f704991b7 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 @@ -1,4 +1,3 @@ -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/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart'; diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index 2cf56fd5f0..f40b93233e 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -215,7 +215,7 @@ impl GridMetaPad { |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) { None => Ok(None), Some(index) => { - debug_assert_eq!(index, from_index); + // debug_assert_eq!(index, from_index); let field_meta = grid_meta.fields.remove(index); grid_meta.fields.insert(to_index, field_meta); Ok(Some(())) From e647fd0a5749c5b408760f7e19efd9ffff24d630 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Apr 2022 08:04:29 +0800 Subject: [PATCH 21/26] chore: add cell cache --- .../app_flowy/lib/startup/deps_resolver.dart | 12 +-- .../{cell_bloc => cell}/cell_listener.dart | 0 .../application/grid/cell/cell_service.dart | 75 +++++++++++++++++++ .../checkbox_cell_bloc.dart | 8 +- .../{cell_bloc => cell}/date_cell_bloc.dart | 14 ++-- .../{cell_bloc => cell}/number_cell_bloc.dart | 8 +- .../select_option_service.dart | 0 .../selection_cell_bloc.dart | 10 +-- .../selection_editor_bloc.dart | 6 +- .../{cell_bloc => cell}/text_cell_bloc.dart | 8 +- .../grid/cell_bloc/cell_service.dart | 35 --------- .../workspace/application/grid/prelude.dart | 12 +-- .../application/grid/row/row_bloc.dart | 4 +- .../application/grid/row/row_service.dart | 6 +- .../grid/src/widgets/cell/cell_builder.dart | 2 +- .../grid/src/widgets/cell/checkbox_cell.dart | 2 +- .../grid/src/widgets/cell/date_cell.dart | 2 +- .../grid/src/widgets/cell/number_cell.dart | 2 +- .../cell/selection_cell/selection_cell.dart | 4 +- .../cell/selection_cell/selection_editor.dart | 6 +- .../grid/src/widgets/cell/text_cell.dart | 2 +- .../src/widgets/row/cell/number_cell.dart | 2 +- .../grid/src/widgets/row/number_cell.dart | 2 +- 23 files changed, 131 insertions(+), 91 deletions(-) rename frontend/app_flowy/lib/workspace/application/grid/{cell_bloc => cell}/cell_listener.dart (100%) create mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart rename frontend/app_flowy/lib/workspace/application/grid/{cell_bloc => cell}/checkbox_cell_bloc.dart (92%) rename frontend/app_flowy/lib/workspace/application/grid/{cell_bloc => cell}/date_cell_bloc.dart (87%) rename frontend/app_flowy/lib/workspace/application/grid/{cell_bloc => cell}/number_cell_bloc.dart (93%) rename frontend/app_flowy/lib/workspace/application/grid/{cell_bloc => cell}/select_option_service.dart (100%) rename frontend/app_flowy/lib/workspace/application/grid/{cell_bloc => cell}/selection_cell_bloc.dart (89%) rename frontend/app_flowy/lib/workspace/application/grid/{cell_bloc => cell}/selection_editor_bloc.dart (97%) rename frontend/app_flowy/lib/workspace/application/grid/{cell_bloc => cell}/text_cell_bloc.dart (86%) delete mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_service.dart diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 47267cc2c9..7e26566367 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -171,32 +171,32 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => TextCellBloc( service: CellService(), cellData: cellData, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => SelectionCellBloc( cellData: cellData, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => NumberCellBloc( cellData: cellData, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => DateCellBloc( - cellData: cellData, + cellIdentifier: cellData, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => CheckboxCellBloc( service: CellService(), cellData: cellData, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart similarity index 100% rename from frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_listener.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/cell_listener.dart 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 new file mode 100644 index 0000000000..a4a3cf2d60 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -0,0 +1,75 @@ +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/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; + +class CellService { + CellService(); + + Future> updateCell({ + required String gridId, + required String fieldId, + required String rowId, + required String data, + }) { + final payload = CellChangeset.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId + ..data = data; + return GridEventUpdateCell(payload).send(); + } + + Future> getCell({ + required String gridId, + required String fieldId, + required String rowId, + }) { + final payload = CellIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId; + return GridEventGetCell(payload).send(); + } +} + +class CellCache { + final CellService _cellService; + final HashMap _cellDataMap = HashMap(); + + CellCache() : _cellService = CellService(); + + Future> getCellData(GridCellIdentifier 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(GridCellIdentifier identifier) { + return "${identifier.rowId}/${identifier.field.id}"; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart similarity index 92% rename from frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart index 3a4500eb45..2fae2464be 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/checkbox_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart'; +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; @@ -15,7 +15,7 @@ class CheckboxCellBloc extends Bloc { CheckboxCellBloc({ required CellService service, - required CellData cellData, + required GridCellIdentifier cellData, }) : _service = service, _listener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), super(CheckboxCellState.initial(cellData)) { @@ -87,11 +87,11 @@ class CheckboxCellEvent with _$CheckboxCellEvent { @freezed class CheckboxCellState with _$CheckboxCellState { const factory CheckboxCellState({ - required CellData cellData, + required GridCellIdentifier cellData, required bool isSelected, }) = _CheckboxCellState; - factory CheckboxCellState.initial(CellData cellData) { + factory CheckboxCellState.initial(GridCellIdentifier cellData) { return CheckboxCellState(cellData: cellData, isSelected: _isSelected(cellData.cell)); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart similarity index 87% rename from frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index d7e0c078aa..e4c94230a9 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart'; +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'; @@ -15,11 +15,11 @@ class DateCellBloc extends Bloc { final CellListener _cellListener; final SingleFieldListener _fieldListener; - DateCellBloc({required CellData cellData}) + DateCellBloc({required GridCellIdentifier cellIdentifier}) : _service = CellService(), - _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), - _fieldListener = SingleFieldListener(fieldId: cellData.field.id), - super(DateCellState.initial(cellData)) { + _cellListener = CellListener(rowId: cellIdentifier.rowId, fieldId: cellIdentifier.field.id), + _fieldListener = SingleFieldListener(fieldId: cellIdentifier.field.id), + super(DateCellState.initial(cellIdentifier)) { on( (event, emit) async { event.map( @@ -106,13 +106,13 @@ class DateCellEvent with _$DateCellEvent { @freezed class DateCellState with _$DateCellState { const factory DateCellState({ - required CellData cellData, + required GridCellIdentifier cellData, required String content, required Field field, DateTime? selectedDay, }) = _DateCellState; - factory DateCellState.initial(CellData cellData) => DateCellState( + factory DateCellState.initial(GridCellIdentifier cellData) => DateCellState( cellData: cellData, field: cellData.field, content: cellData.cell?.content ?? "", diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart similarity index 93% rename from frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart index fbc432c557..531e06062a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/number_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart'; +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'; @@ -16,7 +16,7 @@ class NumberCellBloc extends Bloc { final SingleFieldListener _fieldListener; NumberCellBloc({ - required CellData cellData, + required GridCellIdentifier cellData, }) : _service = CellService(), _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), _fieldListener = SingleFieldListener(fieldId: cellData.field.id), @@ -105,11 +105,11 @@ class NumberCellEvent with _$NumberCellEvent { @freezed class NumberCellState with _$NumberCellState { const factory NumberCellState({ - required CellData cellData, + required GridCellIdentifier cellData, required String content, }) = _NumberCellState; - factory NumberCellState.initial(CellData cellData) { + factory NumberCellState.initial(GridCellIdentifier cellData) { return NumberCellState(cellData: cellData, content: cellData.cell?.content ?? ""); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart similarity index 100% rename from frontend/app_flowy/lib/workspace/application/grid/cell_bloc/select_option_service.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart similarity index 89% rename from frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index ae7c48d81f..95ccedd086 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -1,5 +1,5 @@ -import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart'; -import 'package:app_flowy/workspace/application/grid/cell_bloc/select_option_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_listener.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:flowy_sdk/log.dart'; @@ -16,7 +16,7 @@ class SelectionCellBloc extends Bloc { final SingleFieldListener _fieldListener; SelectionCellBloc({ - required CellData cellData, + required GridCellIdentifier cellData, }) : _service = SelectOptionService(), _cellListener = CellListener(rowId: cellData.rowId, fieldId: cellData.field.id), _fieldListener = SingleFieldListener(fieldId: cellData.field.id), @@ -93,12 +93,12 @@ class SelectionCellEvent with _$SelectionCellEvent { @freezed class SelectionCellState with _$SelectionCellState { const factory SelectionCellState({ - required CellData cellData, + required GridCellIdentifier cellData, required List options, required List selectedOptions, }) = _SelectionCellState; - factory SelectionCellState.initial(CellData cellData) => SelectionCellState( + factory SelectionCellState.initial(GridCellIdentifier cellData) => SelectionCellState( cellData: cellData, options: [], selectedOptions: [], diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart similarity index 97% rename from frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index 0d1b2705e3..1636c293ed 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dart'; +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'; @@ -18,7 +18,7 @@ class SelectOptionEditorBloc extends Bloc options, required List selectedOptions, }) : _selectOptionService = SelectOptionService(), @@ -174,7 +174,7 @@ class SelectOptionEditorState with _$SelectOptionEditorState { }) = _SelectOptionEditorState; factory SelectOptionEditorState.initial( - CellData cellData, + GridCellIdentifier cellData, List options, List selectedOptions, ) { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/text_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart similarity index 86% rename from frontend/app_flowy/lib/workspace/application/grid/cell_bloc/text_cell_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart index 5af39bbd9f..e45cb7c1f1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/text_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart @@ -11,7 +11,7 @@ class TextCellBloc extends Bloc { TextCellBloc({ required this.service, - required CellData cellData, + required GridCellIdentifier cellData, }) : super(TextCellState.initial(cellData)) { on( (event, emit) async { @@ -53,7 +53,7 @@ class TextCellBloc extends Bloc { @freezed class TextCellEvent with _$TextCellEvent { const factory TextCellEvent.initial() = _InitialCell; - const factory TextCellEvent.didReceiveCellData(CellData cellData) = _DidReceiveCellData; + const factory TextCellEvent.didReceiveCellData(GridCellIdentifier cellData) = _DidReceiveCellData; const factory TextCellEvent.updateText(String text) = _UpdateText; } @@ -61,10 +61,10 @@ class TextCellEvent with _$TextCellEvent { class TextCellState with _$TextCellState { const factory TextCellState({ required String content, - required CellData cellData, + required GridCellIdentifier cellData, }) = _TextCellState; - factory TextCellState.initial(CellData cellData) => TextCellState( + factory TextCellState.initial(GridCellIdentifier cellData) => TextCellState( content: cellData.cell?.content ?? "", cellData: cellData, ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_service.dart deleted file mode 100644 index dfce5d3993..0000000000 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/cell_service.dart +++ /dev/null @@ -1,35 +0,0 @@ -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/protobuf/flowy-grid-data-model/grid.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; - -class CellService { - CellService(); - - Future> updateCell({ - required String gridId, - required String fieldId, - required String rowId, - required String data, - }) { - final payload = CellChangeset.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId - ..data = data; - return GridEventUpdateCell(payload).send(); - } - - Future> getCell({ - required String gridId, - required String fieldId, - required String rowId, - }) { - final payload = CellIdentifierPayload.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId; - return GridEventGetCell(payload).send(); - } -} diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 1308e1a67e..16287db6bf 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -16,12 +16,12 @@ export 'field/type_option/number_bloc.dart'; export 'field/type_option/single_select_bloc.dart'; // Cell -export 'cell_bloc/text_cell_bloc.dart'; -export 'cell_bloc/number_cell_bloc.dart'; -export 'cell_bloc/selection_cell_bloc.dart'; -export 'cell_bloc/date_cell_bloc.dart'; -export 'cell_bloc/checkbox_cell_bloc.dart'; -export 'cell_bloc/cell_service.dart'; +export 'cell/text_cell_bloc.dart'; +export 'cell/number_cell_bloc.dart'; +export 'cell/selection_cell_bloc.dart'; +export 'cell/date_cell_bloc.dart'; +export 'cell/checkbox_cell_bloc.dart'; +export 'cell/cell_service.dart'; // Setting export 'setting/setting_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 4ec7ce3a17..69731a0329 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 @@ -12,7 +12,7 @@ import 'package:dartz/dartz.dart'; part 'row_bloc.freezed.dart'; -typedef CellDataMap = LinkedHashMap; +typedef CellDataMap = LinkedHashMap; class RowBloc extends Bloc { final RowService _rowService; @@ -111,7 +111,7 @@ class RowBloc extends Bloc { var map = CellDataMap.new(); for (final field in fields) { if (field.visibility) { - map[field.id] = CellData( + map[field.id] = GridCellIdentifier( rowId: row.id, gridId: _rowService.gridId, cell: row.cellByFieldId[field.id], 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 23cecb1489..c35466f5c3 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,10 +84,10 @@ class RowsNotifier extends ChangeNotifier { class GridRowCache { final String gridId; late GridRowListener _rowsListener; + final RowsNotifier _rowNotifier = RowsNotifier(); final HashMap _rowDataMap = HashMap(); UnmodifiableListView _fields = UnmodifiableListView([]); - final RowsNotifier _rowNotifier = RowsNotifier(); GridRowCache({required this.gridId}) { _rowsListener = GridRowListener(gridId: gridId); @@ -216,8 +216,8 @@ class GridRowCache { } @freezed -class CellData with _$CellData { - const factory CellData({ +class GridCellIdentifier with _$GridCellIdentifier { + const factory GridCellIdentifier({ required String gridId, required String rowId, required Field field, 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 2b00a13a10..7af09ca6b5 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 @@ -7,7 +7,7 @@ import 'number_cell.dart'; import 'selection_cell/selection_cell.dart'; import 'text_cell.dart'; -Widget buildGridCell(CellData cellData) { +Widget buildGridCell(GridCellIdentifier cellData) { final key = ValueKey(cellData.field.id + cellData.rowId); switch (cellData.field.fieldType) { case FieldType.Checkbox: 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 b4095c71d9..312c8ef71c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart @@ -6,7 +6,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class CheckboxCell extends StatefulWidget { - final CellData cellData; + final GridCellIdentifier cellData; const CheckboxCell({ required this.cellData, 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 b913a09e4e..33f99c2386 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 @@ -9,7 +9,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:table_calendar/table_calendar.dart'; class DateCell extends GridCell { - final CellData cellData; + final GridCellIdentifier cellData; const DateCell({ required this.cellData, 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 cd4db24c7a..56946945ae 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class NumberCell extends GridCell { - final CellData cellData; + final GridCellIdentifier cellData; const NumberCell({ required this.cellData, 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 a7cf70a64e..4e0cba65bb 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 @@ -8,7 +8,7 @@ import 'extension.dart'; import 'selection_editor.dart'; class SingleSelectCell extends GridCell { - final CellData cellData; + final GridCellIdentifier cellData; const SingleSelectCell({ required this.cellData, @@ -64,7 +64,7 @@ class _SingleSelectCellState extends State { //---------------------------------------------------------------- class MultiSelectCell extends GridCell { - final CellData cellData; + final GridCellIdentifier cellData; const MultiSelectCell({ required this.cellData, 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 4ebd4407b0..e3e0b39f0a 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,5 +1,5 @@ import 'dart:collection'; -import 'package:app_flowy/workspace/application/grid/cell_bloc/selection_editor_bloc.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'; @@ -25,7 +25,7 @@ import 'text_field.dart'; const double _editorPannelWidth = 300; class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { - final CellData cellData; + final GridCellIdentifier cellData; final List options; final List selectedOptions; final VoidCallback onDismissed; @@ -66,7 +66,7 @@ class SelectOptionCellEditor extends StatelessWidget with FlowyOverlayDelegate { static void show( BuildContext context, - CellData cellData, + GridCellIdentifier cellData, List options, List selectedOptions, VoidCallback onDismissed, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart index 543a337b9b..e6649853a5 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 @@ -6,7 +6,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'cell_container.dart'; class GridTextCell extends GridCell { - final CellData cellData; + final GridCellIdentifier cellData; const GridTextCell({ required this.cellData, Key? key, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/cell/number_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/cell/number_cell.dart index 41b8cf6ee5..6e4c430986 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/cell/number_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/cell/number_cell.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class NumberCell extends StatefulWidget { - final CellData cellData; + final GridCellIdentifier cellData; const NumberCell({ required this.cellData, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/number_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/number_cell.dart index 41b8cf6ee5..6e4c430986 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/number_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/number_cell.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class NumberCell extends StatefulWidget { - final CellData cellData; + final GridCellIdentifier cellData; const NumberCell({ required this.cellData, From 0a19364ea7b6af05c458e095cd40cd7670a70df3 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Apr 2022 09:46:38 +0800 Subject: [PATCH 22/26] chore: remove row listener from rowbloc --- .../workspace/application/grid/grid_bloc.dart | 1 - .../application/grid/grid_listener.dart | 2 +- .../application/grid/row/row_bloc.dart | 23 ++--- .../application/grid/row/row_service.dart | 95 +++++++++++++++---- .../plugins/grid/src/grid_page.dart | 10 +- .../flowy-grid/dart_notification.pbenum.dart | 12 +-- .../flowy-grid/dart_notification.pbjson.dart | 10 +- .../flowy-grid/src/dart_notification.rs | 8 +- .../src/protobuf/model/dart_notification.rs | 30 +++--- .../protobuf/proto/dart_notification.proto | 8 +- .../src/services/block_meta_manager.rs | 65 +++++-------- .../flowy-grid/src/services/grid_editor.rs | 16 ++-- .../src/client_grid/grid_meta_pad.rs | 2 +- 13 files changed, 158 insertions(+), 124 deletions(-) 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 4d54081980..f38e874453 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -46,7 +46,6 @@ class GridBloc extends Bloc { await _gridService.closeGrid(); await fieldCache.dispose(); await rowCache.dispose(); - fieldCache.dispose(); return super.close(); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart index fcff6fa15f..e6c7dc9de7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_listener.dart @@ -23,7 +23,7 @@ class GridRowListener { void _handler(GridNotification ty, Either result) { switch (ty) { - case GridNotification.DidUpdateGridBlock: + case GridNotification.DidUpdateGridRow: result.fold( (payload) => rowsUpdateNotifier.value = left([GridRowsChangeset.fromBuffer(payload)]), (error) => rowsUpdateNotifier.value = right(error), 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 69731a0329..1f026a0af6 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,12 +1,9 @@ import 'dart:collection'; - import 'package:app_flowy/workspace/application/grid/grid_service.dart'; -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; -import 'row_listener.dart'; import 'row_service.dart'; import 'package:dartz/dartz.dart'; @@ -16,7 +13,7 @@ typedef CellDataMap = LinkedHashMap; class RowBloc extends Bloc { final RowService _rowService; - final RowListener _rowlistener; + final GridFieldCache _fieldCache; final GridRowCache _rowCache; @@ -25,7 +22,6 @@ class RowBloc extends Bloc { required GridFieldCache fieldCache, required GridRowCache rowCache, }) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), - _rowlistener = RowListener(rowId: rowData.rowId), _fieldCache = fieldCache, _rowCache = rowCache, super(RowState.initial(rowData)) { @@ -76,27 +72,20 @@ class RowBloc extends Bloc { @override Future close() async { - await _rowlistener.stop(); return super.close(); } Future _startListening() async { - _rowlistener.updateRowNotifier?.addPublishListener( - (result) { - result.fold( - (row) => add(RowEvent.didUpdateRow(row)), - (err) => Log.error(err), - ); - }, - listenWhen: () => !isClosed, - ); - _fieldCache.addListener( listener: () => add(const RowEvent.fieldsDidUpdate()), listenWhen: () => !isClosed, ); - _rowlistener.start(); + _rowCache.addRowListener( + rowId: state.rowData.rowId, + onUpdated: (row) => add(RowEvent.didUpdateRow(row)), + listenWhen: () => !isClosed, + ); } Future _loadRow(Emitter emit) 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 c35466f5c3..bed21d1691 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,6 +1,5 @@ import 'dart:collection'; -import 'package:app_flowy/workspace/application/grid/grid_listener.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; @@ -10,6 +9,8 @@ import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:app_flowy/workspace/application/grid/grid_listener.dart'; + part 'row_service.freezed.dart'; class RowService { @@ -86,7 +87,6 @@ class GridRowCache { late GridRowListener _rowsListener; final RowsNotifier _rowNotifier = RowsNotifier(); final HashMap _rowDataMap = HashMap(); - UnmodifiableListView _fields = UnmodifiableListView([]); GridRowCache({required this.gridId}) { @@ -113,8 +113,11 @@ class GridRowCache { _rowNotifier.dispose(); } - void addListener({void Function(List, GridRowChangeReason)? onChanged, bool Function()? listenWhen}) { - _rowNotifier.addListener(() { + void addListener({ + void Function(List, GridRowChangeReason)? onChanged, + bool Function()? listenWhen, + }) { + listener() { if (listenWhen != null && listenWhen() == false) { return; } @@ -122,6 +125,32 @@ class GridRowCache { if (onChanged != null) { onChanged(clonedRows, _rowNotifier._changeReason); } + } + + _rowNotifier.addListener(listener); + } + + void addRowListener({ + required String rowId, + void Function(Row)? onUpdated, + bool Function()? listenWhen, + }) { + _rowNotifier.addListener(() { + if (onUpdated == null) { + return; + } + + if (listenWhen != null && listenWhen() == false) { + return; + } + + _rowNotifier._changeReason.whenOrNull(update: (indexs) { + final updatedIndex = indexs.firstWhereOrNull((updatedIndex) => updatedIndex.rowId == rowId); + final row = _rowDataMap[rowId]; + if (updatedIndex != null && row != null) { + onUpdated(row); + } + }); }); } @@ -166,14 +195,14 @@ class GridRowCache { } final List newRows = []; - final DeletedIndex deletedIndex = []; + final DeletedIndexs deletedIndex = []; final Map deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder}; - _rowNotifier.rows.asMap().forEach((index, value) { - if (deletedRowMap[value.rowId] == null) { - newRows.add(value); + _rowNotifier.rows.asMap().forEach((index, row) { + if (deletedRowMap[row.rowId] == null) { + newRows.add(row); } else { - deletedIndex.add(Tuple2(index, value)); + deletedIndex.add(DeletedIndex(index: index, row: row)); } }); @@ -189,7 +218,12 @@ class GridRowCache { final List newRows = _rowNotifier.rows; for (final createdRow in createdRows) { final gridRow = GridRow.fromBlockRow(gridId, createdRow.rowOrder, _fields); - insertIndexs.add(Tuple2(createdRow.index, gridRow.rowId)); + insertIndexs.add( + InsertedIndex( + index: createdRow.index, + rowId: gridRow.rowId, + ), + ); newRows.insert(createdRow.index, gridRow); } _rowNotifier.updateRows(newRows, GridRowChangeReason.insert(insertIndexs)); @@ -200,14 +234,15 @@ class GridRowCache { return; } - final List updatedIndexs = []; + final UpdatedIndexs updatedIndexs = []; final List newRows = _rowNotifier.rows; for (final rowOrder in updatedRows) { final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId); if (index != -1) { newRows.removeAt(index); newRows.insert(index, GridRow.fromBlockRow(gridId, rowOrder, _fields)); - updatedIndexs.add(index); + _rowDataMap.remove(rowOrder.rowId); + updatedIndexs.add(UpdatedIndex(index: index, rowId: rowOrder.rowId)); } } @@ -246,13 +281,41 @@ class GridRow with _$GridRow { } } -typedef InsertedIndexs = List>; -typedef DeletedIndex = List>; +typedef InsertedIndexs = List; +typedef DeletedIndexs = List; +typedef UpdatedIndexs = List; + +class InsertedIndex { + int index; + String rowId; + InsertedIndex({ + required this.index, + required this.rowId, + }); +} + +class DeletedIndex { + int index; + GridRow row; + DeletedIndex({ + required this.index, + required this.row, + }); +} + +class UpdatedIndex { + int index; + String rowId; + UpdatedIndex({ + required this.index, + required this.rowId, + }); +} @freezed class GridRowChangeReason with _$GridRowChangeReason { const factory GridRowChangeReason.insert(InsertedIndexs items) = _Insert; - const factory GridRowChangeReason.delete(DeletedIndex items) = _Delete; - const factory GridRowChangeReason.update(List indexs) = _Update; + const factory GridRowChangeReason.delete(DeletedIndexs items) = _Delete; + const factory GridRowChangeReason.update(UpdatedIndexs indexs) = _Update; const factory GridRowChangeReason.initial() = InitialListState; } 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 1a5f64c03a..c4b937300e 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 @@ -191,22 +191,20 @@ class _GridRowsState extends State<_GridRows> { return BlocConsumer( listenWhen: (previous, current) => previous.listState != current.listState, listener: (context, state) { - state.listState.map( + state.listState.mapOrNull( insert: (value) { for (final item in value.items) { - _key.currentState?.insertItem(item.value1); + _key.currentState?.insertItem(item.index); } }, delete: (value) { for (final item in value.items) { _key.currentState?.removeItem( - item.value1, - (context, animation) => _renderRow(context, item.value2, animation), + item.index, + (context, animation) => _renderRow(context, item.row, animation), ); } }, - initial: (_) {}, - update: (_) {}, ); }, buildWhen: (previous, current) => false, diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart index 7b43def65e..7a89d33361 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbenum.dart @@ -12,19 +12,19 @@ import 'package:protobuf/protobuf.dart' as $pb; class GridNotification extends $pb.ProtobufEnum { static const GridNotification Unknown = GridNotification._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown'); static const GridNotification DidCreateBlock = GridNotification._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidCreateBlock'); - static const GridNotification DidUpdateGridBlock = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridBlock'); + static const GridNotification DidUpdateGridRow = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridRow'); + static const GridNotification DidUpdateGridField = GridNotification._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridField'); static const GridNotification DidUpdateRow = GridNotification._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateRow'); - static const GridNotification DidUpdateCell = GridNotification._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateCell'); - static const GridNotification DidUpdateGridField = GridNotification._(40, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateGridField'); - static const GridNotification DidUpdateField = GridNotification._(41, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateField'); + static const GridNotification DidUpdateCell = GridNotification._(40, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateCell'); + static const GridNotification DidUpdateField = GridNotification._(50, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateField'); static const $core.List values = [ Unknown, DidCreateBlock, - DidUpdateGridBlock, + DidUpdateGridRow, + DidUpdateGridField, DidUpdateRow, DidUpdateCell, - DidUpdateGridField, DidUpdateField, ]; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart index 8c262092db..96a087ca40 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/dart_notification.pbjson.dart @@ -14,13 +14,13 @@ const GridNotification$json = const { '2': const [ const {'1': 'Unknown', '2': 0}, const {'1': 'DidCreateBlock', '2': 11}, - const {'1': 'DidUpdateGridBlock', '2': 20}, + const {'1': 'DidUpdateGridRow', '2': 20}, + const {'1': 'DidUpdateGridField', '2': 21}, const {'1': 'DidUpdateRow', '2': 30}, - const {'1': 'DidUpdateCell', '2': 31}, - const {'1': 'DidUpdateGridField', '2': 40}, - const {'1': 'DidUpdateField', '2': 41}, + const {'1': 'DidUpdateCell', '2': 40}, + const {'1': 'DidUpdateField', '2': 50}, ], }; /// Descriptor for `GridNotification`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhYKEkRpZFVwZGF0ZUdyaWRCbG9jaxAUEhAKDERpZFVwZGF0ZVJvdxAeEhEKDURpZFVwZGF0ZUNlbGwQHxIWChJEaWRVcGRhdGVHcmlkRmllbGQQKBISCg5EaWRVcGRhdGVGaWVsZBAp'); +final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhQKEERpZFVwZGF0ZUdyaWRSb3cQFBIWChJEaWRVcGRhdGVHcmlkRmllbGQQFRIQCgxEaWRVcGRhdGVSb3cQHhIRCg1EaWRVcGRhdGVDZWxsECgSEgoORGlkVXBkYXRlRmllbGQQMg=='); diff --git a/frontend/rust-lib/flowy-grid/src/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/dart_notification.rs index 156ba9058a..92749da519 100644 --- a/frontend/rust-lib/flowy-grid/src/dart_notification.rs +++ b/frontend/rust-lib/flowy-grid/src/dart_notification.rs @@ -6,11 +6,11 @@ const OBSERVABLE_CATEGORY: &str = "Grid"; pub enum GridNotification { Unknown = 0, DidCreateBlock = 11, - DidUpdateGridBlock = 20, + DidUpdateGridRow = 20, + DidUpdateGridField = 21, DidUpdateRow = 30, - DidUpdateCell = 31, - DidUpdateGridField = 40, - DidUpdateField = 41, + DidUpdateCell = 40, + DidUpdateField = 50, } impl std::default::Default for GridNotification { diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs index 338737c643..ff60cbf9e7 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/dart_notification.rs @@ -27,11 +27,11 @@ pub enum GridNotification { Unknown = 0, DidCreateBlock = 11, - DidUpdateGridBlock = 20, + DidUpdateGridRow = 20, + DidUpdateGridField = 21, DidUpdateRow = 30, - DidUpdateCell = 31, - DidUpdateGridField = 40, - DidUpdateField = 41, + DidUpdateCell = 40, + DidUpdateField = 50, } impl ::protobuf::ProtobufEnum for GridNotification { @@ -43,11 +43,11 @@ impl ::protobuf::ProtobufEnum for GridNotification { match value { 0 => ::std::option::Option::Some(GridNotification::Unknown), 11 => ::std::option::Option::Some(GridNotification::DidCreateBlock), - 20 => ::std::option::Option::Some(GridNotification::DidUpdateGridBlock), + 20 => ::std::option::Option::Some(GridNotification::DidUpdateGridRow), + 21 => ::std::option::Option::Some(GridNotification::DidUpdateGridField), 30 => ::std::option::Option::Some(GridNotification::DidUpdateRow), - 31 => ::std::option::Option::Some(GridNotification::DidUpdateCell), - 40 => ::std::option::Option::Some(GridNotification::DidUpdateGridField), - 41 => ::std::option::Option::Some(GridNotification::DidUpdateField), + 40 => ::std::option::Option::Some(GridNotification::DidUpdateCell), + 50 => ::std::option::Option::Some(GridNotification::DidUpdateField), _ => ::std::option::Option::None } } @@ -56,10 +56,10 @@ impl ::protobuf::ProtobufEnum for GridNotification { static values: &'static [GridNotification] = &[ GridNotification::Unknown, GridNotification::DidCreateBlock, - GridNotification::DidUpdateGridBlock, + GridNotification::DidUpdateGridRow, + GridNotification::DidUpdateGridField, GridNotification::DidUpdateRow, GridNotification::DidUpdateCell, - GridNotification::DidUpdateGridField, GridNotification::DidUpdateField, ]; values @@ -89,11 +89,11 @@ impl ::protobuf::reflect::ProtobufValue for GridNotification { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x17dart_notification.proto*\x9c\x01\n\x10GridNotification\x12\x0b\n\ - \x07Unknown\x10\0\x12\x12\n\x0eDidCreateBlock\x10\x0b\x12\x16\n\x12DidUp\ - dateGridBlock\x10\x14\x12\x10\n\x0cDidUpdateRow\x10\x1e\x12\x11\n\rDidUp\ - dateCell\x10\x1f\x12\x16\n\x12DidUpdateGridField\x10(\x12\x12\n\x0eDidUp\ - dateField\x10)b\x06proto3\ + \n\x17dart_notification.proto*\x9a\x01\n\x10GridNotification\x12\x0b\n\ + \x07Unknown\x10\0\x12\x12\n\x0eDidCreateBlock\x10\x0b\x12\x14\n\x10DidUp\ + dateGridRow\x10\x14\x12\x16\n\x12DidUpdateGridField\x10\x15\x12\x10\n\ + \x0cDidUpdateRow\x10\x1e\x12\x11\n\rDidUpdateCell\x10(\x12\x12\n\x0eDidU\ + pdateField\x102b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto index a4e5188346..9a2899833f 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/dart_notification.proto @@ -3,9 +3,9 @@ syntax = "proto3"; enum GridNotification { Unknown = 0; DidCreateBlock = 11; - DidUpdateGridBlock = 20; + DidUpdateGridRow = 20; + DidUpdateGridField = 21; DidUpdateRow = 30; - DidUpdateCell = 31; - DidUpdateGridField = 40; - DidUpdateField = 41; + DidUpdateCell = 40; + DidUpdateField = 50; } 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 2a8eae4497..58c623adc6 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 @@ -2,13 +2,13 @@ use crate::dart_notification::{send_dart_notification, GridNotification}; 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, make_rows_from_row_metas, GridBlockSnapshot}; +use crate::services::row::{group_row_orders, GridBlockSnapshot}; use std::borrow::Cow; use dashmap::DashMap; use flowy_error::FlowyResult; use flowy_grid_data_model::entities::{ - CellChangeset, CellMeta, CellNotificationData, FieldMeta, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, + CellChangeset, CellMeta, CellNotificationData, GridBlockMeta, GridBlockMetaChangeset, GridRowsChangeset, IndexRowOrder, RowMeta, RowMetaChangeset, RowOrder, }; use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence; @@ -76,7 +76,7 @@ impl GridBlockMetaEditorManager { index_row_order.index = row_index; let _ = self - .notify_did_update_rows(GridRowsChangeset::insert(block_id, vec![index_row_order])) + .notify_did_update_block(GridRowsChangeset::insert(block_id, vec![index_row_order])) .await?; Ok(row_count) } @@ -98,7 +98,7 @@ impl GridBlockMetaEditorManager { changesets.push(GridBlockMetaChangeset::from_row_count(&block_id, row_count)); let _ = self - .notify_did_update_rows(GridRowsChangeset::insert(&block_id, inserted_row_orders)) + .notify_did_update_block(GridRowsChangeset::insert(&block_id, inserted_row_orders)) .await?; } @@ -108,19 +108,7 @@ impl GridBlockMetaEditorManager { pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { let editor = self.get_editor_from_row_id(&changeset.row_id).await?; let _ = editor.update_row(changeset.clone()).await?; - - match editor - .get_row_orders(Some(vec![Cow::Borrowed(&changeset.row_id)])) - .await? - .pop() - { - None => {} - Some(row_order) => { - let block_order_changeset = GridRowsChangeset::update(&editor.block_id, vec![row_order]); - let _ = self.notify_did_update_rows(block_order_changeset).await?; - } - } - + let _ = self.notify_did_update_block_row(&changeset.row_id).await?; Ok(()) } @@ -131,7 +119,7 @@ impl GridBlockMetaEditorManager { 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_rows(GridRowsChangeset::delete(&block_id, row_orders)) + .notify_did_update_block(GridRowsChangeset::delete(&block_id, row_orders)) .await?; Ok(()) @@ -173,7 +161,7 @@ impl GridBlockMetaEditorManager { updated_rows: vec![], }; - let _ = self.notify_did_update_rows(notified_changeset).await?; + let _ = self.notify_did_update_block(notified_changeset).await?; } } @@ -181,10 +169,8 @@ impl GridBlockMetaEditorManager { } pub async fn update_cell(&self, changeset: CellChangeset) -> FlowyResult<()> { - let row_id = changeset.row_id.clone(); - let editor = self.get_editor_from_row_id(&row_id).await?; let row_changeset: RowMetaChangeset = changeset.clone().into(); - let _ = editor.update_row(row_changeset).await?; + let _ = self.update_row(row_changeset).await?; let cell_notification_data = CellNotificationData { grid_id: changeset.grid_id, @@ -193,6 +179,7 @@ impl GridBlockMetaEditorManager { content: changeset.data, }; self.notify_did_update_cell(cell_notification_data).await?; + Ok(()) } @@ -239,8 +226,22 @@ impl GridBlockMetaEditorManager { Ok(block_cell_metas) } - async fn notify_did_update_rows(&self, changeset: GridRowsChangeset) -> FlowyResult<()> { - send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridBlock) + 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() { + 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) .send(); Ok(()) @@ -253,22 +254,6 @@ impl GridBlockMetaEditorManager { .send(); Ok(()) } - - #[allow(dead_code)] - async fn notify_did_update_row(&self, row_id: &str, field_metas: &[FieldMeta]) -> FlowyResult<()> { - match self.get_row_meta(row_id).await? { - None => {} - Some(row_meta) => { - let row_metas = vec![row_meta]; - if let Some(row) = make_rows_from_row_metas(field_metas, &row_metas).pop() { - send_dart_notification(row_id, GridNotification::DidUpdateRow) - .payload(row) - .send(); - } - } - } - Ok(()) - } } async fn make_block_meta_editor_map( 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 b34e0fea65..2dd6e57ea5 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -77,7 +77,7 @@ impl ClientGridEditor { Ok(grid.update_field_meta(changeset, deserializer)?) }) .await?; - let _ = self.notify_grid_did_update_field(&field_id).await?; + let _ = self.notify_did_update_grid_field(&field_id).await?; } else { let _ = self .modify(|grid| { @@ -87,7 +87,7 @@ impl ClientGridEditor { Ok(grid.create_field_meta(field_meta, start_field_id)?) }) .await?; - let _ = self.notify_grid_did_insert_field(&field_id).await?; + let _ = self.notify_did_insert_grid_field(&field_id).await?; } Ok(()) @@ -114,14 +114,14 @@ impl ClientGridEditor { .modify(|grid| Ok(grid.update_field_meta(params, json_deserializer)?)) .await?; - let _ = self.notify_grid_did_update_field(&field_id).await?; + let _ = self.notify_did_update_grid_field(&field_id).await?; Ok(()) } pub async fn replace_field(&self, field_meta: FieldMeta) -> FlowyResult<()> { let field_id = field_meta.id.clone(); let _ = self.modify(|pad| Ok(pad.replace_field_meta(field_meta)?)).await?; - let _ = self.notify_grid_did_update_field(&field_id).await?; + let _ = self.notify_did_update_grid_field(&field_id).await?; Ok(()) } @@ -153,7 +153,7 @@ impl ClientGridEditor { .modify(|grid| Ok(grid.switch_to_field(field_id, field_type.clone(), type_option_json_builder)?)) .await?; - let _ = self.notify_grid_did_update_field(field_id).await?; + let _ = self.notify_did_update_grid_field(field_id).await?; Ok(()) } @@ -164,7 +164,7 @@ impl ClientGridEditor { .modify(|grid| Ok(grid.duplicate_field_meta(field_id, &duplicated_field_id)?)) .await?; - let _ = self.notify_grid_did_insert_field(field_id).await?; + let _ = self.notify_did_insert_grid_field(field_id).await?; Ok(()) } @@ -462,7 +462,7 @@ impl ClientGridEditor { } #[tracing::instrument(level = "trace", skip_all, err)] - async fn notify_grid_did_insert_field(&self, field_id: &str) -> FlowyResult<()> { + async fn notify_did_insert_grid_field(&self, field_id: &str) -> FlowyResult<()> { if let Some((index, field_meta)) = self.pad.read().await.get_field_meta(field_id) { let index_field = IndexField::from_field_meta(field_meta, index); let notified_changeset = GridFieldChangeset::insert(&self.grid_id, vec![index_field]); @@ -472,7 +472,7 @@ impl ClientGridEditor { } #[tracing::instrument(level = "trace", skip_all, err)] - async fn notify_grid_did_update_field(&self, field_id: &str) -> FlowyResult<()> { + async fn notify_did_update_grid_field(&self, field_id: &str) -> FlowyResult<()> { let mut field_metas = self.get_field_metas(Some(vec![field_id])).await?; debug_assert!(field_metas.len() == 1); diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index f40b93233e..d91265e896 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -208,7 +208,7 @@ impl GridMetaPad { pub fn move_field( &mut self, field_id: &str, - from_index: usize, + _from_index: usize, to_index: usize, ) -> CollaborateResult> { self.modify_grid( From 917e15a1b759c645f30052dd1ff2596ae24d5487 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Apr 2022 14:50:29 +0800 Subject: [PATCH 23/26] chore: remove listener --- .../application/grid/grid_service.dart | 14 +- .../application/grid/row/row_bloc.dart | 15 +- .../application/grid/row/row_service.dart | 139 +++++++++--------- 3 files changed, 93 insertions(+), 75 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 0d24e9974c..080d6e79fc 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -85,8 +85,9 @@ class GridFieldCache { _fieldNotifier.fields = [...fields]; } - void addListener({VoidCallback? listener, void Function(List)? onChanged, bool Function()? listenWhen}) { - _fieldNotifier.addListener(() { + VoidCallback addListener( + {VoidCallback? listener, void Function(List)? onChanged, bool Function()? listenWhen}) { + f() { if (listenWhen != null && listenWhen() == false) { return; } @@ -98,7 +99,14 @@ class GridFieldCache { if (listener != null) { listener(); } - }); + } + + _fieldNotifier.addListener(f); + return f; + } + + void removeListener(VoidCallback f) { + _fieldNotifier.removeListener(f); } void _deleteFields(List deletedFields) { 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 1f026a0af6..7d853ce97e 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,4 +1,5 @@ import 'dart:collection'; + import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -13,9 +14,10 @@ typedef CellDataMap = LinkedHashMap; class RowBloc extends Bloc { final RowService _rowService; - final GridFieldCache _fieldCache; final GridRowCache _rowCache; + void Function()? _rowListenCallback; + void Function()? _fieldListenCallback; RowBloc({ required GridRow rowData, @@ -72,16 +74,23 @@ class RowBloc extends Bloc { @override Future close() async { + if (_rowListenCallback != null) { + _rowCache.removeRowListener(_rowListenCallback!); + } + + if (_fieldListenCallback != null) { + _fieldCache.removeListener(_fieldListenCallback!); + } return super.close(); } Future _startListening() async { - _fieldCache.addListener( + _fieldListenCallback = _fieldCache.addListener( listener: () => add(const RowEvent.fieldsDidUpdate()), listenWhen: () => !isClosed, ); - _rowCache.addRowListener( + _rowListenCallback = _rowCache.addRowListener( rowId: state.rowData.rowId, onUpdated: (row) => add(RowEvent.didUpdateRow(row)), listenWhen: () => !isClosed, 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 bed21d1691..9cb1ac81a9 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart @@ -1,5 +1,4 @@ import 'dart:collection'; - import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; @@ -8,61 +7,10 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; - import 'package:app_flowy/workspace/application/grid/grid_listener.dart'; part 'row_service.freezed.dart'; -class RowService { - final String gridId; - final String rowId; - - RowService({required this.gridId, required this.rowId}); - - Future> createRow() { - CreateRowPayload payload = CreateRowPayload.create() - ..gridId = gridId - ..startRowId = rowId; - - return GridEventCreateRow(payload).send(); - } - - Future> moveRow(String rowId, int fromIndex, int toIndex) { - final payload = MoveItemPayload.create() - ..gridId = gridId - ..itemId = rowId - ..ty = MoveItemType.MoveRow - ..fromIndex = fromIndex - ..toIndex = toIndex; - - return GridEventMoveItem(payload).send(); - } - - Future> getRow() { - final payload = RowIdentifierPayload.create() - ..gridId = gridId - ..rowId = rowId; - - return GridEventGetRow(payload).send(); - } - - Future> deleteRow() { - final payload = RowIdentifierPayload.create() - ..gridId = gridId - ..rowId = rowId; - - return GridEventDeleteRow(payload).send(); - } - - Future> duplicateRow() { - final payload = RowIdentifierPayload.create() - ..gridId = gridId - ..rowId = rowId; - - return GridEventDuplicateRow(payload).send(); - } -} - class RowsNotifier extends ChangeNotifier { List _rows = []; GridRowChangeReason _changeReason = const InitialListState(); @@ -84,13 +32,12 @@ class RowsNotifier extends ChangeNotifier { class GridRowCache { final String gridId; - late GridRowListener _rowsListener; + final GridRowListener _rowsListener; final RowsNotifier _rowNotifier = RowsNotifier(); final HashMap _rowDataMap = HashMap(); UnmodifiableListView _fields = UnmodifiableListView([]); - GridRowCache({required this.gridId}) { - _rowsListener = GridRowListener(gridId: gridId); + GridRowCache({required this.gridId}) : _rowsListener = GridRowListener(gridId: gridId) { _rowsListener.rowsUpdateNotifier.addPublishListener((result) { result.fold( (changesets) { @@ -106,18 +53,18 @@ class GridRowCache { _rowsListener.start(); } - List get clonedRows => [..._rowNotifier.rows]; - Future dispose() async { await _rowsListener.stop(); _rowNotifier.dispose(); } + List get clonedRows => [..._rowNotifier.rows]; + void addListener({ void Function(List, GridRowChangeReason)? onChanged, bool Function()? listenWhen, }) { - listener() { + _rowNotifier.addListener(() { if (listenWhen != null && listenWhen() == false) { return; } @@ -125,17 +72,15 @@ class GridRowCache { if (onChanged != null) { onChanged(clonedRows, _rowNotifier._changeReason); } - } - - _rowNotifier.addListener(listener); + }); } - void addRowListener({ + VoidCallback addRowListener({ required String rowId, void Function(Row)? onUpdated, bool Function()? listenWhen, }) { - _rowNotifier.addListener(() { + f() { if (onUpdated == null) { return; } @@ -145,13 +90,19 @@ class GridRowCache { } _rowNotifier._changeReason.whenOrNull(update: (indexs) { - final updatedIndex = indexs.firstWhereOrNull((updatedIndex) => updatedIndex.rowId == rowId); final row = _rowDataMap[rowId]; - if (updatedIndex != null && row != null) { + if (indexs[rowId] != null && row != null) { onUpdated(row); } }); - }); + } + + _rowNotifier.addListener(f); + return f; + } + + void removeRowListener(VoidCallback callback) { + _rowNotifier.removeListener(callback); } Future> getRowData(String rowId) async { @@ -234,7 +185,7 @@ class GridRowCache { return; } - final UpdatedIndexs updatedIndexs = []; + final UpdatedIndexs updatedIndexs = UpdatedIndexs(); final List newRows = _rowNotifier.rows; for (final rowOrder in updatedRows) { final index = newRows.indexWhere((row) => row.rowId == rowOrder.rowId); @@ -242,7 +193,7 @@ class GridRowCache { newRows.removeAt(index); newRows.insert(index, GridRow.fromBlockRow(gridId, rowOrder, _fields)); _rowDataMap.remove(rowOrder.rowId); - updatedIndexs.add(UpdatedIndex(index: index, rowId: rowOrder.rowId)); + updatedIndexs[rowOrder.rowId] = UpdatedIndex(index: index, rowId: rowOrder.rowId); } } @@ -250,6 +201,56 @@ class GridRowCache { } } +class RowService { + final String gridId; + final String rowId; + + RowService({required this.gridId, required this.rowId}); + + Future> createRow() { + CreateRowPayload payload = CreateRowPayload.create() + ..gridId = gridId + ..startRowId = rowId; + + return GridEventCreateRow(payload).send(); + } + + Future> moveRow(String rowId, int fromIndex, int toIndex) { + final payload = MoveItemPayload.create() + ..gridId = gridId + ..itemId = rowId + ..ty = MoveItemType.MoveRow + ..fromIndex = fromIndex + ..toIndex = toIndex; + + return GridEventMoveItem(payload).send(); + } + + Future> getRow() { + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + return GridEventGetRow(payload).send(); + } + + Future> deleteRow() { + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + return GridEventDeleteRow(payload).send(); + } + + Future> duplicateRow() { + final payload = RowIdentifierPayload.create() + ..gridId = gridId + ..rowId = rowId; + + return GridEventDuplicateRow(payload).send(); + } +} + @freezed class GridCellIdentifier with _$GridCellIdentifier { const factory GridCellIdentifier({ @@ -283,7 +284,7 @@ class GridRow with _$GridRow { typedef InsertedIndexs = List; typedef DeletedIndexs = List; -typedef UpdatedIndexs = List; +typedef UpdatedIndexs = LinkedHashMap; class InsertedIndex { int index; From 13e8c629881b96caccc47bc3a43d661611b04164 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Apr 2022 15:15:34 +0800 Subject: [PATCH 24/26] fix: grid property list bugs --- .../app_flowy/lib/startup/deps_resolver.dart | 5 ++- .../grid/setting/property_bloc.dart | 15 +++++---- .../plugins/grid/src/grid_page.dart | 3 +- .../src/widgets/toolbar/grid_property.dart | 33 +++++++++++-------- .../src/widgets/toolbar/grid_setting.dart | 7 ++-- .../src/widgets/toolbar/grid_toolbar.dart | 7 ++-- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 7e26566367..1a51652458 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -17,7 +17,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'; 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'; @@ -223,7 +222,7 @@ void _resolveGridDeps(GetIt getIt) { (typeOption, _) => NumberTypeOptionBloc(typeOption: typeOption), ); - getIt.registerFactoryParam>( - (gridId, fields) => GridPropertyBloc(gridId: gridId, fields: fields), + getIt.registerFactoryParam( + (gridId, cache) => GridPropertyBloc(gridId: gridId, fieldCache: cache), ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index bf87851ebb..c69b8062bf 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -11,11 +11,12 @@ part 'property_bloc.freezed.dart'; class GridPropertyBloc extends Bloc { final FieldService _service; final GridFieldCache _fieldCache; + Function()? _listenFieldCallback; - GridPropertyBloc({required String gridId, required List fields}) + GridPropertyBloc({required String gridId, required GridFieldCache fieldCache}) : _service = FieldService(gridId: gridId), - _fieldCache = GridFieldCache(gridId: gridId), - super(GridPropertyState.initial(gridId, fields)) { + _fieldCache = fieldCache, + super(GridPropertyState.initial(gridId, fieldCache.clonedFields)) { on( (event, emit) async { await event.map( @@ -42,13 +43,15 @@ class GridPropertyBloc extends Bloc { @override Future close() async { - await _fieldCache.dispose(); + if (_listenFieldCallback != null) { + _fieldCache.removeListener(_listenFieldCallback!); + } return super.close(); } void _startListening() { - _fieldCache.addListener( - onChanged: (fields) => add(GridPropertyEvent.didReceiveFieldUpdate(_fieldCache.clonedFields)), + _listenFieldCallback = _fieldCache.addListener( + onChanged: (fields) => add(GridPropertyEvent.didReceiveFieldUpdate(fields)), listenWhen: () => !isClosed, ); } 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 c4b937300e..a8d564c6c0 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 @@ -164,9 +164,10 @@ class _GridToolbarAdaptor extends StatelessWidget { Widget build(BuildContext context) { return BlocSelector( selector: (state) { + final fieldCache = context.read().fieldCache; return GridToolbarContext( gridId: state.gridId, - fields: state.fields, + fieldCache: fieldCache, ); }, builder: (context, toolbarContext) { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index 75898d5ba7..bc108f78d7 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:app_flowy/workspace/application/grid/setting/property_bloc.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart'; @@ -18,10 +19,10 @@ import 'package:styled_widget/styled_widget.dart'; class GridPropertyList extends StatelessWidget with FlowyOverlayDelegate { final String gridId; - final List fields; + final GridFieldCache fieldCache; const GridPropertyList({ required this.gridId, - required this.fields, + required this.fieldCache, Key? key, }) : super(key: key); @@ -43,7 +44,7 @@ class GridPropertyList extends StatelessWidget with FlowyOverlayDelegate { Widget build(BuildContext context) { return BlocProvider( create: (context) => - getIt(param1: gridId, param2: fields)..add(const GridPropertyEvent.initial()), + getIt(param1: gridId, param2: fieldCache)..add(const GridPropertyEvent.initial()), child: BlocBuilder( builder: (context, state) { final cells = state.fields.map((field) { @@ -91,17 +92,7 @@ class _GridPropertyCell extends StatelessWidget { Expanded( child: SizedBox( height: GridSize.typeOptionItemHeight, - child: FlowyButton( - text: FlowyText.medium(field.name, fontSize: 12), - hoverColor: theme.hover, - leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), - onTap: () { - FieldEditor( - gridId: gridId, - fieldContextLoader: FieldContextLoaderAdaptor(gridId: gridId, field: field), - ).show(context, anchorDirection: AnchorDirection.bottomRight); - }, - ), + child: _editFieldButton(theme, context), ), ), FlowyIconButton( @@ -115,4 +106,18 @@ class _GridPropertyCell extends StatelessWidget { ], ); } + + FlowyButton _editFieldButton(AppTheme theme, BuildContext context) { + return FlowyButton( + text: FlowyText.medium(field.name, fontSize: 12), + hoverColor: theme.hover, + leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), + onTap: () { + FieldEditor( + gridId: gridId, + fieldContextLoader: FieldContextLoaderAdaptor(gridId: gridId, field: field), + ).show(context, anchorDirection: AnchorDirection.bottomRight); + }, + ); + } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart index a67ddd290f..f6f00add9d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart @@ -1,3 +1,4 @@ +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:app_flowy/workspace/application/grid/setting/setting_bloc.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/image.dart'; @@ -18,11 +19,11 @@ import 'grid_property.dart'; class GridSettingContext { final String gridId; - final List fields; + final GridFieldCache fieldCache; GridSettingContext({ required this.gridId, - required this.fields, + required this.fieldCache, }); } @@ -41,7 +42,7 @@ class GridSettingList extends StatelessWidget { case GridSettingAction.sortBy: break; case GridSettingAction.properties: - GridPropertyList(gridId: settingContext.gridId, fields: settingContext.fields).show(context); + GridPropertyList(gridId: settingContext.gridId, fieldCache: settingContext.fieldCache).show(context); break; } }, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart index 9569f95225..4400260941 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart @@ -1,3 +1,4 @@ +import 'package:app_flowy/workspace/application/grid/grid_service.dart'; import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/extension.dart'; @@ -12,10 +13,10 @@ import 'grid_setting.dart'; class GridToolbarContext { final String gridId; - final List fields; + final GridFieldCache fieldCache; GridToolbarContext({ required this.gridId, - required this.fields, + required this.fieldCache, }); } @@ -27,7 +28,7 @@ class GridToolbar extends StatelessWidget { Widget build(BuildContext context) { final settingContext = GridSettingContext( gridId: toolbarContext.gridId, - fields: toolbarContext.fields, + fieldCache: toolbarContext.fieldCache, ); return SizedBox( height: 40, From 0acc0b0e8165495133c832a25b571c12ca7dd3f8 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Apr 2022 15:39:33 +0800 Subject: [PATCH 25/26] fix: duplicate field --- frontend/rust-lib/flowy-grid/src/services/grid_editor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2dd6e57ea5..d2312708b1 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -164,7 +164,7 @@ impl ClientGridEditor { .modify(|grid| Ok(grid.duplicate_field_meta(field_id, &duplicated_field_id)?)) .await?; - let _ = self.notify_did_insert_grid_field(field_id).await?; + let _ = self.notify_did_insert_grid_field(&duplicated_field_id).await?; Ok(()) } From 006b3c38112e9774edb3bd1f69612a788c5b5707 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 17 Apr 2022 20:50:16 +0800 Subject: [PATCH 26/26] chore: fix unit test & warnings --- .github/workflows/rust_test.yml | 2 +- .../plugins/grid/src/widgets/toolbar/grid_setting.dart | 1 - .../plugins/grid/src/widgets/toolbar/grid_toolbar.dart | 1 - frontend/rust-lib/flowy-text-block/src/editor.rs | 9 +++++---- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rust_test.yml b/.github/workflows/rust_test.yml index 998f6378e1..30b1f15576 100644 --- a/.github/workflows/rust_test.yml +++ b/.github/workflows/rust_test.yml @@ -44,7 +44,7 @@ jobs: - name: Run rust-lib tests working-directory: frontend/rust-lib - run: RUST_LOG=info cargo test --no-default-features + run: RUST_LOG=info cargo test --no-default-features --features="sync" - name: Run shared-lib tests working-directory: shared-lib diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart index f6f00add9d..05a72a5504 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart @@ -8,7 +8,6 @@ import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart index 4400260941..8d25189163 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart @@ -3,7 +3,6 @@ import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/extension.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/rust-lib/flowy-text-block/src/editor.rs b/frontend/rust-lib/flowy-text-block/src/editor.rs index 55160010bf..d43fc24f1c 100644 --- a/frontend/rust-lib/flowy-text-block/src/editor.rs +++ b/frontend/rust-lib/flowy-text-block/src/editor.rs @@ -26,27 +26,28 @@ pub struct ClientTextBlockEditor { #[allow(dead_code)] rev_manager: Arc, #[cfg(feature = "sync")] - ws_manager: Arc, + ws_manager: Arc, edit_cmd_tx: EditorCommandSender, } impl ClientTextBlockEditor { + #[allow(unused_variables)] pub(crate) async fn new( doc_id: &str, user: Arc, mut rev_manager: RevisionManager, - _rev_web_socket: Arc, + rev_web_socket: Arc, cloud_service: Arc, ) -> FlowyResult> { let document_info = rev_manager.load::(Some(cloud_service)).await?; let delta = document_info.delta()?; let rev_manager = Arc::new(rev_manager); let doc_id = doc_id.to_string(); - let _user_id = user.user_id()?; + let user_id = user.user_id()?; let edit_cmd_tx = spawn_edit_queue(user, rev_manager.clone(), delta); #[cfg(feature = "sync")] - let ws_manager = make_block_ws_manager( + let ws_manager = crate::web_socket::make_block_ws_manager( doc_id.clone(), user_id.clone(), edit_cmd_tx.clone(),