From 1f30a77f1d43681840f342887721b61973508193 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sun, 20 Mar 2022 17:17:06 +0800 Subject: [PATCH] feat: save text cell data --- frontend/app_flowy/lib/plugin/plugin.dart | 6 - .../lib/workspace/application/appearance.dart | 14 +- .../grid/cell_bloc/text_cell_bloc.dart | 1 + .../workspace/application/grid/grid_bloc.dart | 56 +++---- .../application/grid/grid_block_service.dart | 56 ++++--- .../application/grid/grid_service.dart | 4 +- .../workspace/application/grid/row_bloc.dart | 34 ++--- .../home/menu/app/section/section.dart | 8 +- .../presentation/plugins/blank/blank.dart | 2 +- .../presentation/plugins/doc/document.dart | 84 +---------- .../presentation/plugins/grid/grid.dart | 6 +- .../plugins/grid/src/grid_page.dart | 72 ++++----- .../grid/src/widgets/content/grid_row.dart | 139 +++++++++--------- .../grid/src/widgets/content/text_cell.dart | 39 +++-- .../grid/src/widgets/header/header.dart | 18 ++- .../plugins/widgets/left_bar_item.dart | 74 ++++++++++ .../packages/flowy_infra/lib/notifier.dart | 21 ++- .../flowy-grid-data-model/grid.pb.dart | 16 +- .../flowy-grid-data-model/grid.pbjson.dart | 4 +- .../flowy-grid/dart_notification.pbenum.dart | 8 +- .../flowy-grid/dart_notification.pbjson.dart | 8 +- .../flowy-grid/src/dart_notification.rs | 8 +- frontend/rust-lib/flowy-grid/src/manager.rs | 2 +- .../src/protobuf/model/dart_notification.rs | 22 +-- .../protobuf/proto/dart_notification.proto | 6 +- .../src/services/block_meta_editor.rs | 35 +++-- .../flowy-grid/src/services/row/row_loader.rs | 6 +- .../flowy-revision/src/rev_manager.rs | 2 + .../src/entities/grid.rs | 10 +- .../src/protobuf/model/grid.rs | 78 +++++----- .../src/protobuf/proto/grid.proto | 2 +- .../src/client_grid/grid_block_meta_pad.rs | 37 ++--- 32 files changed, 473 insertions(+), 405 deletions(-) create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart diff --git a/frontend/app_flowy/lib/plugin/plugin.dart b/frontend/app_flowy/lib/plugin/plugin.dart index 607ebaab53..8d30b122ad 100644 --- a/frontend/app_flowy/lib/plugin/plugin.dart +++ b/frontend/app_flowy/lib/plugin/plugin.dart @@ -61,12 +61,6 @@ abstract class PluginConfig { } abstract class PluginDisplay with NavigationItem { - @override - Widget get leftBarItem; - - @override - Widget? get rightBarItem; - List get navigationItems; PublishNotifier? get notifier => null; diff --git a/frontend/app_flowy/lib/workspace/application/appearance.dart b/frontend/app_flowy/lib/workspace/application/appearance.dart index 87cd7e1af8..ffd7e18c92 100644 --- a/frontend/app_flowy/lib/workspace/application/appearance.dart +++ b/frontend/app_flowy/lib/workspace/application/appearance.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:app_flowy/user/application/user_settings_service.dart'; import 'package:equatable/equatable.dart'; import 'package:flowy_infra/theme.dart'; @@ -11,7 +13,7 @@ class AppearanceSettingModel extends ChangeNotifier with EquatableMixin { AppearanceSettings setting; AppTheme _theme; Locale _locale; - CancelableOperation? _saveOperation; + Timer? _saveOperation; AppearanceSettingModel(this.setting) : _theme = AppTheme.fromName(name: setting.theme), @@ -21,12 +23,10 @@ class AppearanceSettingModel extends ChangeNotifier with EquatableMixin { Locale get locale => _locale; Future save() async { - _saveOperation?.cancel; - _saveOperation = CancelableOperation.fromFuture( - Future.delayed(const Duration(seconds: 1), () async { - await UserSettingsService().setAppearanceSettings(setting); - }), - ); + _saveOperation?.cancel(); + _saveOperation = Timer(const Duration(seconds: 2), () async { + await UserSettingsService().setAppearanceSettings(setting); + }); } @override 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_bloc/text_cell_bloc.dart index 80bc722be7..407cde3d2c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/text_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/text_cell_bloc.dart @@ -17,6 +17,7 @@ class TextCellBloc extends Bloc { initial: (_InitialCell value) async {}, updateText: (_UpdateText value) { service.updateCell(data: value.text); + emit(state.copyWith(content: value.text)); }, ); }, 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 1db06d815c..fd2fefbac5 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -1,5 +1,6 @@ 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'; @@ -32,7 +33,7 @@ class GridBloc extends Bloc { delete: (_Delete value) {}, rename: (_Rename value) {}, updateDesc: (_Desc value) {}, - didLoadRows: (_DidLoadRows value) { + rowsDidUpdate: (_RowsDidUpdate value) { emit(state.copyWith(rows: value.rows)); }, ); @@ -47,10 +48,19 @@ class GridBloc extends Bloc { return super.close(); } - Future _startGridListening() async { - _blockService.didLoadRowscallback = (rows) { - add(GridEvent.didLoadRows(rows)); - }; + Future _initGridBlockService(Grid grid, List fields) async { + _blockService = GridBlockService( + gridId: grid.id, + fields: fields, + blockOrders: grid.blockOrders, + ); + + _blockService.rowsUpdateNotifier.addPublishListener((result) { + result.fold( + (rows) => add(GridEvent.rowsDidUpdate(rows)), + (err) => Log.error('$err'), + ); + }); _gridListener.start(); } @@ -70,36 +80,18 @@ class GridBloc extends Bloc { final result = await service.getFields(gridId: grid.id, fieldOrders: grid.fieldOrders); return Future( () => result.fold( - (fields) => _loadGridBlocks(grid, fields.items, emit), + (fields) { + _initGridBlockService(grid, fields.items); + emit(state.copyWith( + grid: Some(grid), + fields: Some(fields.items), + loadingState: GridLoadingState.finish(left(unit)), + )); + }, (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)))), ), ); } - - Future _loadGridBlocks(Grid grid, List fields, Emitter emit) async { - final result = await service.getGridBlocks(gridId: grid.id, blockOrders: grid.blockOrders); - result.fold( - (repeatedGridBlock) { - final gridBlocks = repeatedGridBlock.items; - final gridId = view.id; - _blockService = GridBlockService( - gridId: gridId, - fields: fields, - gridBlocks: gridBlocks, - ); - final rows = _blockService.rows(); - - _startGridListening(); - emit(state.copyWith( - grid: Some(grid), - fields: Some(fields), - rows: rows, - loadingState: GridLoadingState.finish(left(unit)), - )); - }, - (err) => emit(state.copyWith(loadingState: GridLoadingState.finish(right(err)), rows: [])), - ); - } } @freezed @@ -109,7 +101,7 @@ abstract class GridEvent with _$GridEvent { const factory GridEvent.updateDesc(String gridId, String desc) = _Desc; const factory GridEvent.delete(String gridId) = _Delete; const factory GridEvent.createRow() = _CreateRow; - const factory GridEvent.didLoadRows(List rows) = _DidLoadRows; + const factory GridEvent.rowsDidUpdate(List rows) = _RowsDidUpdate; } @freezed diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_block_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_block_service.dart index 3672a910f4..f84278399c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_block_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_block_service.dart @@ -1,5 +1,7 @@ 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-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/dart-notify/subject.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; @@ -9,40 +11,38 @@ import 'package:flowy_infra/notifier.dart'; import 'dart:async'; import 'dart:typed_data'; import 'package:app_flowy/core/notification_helper.dart'; - import 'grid_service.dart'; -typedef DidLoadRowsCallback = void Function(List); -typedef GridBlockUpdateNotifiedValue = Either; +typedef RowsUpdateNotifierValue = Either, FlowyError>; class GridBlockService { String gridId; List fields; LinkedHashMap blockMap = LinkedHashMap(); late GridBlockListener _blockListener; - DidLoadRowsCallback? didLoadRowscallback; + PublishNotifier rowsUpdateNotifier = PublishNotifier(); - GridBlockService({required this.gridId, required this.fields, required List gridBlocks}) { - for (final gridBlock in gridBlocks) { - blockMap[gridBlock.blockId] = gridBlock; - } + GridBlockService({required this.gridId, required this.fields, required List blockOrders}) { + _loadGridBlocks(blockOrders: blockOrders); _blockListener = GridBlockListener(gridId: gridId); - _blockListener.blockUpdateNotifier.addPublishListener((result) { - result.fold((blockId) { - // - }, (err) => null); + _blockListener.rowsUpdateNotifier.addPublishListener((result) { + result.fold( + (blockId) => _loadGridBlocks(blockOrders: [GridBlockOrder.create()..blockId = blockId.value]), + (err) => Log.error(err), + ); }); + _blockListener.start(); } - List rows() { + List buildRows() { List rows = []; blockMap.forEach((_, GridBlock gridBlock) { rows.addAll(gridBlock.rowOrders.map( (rowOrder) => GridRowData( gridId: gridId, fields: fields, - blockId: gridBlock.blockId, + blockId: gridBlock.id, rowId: rowOrder.rowId, height: rowOrder.height.toDouble(), ), @@ -54,11 +54,29 @@ class GridBlockService { Future stop() async { await _blockListener.stop(); } + + void _loadGridBlocks({required List blockOrders}) { + final payload = QueryGridBlocksPayload.create() + ..gridId = gridId + ..blockOrders.addAll(blockOrders); + + GridEventGetGridBlocks(payload).send().then((result) { + result.fold( + (repeatedBlocks) { + for (final gridBlock in repeatedBlocks.items) { + blockMap[gridBlock.id] = gridBlock; + } + rowsUpdateNotifier.value = left(buildRows()); + }, + (err) => rowsUpdateNotifier.value = right(err), + ); + }); + } } class GridBlockListener { final String gridId; - PublishNotifier blockUpdateNotifier = PublishNotifier(); + PublishNotifier> rowsUpdateNotifier = PublishNotifier(comparable: null); StreamSubscription? _subscription; late GridNotificationParser _parser; @@ -77,10 +95,10 @@ class GridBlockListener { void _handleObservableType(GridNotification ty, Either result) { switch (ty) { - case GridNotification.GridDidUpdateBlock: + case GridNotification.BlockDidUpdateRow: result.fold( - (payload) => blockUpdateNotifier.value = left(GridBlockId.fromBuffer(payload)), - (error) => blockUpdateNotifier.value = right(error), + (payload) => rowsUpdateNotifier.value = left(GridBlockId.fromBuffer(payload)), + (error) => rowsUpdateNotifier.value = right(error), ); break; @@ -91,6 +109,6 @@ class GridBlockListener { Future stop() async { await _subscription?.cancel(); - blockUpdateNotifier.dispose(); + rowsUpdateNotifier.dispose(); } } 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 506401706b..2aafd02fba 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -13,9 +13,9 @@ class GridService { return GridEventGetGridData(payload).send(); } - Future> createRow({required String gridId, Option? upperRowId}) { + Future> createRow({required String gridId, Option? startRowId}) { CreateRowPayload payload = CreateRowPayload.create()..gridId = gridId; - upperRowId?.fold(() => null, (id) => payload.startRowId = id); + startRowId?.fold(() => null, (id) => payload.startRowId = id); return GridEventCreateRow(payload).send(); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row_bloc.dart index bf13c682d7..67fcc5cbc2 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row_bloc.dart @@ -19,7 +19,7 @@ class RowBloc extends Bloc { await event.map( initial: (_InitialRow value) async { _startRowListening(); - await _loadCellDatas(emit); + await _loadRow(emit); }, createRow: (_CreateRow value) { rowService.createRow(); @@ -58,20 +58,20 @@ class RowBloc extends Bloc { listener.start(); } - Future _loadCellDatas(Emitter emit) async { - final result = await rowService.getRow(); - result.fold( - (row) { - emit(state.copyWith( - cellDatas: makeGridCellDatas(row), - rowHeight: row.height.toDouble(), - )); - }, - (e) => Log.error(e), - ); + Future _loadRow(Emitter emit) async { + final Future> cellDatas = rowService.getRow().then((result) { + return result.fold( + (row) => _makeCellDatas(row), + (e) { + Log.error(e); + return []; + }, + ); + }); + emit(state.copyWith(cellDatas: cellDatas)); } - List makeGridCellDatas(Row row) { + List _makeCellDatas(Row row) { return rowService.rowData.fields.map((field) { final cell = row.cellByFieldId[field.id]; final rowData = rowService.rowData; @@ -96,18 +96,18 @@ abstract class RowEvent with _$RowEvent { } @freezed -abstract class RowState with _$RowState { +class RowState with _$RowState { const factory RowState({ required String rowId, required double rowHeight, - required List cellDatas, + required Future> cellDatas, required bool active, }) = _RowState; factory RowState.initial(GridRowData data) => RowState( rowId: data.rowId, - active: false, rowHeight: data.height, - cellDatas: [], + cellDatas: Future(() => []), + active: false, ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/section.dart b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/section.dart index dcb2d454b9..ed0a718f58 100644 --- a/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/section.dart +++ b/frontend/app_flowy/lib/workspace/presentation/home/menu/app/section/section.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/view/view_ext.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; @@ -64,7 +66,7 @@ class ViewSectionNotifier with ChangeNotifier { bool isDisposed = false; List _views; View? _selectedView; - CancelableOperation? _notifyListenerOperation; + Timer? _notifyListenerOperation; ViewSectionNotifier({ required BuildContext context, @@ -120,9 +122,7 @@ class ViewSectionNotifier with ChangeNotifier { void _notifyListeners() { _notifyListenerOperation?.cancel(); - _notifyListenerOperation = CancelableOperation.fromFuture( - Future.delayed(const Duration(milliseconds: 30), () {}), - ).then((_) { + _notifyListenerOperation = Timer(const Duration(milliseconds: 30), () { if (!isDisposed) { notifyListeners(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/blank/blank.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/blank/blank.dart index 598f6971f2..05456f20f4 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/blank/blank.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/blank/blank.dart @@ -40,7 +40,7 @@ class BlankPagePlugin extends Plugin { PluginType get ty => _pluginType; } -class BlankPagePluginDisplay extends PluginDisplay { +class BlankPagePluginDisplay extends PluginDisplay with NavigationItem { @override Widget get leftBarItem => FlowyText.medium(LocaleKeys.blankPageTitle.tr(), fontSize: 12); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart index f027bf3e7a..e8f0290123 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/document.dart @@ -10,14 +10,13 @@ import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/appearance.dart'; import 'package:app_flowy/workspace/application/doc/share_bloc.dart'; import 'package:app_flowy/workspace/application/view/view_listener.dart'; -import 'package:app_flowy/workspace/application/view/view_service.dart'; import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; +import 'package:app_flowy/workspace/presentation/plugins/widgets/left_bar_item.dart'; import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart'; import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/notifier.dart'; import 'package:flowy_infra/size.dart'; -import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/widget/rounded_button.dart'; import 'package:flowy_sdk/log.dart'; @@ -89,7 +88,7 @@ class DocumentPlugin implements Plugin { PluginId get id => _view.id; } -class DocumentPluginDisplay extends PluginDisplay { +class DocumentPluginDisplay extends PluginDisplay with NavigationItem { final PublishNotifier _displayNotifier = PublishNotifier(); final View _view; @@ -99,91 +98,16 @@ class DocumentPluginDisplay extends PluginDisplay { Widget buildWidget() => DocumentPage(view: _view, key: ValueKey(_view.id)); @override - Widget get leftBarItem => DocumentLeftBarItem(view: _view); + Widget get leftBarItem => ViewLeftBarItem(view: _view); @override Widget? get rightBarItem => DocumentShareButton(view: _view); @override - List get navigationItems => _makeNavigationItems(); + List get navigationItems => [this]; @override PublishNotifier? get notifier => _displayNotifier; - - List _makeNavigationItems() { - return [ - this, - ]; - } -} - -class DocumentLeftBarItem extends StatefulWidget { - final View view; - - DocumentLeftBarItem({required this.view, Key? key}) : super(key: ValueKey(view.hashCode)); - - @override - State createState() => _DocumentLeftBarItemState(); -} - -class _DocumentLeftBarItemState extends State { - final _controller = TextEditingController(); - final _focusNode = FocusNode(); - late ViewService service; - - @override - void initState() { - service = ViewService(/*view: widget.view*/); - _focusNode.addListener(_handleFocusChanged); - super.initState(); - } - - @override - void dispose() { - _controller.dispose(); - _focusNode.removeListener(_handleFocusChanged); - _focusNode.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - _controller.text = widget.view.name; - - final theme = context.watch(); - return IntrinsicWidth( - key: ValueKey(_controller.text), - child: TextField( - controller: _controller, - focusNode: _focusNode, - scrollPadding: EdgeInsets.zero, - decoration: const InputDecoration( - contentPadding: EdgeInsets.zero, - border: InputBorder.none, - isDense: true, - ), - style: TextStyle( - color: theme.textColor, - fontSize: 14, - fontWeight: FontWeight.w500, - overflow: TextOverflow.ellipsis, - ), - // cursorColor: widget.cursorColor, - // obscureText: widget.enableObscure, - ), - ); - } - - void _handleFocusChanged() { - if (_controller.text.isEmpty) { - _controller.text = widget.view.name; - return; - } - - if (_controller.text != widget.view.name) { - service.updateView(viewId: widget.view.id, name: _controller.text); - } - } } class DocumentShareButton extends StatelessWidget { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart index cf6b4c9032..adc2a91fa9 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/grid.dart @@ -1,5 +1,5 @@ import 'package:app_flowy/workspace/presentation/home/home_stack.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:app_flowy/workspace/presentation/plugins/widgets/left_bar_item.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:app_flowy/plugin/plugin.dart'; import 'package:flutter/material.dart'; @@ -28,7 +28,7 @@ class GridPluginBuilder implements PluginBuilder { class GridPluginConfig implements PluginConfig { @override - bool get creatable => false; + bool get creatable => true; } class GridPlugin extends Plugin { @@ -56,7 +56,7 @@ class GridPluginDisplay extends PluginDisplay { GridPluginDisplay({required View view, Key? key}) : _view = view; @override - Widget get leftBarItem => const FlowyText.medium("Grid demo", fontSize: 12); + Widget get leftBarItem => ViewLeftBarItem(view: _view); @override Widget buildWidget() => GridPage(view: _view); 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 4e7747ac1d..1d6bc07891 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,42 +84,38 @@ class _FlowyGridState extends State { @override Widget build(BuildContext context) { return BlocBuilder( + buildWhen: (previous, current) => previous.fields != current.fields, builder: (context, state) { return state.fields.fold( () => const Center(child: CircularProgressIndicator.adaptive()), - (fields) => _renderGrid(context, fields), + (fields) => _wrapScrollbar(fields, [ + _buildHeader(fields), + _buildRows(context), + const GridFooter(), + ]), ); }, ); } - Widget _renderGrid(BuildContext context, List fields) { - return Stack( - children: [ - StyledSingleChildScrollView( - controller: _scrollController.horizontalController, - axis: Axis.horizontal, - child: SizedBox( - width: GridLayout.headerWidth(fields), - child: CustomScrollView( - physics: StyledScrollPhysics(), - controller: _scrollController.verticalController, - slivers: [ - _buildHeader(fields), - _buildRows(context), - const GridFooter(), - ], - ), + Widget _wrapScrollbar(List fields, List children) { + return ScrollbarListStack( + axis: Axis.vertical, + controller: _scrollController.verticalController, + barSize: GridSize.scrollBarSize, + child: StyledSingleChildScrollView( + controller: _scrollController.horizontalController, + axis: Axis.horizontal, + child: SizedBox( + width: GridLayout.headerWidth(fields), + child: CustomScrollView( + physics: StyledScrollPhysics(), + controller: _scrollController.verticalController, + slivers: [...children], ), ), - ScrollbarListStack( - axis: Axis.vertical, - controller: _scrollController.verticalController, - barSize: GridSize.scrollBarSize, - child: Container(), - ).padding(right: 0, top: GridSize.headerHeight, bottom: GridSize.scrollBarSize), - ], - ); + ), + ).padding(right: 0, top: GridSize.headerHeight, bottom: GridSize.scrollBarSize); } Widget _buildHeader(List fields) { @@ -131,15 +127,21 @@ class _FlowyGridState extends State { } Widget _buildRows(BuildContext context) { - return SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - final rowData = context.read().state.rows[index]; - return GridRowWidget(data: rowData); - }, - childCount: context.read().state.rows.length, - addRepaintBoundaries: true, - ), + return BlocBuilder( + buildWhen: (previous, current) => previous.rows.length != current.rows.length, + builder: (context, state) { + return SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + final rowData = context.read().state.rows[index]; + return GridRowWidget(data: rowData); + }, + childCount: context.read().state.rows.length, + addRepaintBoundaries: true, + addAutomaticKeepAlives: true, + ), + ); + }, ); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart index f062202744..3efc47d33c 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart @@ -11,7 +11,7 @@ import 'cell_container.dart'; class GridRowWidget extends StatefulWidget { final GridRowData data; - GridRowWidget({required this.data, Key? key}) : super(key: ObjectKey(data.rowId)); + GridRowWidget({required this.data, Key? key}) : super(key: ValueKey(data.rowId)); @override State createState() => _GridRowWidgetState(); @@ -30,28 +30,25 @@ class _GridRowWidgetState extends State { Widget build(BuildContext context) { return BlocProvider.value( value: _rowBloc, - child: GestureDetector( - behavior: HitTestBehavior.translucent, - child: MouseRegion( - cursor: SystemMouseCursors.click, - onEnter: (p) => _rowBloc.add(const RowEvent.activeRow()), - onExit: (p) => _rowBloc.add(const RowEvent.disactiveRow()), - child: BlocBuilder( - buildWhen: (p, c) => p.rowHeight != c.rowHeight, - builder: (context, state) { - return SizedBox( - height: _rowBloc.state.rowHeight, - child: Row( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const LeadingRow(), - _buildCells(), - const TrailingRow(), - ], - ), - ); - }, - ), + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (p) => _rowBloc.add(const RowEvent.activeRow()), + onExit: (p) => _rowBloc.add(const RowEvent.disactiveRow()), + child: BlocBuilder( + buildWhen: (p, c) => p.rowHeight != c.rowHeight, + builder: (context, state) { + return SizedBox( + height: _rowBloc.state.rowHeight, + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: const [ + _RowLeading(), + _RowCells(), + _RowTrailing(), + ], + ), + ); + }, ), ), ); @@ -62,69 +59,37 @@ class _GridRowWidgetState extends State { _rowBloc.close(); super.dispose(); } - - Widget _buildCells() { - return BlocBuilder( - buildWhen: (p, c) => p.cellDatas != c.cellDatas, - builder: (context, state) { - return Row( - children: state.cellDatas - .map( - (cellData) => CellContainer( - width: cellData.field.width.toDouble(), - child: buildGridCell(cellData), - ), - ) - .toList(), - ); - }, - ); - } } -class LeadingRow extends StatelessWidget { - const LeadingRow({Key? key}) : super(key: key); +class _RowLeading extends StatelessWidget { + const _RowLeading({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocSelector( selector: (state) => state.active, builder: (context, isActive) { - return SizedBox( - width: GridSize.leadingHeaderPadding, - child: isActive - ? Row( - mainAxisAlignment: MainAxisAlignment.center, - children: const [ - AppendRowButton(), - ], - ) - : null, - ); + return SizedBox(width: GridSize.leadingHeaderPadding, child: isActive ? _activeWidget() : null); }, ); } + + Widget _activeWidget() { + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + AppendRowButton(), + ], + ); + } } -class TrailingRow extends StatelessWidget { - const TrailingRow({Key? key}) : super(key: key); +class _RowTrailing extends StatelessWidget { + const _RowTrailing({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final theme = context.watch(); - final borderSide = BorderSide(color: theme.shader4, width: 0.4); - - return BlocBuilder( - builder: (context, state) { - return Container( - width: GridSize.trailHeaderPadding, - decoration: BoxDecoration( - border: Border(bottom: borderSide), - ), - padding: GridSize.cellContentInsets, - ); - }, - ); + return const SizedBox(); } } @@ -143,3 +108,37 @@ class AppendRowButton extends StatelessWidget { ); } } + +class _RowCells extends StatelessWidget { + const _RowCells({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.cellDatas != current.cellDatas, + builder: (context, state) { + return FutureBuilder( + future: state.cellDatas, + builder: builder, + ); + }, + ); + } + + Widget builder(context, AsyncSnapshot snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.done: + List cellDatas = snapshot.data; + return Row(children: cellDatas.map(_toCell).toList()); + default: + return const SizedBox(); + } + } + + Widget _toCell(GridCellData data) { + return CellContainer( + width: data.field.width.toDouble(), + child: buildGridCell(data), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/text_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/text_cell.dart index 71ab0c41bd..937c5d84ab 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/text_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/text_cell.dart @@ -1,6 +1,9 @@ +import 'dart:async'; + import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/cell_bloc/text_cell_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row_service.dart'; +import 'package:flowy_sdk/log.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -19,27 +22,40 @@ class GridTextCell extends StatefulWidget { class _GridTextCellState extends State { late TextEditingController _controller; + Timer? _delayOperation; final _focusNode = FocusNode(); - late TextCellBloc _cellBloc; + TextCellBloc? _cellBloc; @override void initState() { _cellBloc = getIt(param1: widget.cellData); - _controller = TextEditingController(text: _cellBloc.state.content); - _focusNode.addListener(_focusChanged); + _controller = TextEditingController(text: _cellBloc!.state.content); + _focusNode.addListener(save); super.initState(); } @override Widget build(BuildContext context) { return BlocProvider.value( - value: _cellBloc, + value: _cellBloc!, child: BlocBuilder( + buildWhen: (previous, current) { + return _controller.text != current.content; + }, builder: (context, state) { return TextField( controller: _controller, focusNode: _focusNode, - onChanged: (value) {}, + onChanged: (value) { + Log.info("On change"); + save(); + }, + onEditingComplete: () { + Log.info("On complete"); + }, + onSubmitted: (value) { + Log.info("On submit"); + }, maxLines: 1, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), decoration: const InputDecoration( @@ -55,13 +71,18 @@ class _GridTextCellState extends State { @override Future dispose() async { - _cellBloc.close(); - _focusNode.removeListener(_focusChanged); + _cellBloc?.close(); + _cellBloc = null; + _focusNode.removeListener(save); _focusNode.dispose(); super.dispose(); } - void _focusChanged() { - _cellBloc.add(TextCellEvent.updateText(_controller.text)); + Future save() async { + _delayOperation?.cancel(); + _delayOperation = Timer(const Duration(seconds: 2), () { + _cellBloc?.add(TextCellEvent.updateText(_controller.text)); + }); + // and later, before the timer goes off... } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart index 83d24535f4..e84640a584 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/header.dart @@ -42,6 +42,7 @@ class GridHeader extends StatelessWidget { @override Widget build(BuildContext context) { + final theme = context.watch(); return BlocProvider( create: (context) => getIt(param1: fields)..add(const ColumnEvent.initial()), child: BlocBuilder( @@ -55,13 +56,16 @@ class GridHeader extends StatelessWidget { ) .toList(); - return Row( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const LeadingHeaderCell(), - ...headers, - const TrailingHeaderCell(), - ], + return Container( + color: theme.surface, + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const LeadingHeaderCell(), + ...headers, + const TrailingHeaderCell(), + ], + ), ); }, ), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart new file mode 100644 index 0000000000..7c1e819cc5 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/widgets/left_bar_item.dart @@ -0,0 +1,74 @@ +import 'package:app_flowy/workspace/application/view/view_service.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class ViewLeftBarItem extends StatefulWidget { + final View view; + + ViewLeftBarItem({required this.view, Key? key}) : super(key: ValueKey(view.hashCode)); + + @override + State createState() => _ViewLeftBarItemState(); +} + +class _ViewLeftBarItemState extends State { + final _controller = TextEditingController(); + final _focusNode = FocusNode(); + late ViewService serviceService; + + @override + void initState() { + serviceService = ViewService(/*view: widget.view*/); + _focusNode.addListener(_handleFocusChanged); + super.initState(); + } + + @override + void dispose() { + _controller.dispose(); + _focusNode.removeListener(_handleFocusChanged); + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + _controller.text = widget.view.name; + + final theme = context.watch(); + return IntrinsicWidth( + key: ValueKey(_controller.text), + child: TextField( + controller: _controller, + focusNode: _focusNode, + scrollPadding: EdgeInsets.zero, + decoration: const InputDecoration( + contentPadding: EdgeInsets.zero, + border: InputBorder.none, + isDense: true, + ), + style: TextStyle( + color: theme.textColor, + fontSize: 14, + fontWeight: FontWeight.w500, + overflow: TextOverflow.ellipsis, + ), + // cursorColor: widget.cursorColor, + // obscureText: widget.enableObscure, + ), + ); + } + + void _handleFocusChanged() { + if (_controller.text.isEmpty) { + _controller.text = widget.view.name; + return; + } + + if (_controller.text != widget.view.name) { + serviceService.updateView(viewId: widget.view.id, name: _controller.text); + } + } +} diff --git a/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart b/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart index 0e0c6bc4cf..0079ba51a1 100644 --- a/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart +++ b/frontend/app_flowy/packages/flowy_infra/lib/notifier.dart @@ -1,10 +1,29 @@ import 'package:flutter/material.dart'; +abstract class Comparable { + bool compare(T? previous, T? current); +} + +class ObjectComparable extends Comparable { + @override + bool compare(T? previous, T? current) { + return previous == current; + } +} + class PublishNotifier extends ChangeNotifier { T? _value; + Comparable? comparable = ObjectComparable(); + + PublishNotifier({this.comparable}); set value(T newValue) { - if (_value != newValue) { + if (comparable != null) { + if (comparable!.compare(_value, newValue)) { + _value = newValue; + notifyListeners(); + } + } else { _value = newValue; notifyListeners(); } 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 bc713bbdb8..4462ce8b10 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 @@ -609,19 +609,19 @@ class GridBlockOrder extends $pb.GeneratedMessage { 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') ? '' : 'blockId') + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'id') ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrders', $pb.PbFieldType.PM, subBuilder: RowOrder.create) ..hasRequiredFields = false ; GridBlock._() : super(); factory GridBlock({ - $core.String? blockId, + $core.String? id, $core.Iterable? rowOrders, }) { final _result = create(); - if (blockId != null) { - _result.blockId = blockId; + if (id != null) { + _result.id = id; } if (rowOrders != null) { _result.rowOrders.addAll(rowOrders); @@ -650,13 +650,13 @@ class GridBlock extends $pb.GeneratedMessage { static GridBlock? _defaultInstance; @$pb.TagNumber(1) - $core.String get blockId => $_getSZ(0); + $core.String get id => $_getSZ(0); @$pb.TagNumber(1) - set blockId($core.String v) { $_setString(0, v); } + set id($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) - $core.bool hasBlockId() => $_has(0); + $core.bool hasId() => $_has(0); @$pb.TagNumber(1) - void clearBlockId() => clearField(1); + void clearId() => clearField(1); @$pb.TagNumber(2) $core.List get rowOrders => $_getList(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 5e24c82178..cde3112874 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 @@ -135,13 +135,13 @@ final $typed_data.Uint8List gridBlockOrderDescriptor = $convert.base64Decode('Cg const GridBlock$json = const { '1': 'GridBlock', '2': const [ - const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'}, + const {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'}, const {'1': 'row_orders', '3': 2, '4': 3, '5': 11, '6': '.RowOrder', '10': 'rowOrders'}, ], }; /// Descriptor for `GridBlock`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List gridBlockDescriptor = $convert.base64Decode('CglHcmlkQmxvY2sSGQoIYmxvY2tfaWQYASABKAlSB2Jsb2NrSWQSKAoKcm93X29yZGVycxgCIAMoCzIJLlJvd09yZGVyUglyb3dPcmRlcnM='); +final $typed_data.Uint8List gridBlockDescriptor = $convert.base64Decode('CglHcmlkQmxvY2sSDgoCaWQYASABKAlSAmlkEigKCnJvd19vcmRlcnMYAiADKAsyCS5Sb3dPcmRlclIJcm93T3JkZXJz'); @$core.Deprecated('Use cellDescriptor instead') const Cell$json = const { '1': 'Cell', 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 f68b10f292..27985d016c 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 @@ -11,15 +11,15 @@ 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 GridDidUpdateBlock = GridNotification._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidUpdateBlock'); static const GridNotification GridDidCreateBlock = GridNotification._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidCreateBlock'); - static const GridNotification GridDidUpdateCells = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidUpdateCells'); - static const GridNotification GridDidUpdateFields = GridNotification._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidUpdateFields'); + static const GridNotification BlockDidUpdateRow = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'BlockDidUpdateRow'); + static const GridNotification GridDidUpdateCells = GridNotification._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidUpdateCells'); + static const GridNotification GridDidUpdateFields = GridNotification._(40, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GridDidUpdateFields'); static const $core.List values = [ Unknown, - GridDidUpdateBlock, GridDidCreateBlock, + BlockDidUpdateRow, GridDidUpdateCells, GridDidUpdateFields, ]; 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 b266e63e09..0eebf85cc6 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 @@ -13,12 +13,12 @@ const GridNotification$json = const { '1': 'GridNotification', '2': const [ const {'1': 'Unknown', '2': 0}, - const {'1': 'GridDidUpdateBlock', '2': 10}, const {'1': 'GridDidCreateBlock', '2': 11}, - const {'1': 'GridDidUpdateCells', '2': 20}, - const {'1': 'GridDidUpdateFields', '2': 30}, + const {'1': 'BlockDidUpdateRow', '2': 20}, + const {'1': 'GridDidUpdateCells', '2': 30}, + const {'1': 'GridDidUpdateFields', '2': 40}, ], }; /// Descriptor for `GridNotification`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABIWChJHcmlkRGlkVXBkYXRlQmxvY2sQChIWChJHcmlkRGlkQ3JlYXRlQmxvY2sQCxIWChJHcmlkRGlkVXBkYXRlQ2VsbHMQFBIXChNHcmlkRGlkVXBkYXRlRmllbGRzEB4='); +final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABIWChJHcmlkRGlkQ3JlYXRlQmxvY2sQCxIVChFCbG9ja0RpZFVwZGF0ZVJvdxAUEhYKEkdyaWREaWRVcGRhdGVDZWxscxAeEhcKE0dyaWREaWRVcGRhdGVGaWVsZHMQKA=='); diff --git a/frontend/rust-lib/flowy-grid/src/dart_notification.rs b/frontend/rust-lib/flowy-grid/src/dart_notification.rs index 82ab35bdee..927b71d957 100644 --- a/frontend/rust-lib/flowy-grid/src/dart_notification.rs +++ b/frontend/rust-lib/flowy-grid/src/dart_notification.rs @@ -5,11 +5,13 @@ const OBSERVABLE_CATEGORY: &str = "Grid"; #[derive(ProtoBuf_Enum, Debug)] pub enum GridNotification { Unknown = 0, - GridDidUpdateBlock = 10, + GridDidCreateBlock = 11, - GridDidUpdateCells = 20, - GridDidUpdateFields = 30, + BlockDidUpdateRow = 20, + + GridDidUpdateCells = 30, + GridDidUpdateFields = 40, } impl std::default::Default for GridNotification { diff --git a/frontend/rust-lib/flowy-grid/src/manager.rs b/frontend/rust-lib/flowy-grid/src/manager.rs index 75499acdac..e4f24a8547 100644 --- a/frontend/rust-lib/flowy-grid/src/manager.rs +++ b/frontend/rust-lib/flowy-grid/src/manager.rs @@ -83,7 +83,7 @@ impl GridManager { Ok(()) } - #[tracing::instrument(level = "debug", skip(self), err)] + // #[tracing::instrument(level = "debug", skip(self), err)] pub fn get_grid_editor(&self, grid_id: &str) -> FlowyResult> { match self.editor_map.get(grid_id) { None => Err(FlowyError::internal().context("Should call open_grid function first")), 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 72b3f12abd..4562b238c0 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 @@ -26,10 +26,10 @@ #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum GridNotification { Unknown = 0, - GridDidUpdateBlock = 10, GridDidCreateBlock = 11, - GridDidUpdateCells = 20, - GridDidUpdateFields = 30, + BlockDidUpdateRow = 20, + GridDidUpdateCells = 30, + GridDidUpdateFields = 40, } impl ::protobuf::ProtobufEnum for GridNotification { @@ -40,10 +40,10 @@ impl ::protobuf::ProtobufEnum for GridNotification { fn from_i32(value: i32) -> ::std::option::Option { match value { 0 => ::std::option::Option::Some(GridNotification::Unknown), - 10 => ::std::option::Option::Some(GridNotification::GridDidUpdateBlock), 11 => ::std::option::Option::Some(GridNotification::GridDidCreateBlock), - 20 => ::std::option::Option::Some(GridNotification::GridDidUpdateCells), - 30 => ::std::option::Option::Some(GridNotification::GridDidUpdateFields), + 20 => ::std::option::Option::Some(GridNotification::BlockDidUpdateRow), + 30 => ::std::option::Option::Some(GridNotification::GridDidUpdateCells), + 40 => ::std::option::Option::Some(GridNotification::GridDidUpdateFields), _ => ::std::option::Option::None } } @@ -51,8 +51,8 @@ impl ::protobuf::ProtobufEnum for GridNotification { fn values() -> &'static [Self] { static values: &'static [GridNotification] = &[ GridNotification::Unknown, - GridNotification::GridDidUpdateBlock, GridNotification::GridDidCreateBlock, + GridNotification::BlockDidUpdateRow, GridNotification::GridDidUpdateCells, GridNotification::GridDidUpdateFields, ]; @@ -83,10 +83,10 @@ impl ::protobuf::reflect::ProtobufValue for GridNotification { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x17dart_notification.proto*\x80\x01\n\x10GridNotification\x12\x0b\n\ - \x07Unknown\x10\0\x12\x16\n\x12GridDidUpdateBlock\x10\n\x12\x16\n\x12Gri\ - dDidCreateBlock\x10\x0b\x12\x16\n\x12GridDidUpdateCells\x10\x14\x12\x17\ - \n\x13GridDidUpdateFields\x10\x1eb\x06proto3\ + \n\x17dart_notification.proto*\x7f\n\x10GridNotification\x12\x0b\n\x07Un\ + known\x10\0\x12\x16\n\x12GridDidCreateBlock\x10\x0b\x12\x15\n\x11BlockDi\ + dUpdateRow\x10\x14\x12\x16\n\x12GridDidUpdateCells\x10\x1e\x12\x17\n\x13\ + GridDidUpdateFields\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 0262b34477..be25f80f3b 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 @@ -2,8 +2,8 @@ syntax = "proto3"; enum GridNotification { Unknown = 0; - GridDidUpdateBlock = 10; GridDidCreateBlock = 11; - GridDidUpdateCells = 20; - GridDidUpdateFields = 30; + BlockDidUpdateRow = 20; + GridDidUpdateCells = 30; + GridDidUpdateFields = 40; } 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 ca3f99b363..4a73ccd1b1 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 @@ -46,7 +46,9 @@ impl GridBlockMetaEditorManager { Ok(manager) } + // #[tracing::instrument(level = "trace", skip(self))] pub(crate) async fn get_editor(&self, block_id: &str) -> FlowyResult> { + debug_assert!(!block_id.is_empty()); match self.editor_map.get(block_id) { None => { tracing::error!("The is a fatal error, block is not exist"); @@ -68,7 +70,7 @@ impl GridBlockMetaEditorManager { .insert(row_meta.id.clone(), row_meta.block_id.clone()); let editor = self.get_editor(&row_meta.block_id).await?; let row_count = editor.create_row(row_meta, start_row_id).await?; - self.notify_did_update_block(block_id).await?; + self.notify_block_did_update_row(&block_id).await?; Ok(row_count) } @@ -85,7 +87,7 @@ impl GridBlockMetaEditorManager { row_count = editor.create_row(row.clone(), None).await?; } changesets.push(GridBlockMetaChangeset::from_row_count(&block_id, row_count)); - let _ = self.notify_did_update_block(&block_id).await?; + let _ = self.notify_block_did_update_row(&block_id).await?; } Ok(changesets) @@ -108,7 +110,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?; - let _ = self.notify_did_update_block(&editor.block_id).await?; + let _ = self.notify_block_did_update_row(&editor.block_id).await?; Ok(()) } @@ -183,11 +185,9 @@ impl GridBlockMetaEditorManager { } } - async fn notify_did_update_block(&self, block_id: &str) -> FlowyResult<()> { - let block_id = GridBlockId { - value: block_id.to_owned(), - }; - send_dart_notification(&self.grid_id, GridNotification::GridDidUpdateBlock) + async fn notify_block_did_update_row(&self, block_id: &str) -> FlowyResult<()> { + let block_id: GridBlockId = block_id.into(); + send_dart_notification(&self.grid_id, GridNotification::BlockDidUpdateRow) .payload(block_id) .send(); Ok(()) @@ -277,7 +277,7 @@ impl ClientGridBlockMetaEditor { let mut row_count = 0; let _ = self .modify(|pad| { - let change = pad.add_row(row, start_row_id)?; + let change = pad.add_row_meta(row, start_row_id)?; row_count = pad.number_of_rows(); Ok(change) }) @@ -298,13 +298,22 @@ impl ClientGridBlockMetaEditor { Ok(row_count) } - pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult<()> { + pub async fn update_row(&self, changeset: RowMetaChangeset) -> FlowyResult { + let row_id = changeset.row_id.clone(); let _ = self.modify(|pad| Ok(pad.update_row(changeset)?)).await?; - Ok(()) + let mut row_metas = self.get_row_metas(Some(vec![row_id.clone()])).await?; + debug_assert_eq!(row_metas.len(), 1); + + if row_metas.is_empty() { + return Err(FlowyError::record_not_found().context(format!("Can't find the row with id: {}", &row_id))); + } else { + let a = (**row_metas.pop().as_ref().unwrap()).clone(); + Ok(a) + } } pub async fn get_row_metas(&self, row_ids: Option>) -> FlowyResult>> { - let row_metas = self.pad.read().await.get_rows(row_ids)?; + let row_metas = self.pad.read().await.get_row_metas(row_ids)?; Ok(row_metas) } @@ -313,7 +322,7 @@ impl ClientGridBlockMetaEditor { .pad .read() .await - .get_rows(row_ids)? + .get_row_metas(row_ids)? .iter() .map(RowOrder::from) .collect::>(); diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs index bf2f62c776..70cea1b4c8 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs @@ -43,10 +43,10 @@ pub(crate) fn make_row_ids_per_block(row_orders: &[RowOrder]) -> Vec) -> FlowyResult { Ok(block_meta_snapshots .into_iter() - .map(|row_metas_per_block| { - let row_orders = make_row_orders_from_row_metas(&row_metas_per_block.row_metas); + .map(|block_meta_data| { + let row_orders = make_row_orders_from_row_metas(&block_meta_data.row_metas); GridBlock { - block_id: row_metas_per_block.block_id, + id: block_meta_data.block_id, row_orders, } }) diff --git a/frontend/rust-lib/flowy-revision/src/rev_manager.rs b/frontend/rust-lib/flowy-revision/src/rev_manager.rs index 3cd9b54de0..68d8db6f27 100644 --- a/frontend/rust-lib/flowy-revision/src/rev_manager.rs +++ b/frontend/rust-lib/flowy-revision/src/rev_manager.rs @@ -67,6 +67,7 @@ impl RevisionManager { } } + #[tracing::instrument(level = "debug", skip_all, fields(object_id) err)] pub async fn load(&mut self, cloud: Option>) -> FlowyResult where B: RevisionObjectBuilder, @@ -80,6 +81,7 @@ impl RevisionManager { .load() .await?; self.rev_id_counter.set(rev_id); + tracing::Span::current().record("object_id", &self.object_id.as_str()); B::build_object(&self.object_id, revisions) } 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 c195a85c24..e9a80c4be3 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -181,7 +181,7 @@ pub struct GridBlockOrder { #[derive(Debug, Default, ProtoBuf)] pub struct GridBlock { #[pb(index = 1)] - pub block_id: String, + pub id: String, #[pb(index = 2)] pub row_orders: Vec, @@ -190,7 +190,7 @@ pub struct GridBlock { impl GridBlock { pub fn new(block_id: &str, row_orders: Vec) -> Self { Self { - block_id: block_id.to_owned(), + id: block_id.to_owned(), row_orders, } } @@ -269,6 +269,12 @@ impl AsRef for GridBlockId { } } +impl std::convert::From<&str> for GridBlockId { + fn from(s: &str) -> Self { + GridBlockId { value: s.to_owned() } + } +} + #[derive(ProtoBuf, Default)] pub struct CreateRowPayload { #[pb(index = 1)] diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs index fc538875c9..f947f70851 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 @@ -2111,7 +2111,7 @@ impl ::protobuf::reflect::ProtobufValue for GridBlockOrder { #[derive(PartialEq,Clone,Default)] pub struct GridBlock { // message fields - pub block_id: ::std::string::String, + pub id: ::std::string::String, pub row_orders: ::protobuf::RepeatedField, // special fields pub unknown_fields: ::protobuf::UnknownFields, @@ -2129,30 +2129,30 @@ impl GridBlock { ::std::default::Default::default() } - // string block_id = 1; + // string id = 1; - pub fn get_block_id(&self) -> &str { - &self.block_id + pub fn get_id(&self) -> &str { + &self.id } - pub fn clear_block_id(&mut self) { - self.block_id.clear(); + pub fn clear_id(&mut self) { + self.id.clear(); } // Param is passed by value, moved - pub fn set_block_id(&mut self, v: ::std::string::String) { - self.block_id = v; + pub fn set_id(&mut self, v: ::std::string::String) { + self.id = v; } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. - pub fn mut_block_id(&mut self) -> &mut ::std::string::String { - &mut self.block_id + pub fn mut_id(&mut self) -> &mut ::std::string::String { + &mut self.id } // Take field - pub fn take_block_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.block_id, ::std::string::String::new()) + pub fn take_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.id, ::std::string::String::new()) } // repeated .RowOrder row_orders = 2; @@ -2196,7 +2196,7 @@ impl ::protobuf::Message for GridBlock { 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.block_id)?; + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.id)?; }, 2 => { ::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.row_orders)?; @@ -2213,8 +2213,8 @@ impl ::protobuf::Message for GridBlock { #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; - if !self.block_id.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.block_id); + if !self.id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.id); } for value in &self.row_orders { let len = value.compute_size(); @@ -2226,8 +2226,8 @@ impl ::protobuf::Message for GridBlock { } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.block_id.is_empty() { - os.write_string(1, &self.block_id)?; + if !self.id.is_empty() { + os.write_string(1, &self.id)?; } for v in &self.row_orders { os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?; @@ -2273,9 +2273,9 @@ impl ::protobuf::Message for GridBlock { descriptor.get(|| { let mut fields = ::std::vec::Vec::new(); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "block_id", - |m: &GridBlock| { &m.block_id }, - |m: &mut GridBlock| { &mut m.block_id }, + "id", + |m: &GridBlock| { &m.id }, + |m: &mut GridBlock| { &mut m.id }, )); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "row_orders", @@ -2298,7 +2298,7 @@ impl ::protobuf::Message for GridBlock { impl ::protobuf::Clear for GridBlock { fn clear(&mut self) { - self.block_id.clear(); + self.id.clear(); self.row_orders.clear(); self.unknown_fields.clear(); } @@ -4091,24 +4091,24 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \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\"+\n\x0eGridBlockO\ - rder\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\"P\n\tGridBloc\ - k\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_order\ - s\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\x04Cell\x12\x19\n\ - \x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07content\x18\x02\ - \x20\x01(\tR\x07content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\ - \x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\n\ - \x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05valu\ - e\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\"d\n\x11QueryField\ - Payload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfie\ - ld_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.GridBlockOrd\ - erR\x0bblockOrders\"\\\n\x0fQueryRowPayload\x12\x17\n\x07grid_id\x18\x01\ - \x20\x01(\tR\x06gridId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07bloc\ - kId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowIdb\x06proto3\ + rder\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\"E\n\tGridBloc\ + k\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\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b\ + 2\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\x10CreateRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\ + \x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0R\nstart\ + RowIdB\x15\n\x13one_of_start_row_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\"\\\n\x0fQueryRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06g\ + ridId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x15\n\x06\ + row_id\x18\x03\x20\x01(\tR\x05rowIdb\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 2ce7c429d5..00dee86f6b 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 @@ -44,7 +44,7 @@ message GridBlockOrder { string block_id = 1; } message GridBlock { - string block_id = 1; + string id = 1; repeated RowOrder row_orders = 2; } message Cell { 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 7bfef998c2..768c7bf60a 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 @@ -47,20 +47,21 @@ impl GridBlockMetaPad { Self::from_delta(block_delta) } - pub fn add_row( + #[tracing::instrument(level = "trace", skip(self, row), err)] + pub fn add_row_meta( &mut self, row: RowMeta, start_row_id: Option, ) -> CollaborateResult> { self.modify(|rows| { - if let Some(upper_row_id) = start_row_id { - if upper_row_id.is_empty() { + if let Some(start_row_id) = start_row_id { + if start_row_id.is_empty() { rows.insert(0, Arc::new(row)); return Ok(Some(())); } - if let Some(index) = rows.iter().position(|row| row.id == upper_row_id) { - rows.insert(index, Arc::new(row)); + if let Some(index) = rows.iter().position(|row| row.id == start_row_id) { + rows.insert(index + 1, Arc::new(row)); return Ok(Some(())); } } @@ -77,7 +78,7 @@ impl GridBlockMetaPad { }) } - pub fn get_rows(&self, row_ids: Option>) -> CollaborateResult>> { + pub fn get_row_metas(&self, row_ids: Option>) -> CollaborateResult>> { match row_ids { None => Ok(self.row_metas.to_vec()), Some(row_ids) => { @@ -229,7 +230,7 @@ mod tests { visibility: false, }; - let change = pad.add_row(row, None).unwrap().unwrap(); + let change = pad.add_row_meta(row, None).unwrap().unwrap(); assert_eq!( change.delta.to_delta_str(), r#"[{"retain":29},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"# @@ -243,19 +244,19 @@ mod tests { let row_2 = test_row_meta("2", &pad); let row_3 = test_row_meta("3", &pad); - let change = pad.add_row(row_1.clone(), None).unwrap().unwrap(); + let change = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap(); assert_eq!( change.delta.to_delta_str(), r#"[{"retain":29},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); - let change = pad.add_row(row_2.clone(), None).unwrap().unwrap(); + let change = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap(); assert_eq!( change.delta.to_delta_str(), r#"[{"retain":106},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"# ); - let change = pad.add_row(row_3.clone(), Some("2".to_string())).unwrap().unwrap(); + let change = pad.add_row_meta(row_3.clone(), Some("2".to_string())).unwrap().unwrap(); assert_eq!( change.delta.to_delta_str(), r#"[{"retain":114},{"insert":"3\",\"block_id\":\"1\",\"cell_by_field_id\":{},\"height\":0,\"visibility\":false},{\"id\":\""},{"retain":72}]"# @@ -283,9 +284,9 @@ mod tests { let row_2 = test_row_meta("2", &pad); let row_3 = test_row_meta("3", &pad); - let _ = pad.add_row(row_1.clone(), None).unwrap().unwrap(); - let _ = pad.add_row(row_2.clone(), None).unwrap().unwrap(); - let _ = pad.add_row(row_3.clone(), Some("1".to_string())).unwrap().unwrap(); + let _ = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row_3.clone(), Some("1".to_string())).unwrap().unwrap(); assert_eq!(*pad.row_metas[0], row_3); assert_eq!(*pad.row_metas[1], row_1); @@ -299,9 +300,9 @@ mod tests { let row_2 = test_row_meta("2", &pad); let row_3 = test_row_meta("3", &pad); - let _ = pad.add_row(row_1.clone(), None).unwrap().unwrap(); - let _ = pad.add_row(row_2.clone(), None).unwrap().unwrap(); - let _ = pad.add_row(row_3.clone(), Some("".to_string())).unwrap().unwrap(); + let _ = pad.add_row_meta(row_1.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row_2.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row_3.clone(), Some("".to_string())).unwrap().unwrap(); assert_eq!(*pad.row_metas[0], row_3); assert_eq!(*pad.row_metas[1], row_1); @@ -320,7 +321,7 @@ mod tests { visibility: false, }; - let _ = pad.add_row(row.clone(), None).unwrap().unwrap(); + let _ = pad.add_row_meta(row.clone(), None).unwrap().unwrap(); let change = pad.delete_rows(&[row.id]).unwrap().unwrap(); assert_eq!( change.delta.to_delta_str(), @@ -348,7 +349,7 @@ mod tests { cell_by_field_id: Default::default(), }; - let _ = pad.add_row(row, None).unwrap().unwrap(); + let _ = pad.add_row_meta(row, None).unwrap().unwrap(); let change = pad.update_row(changeset).unwrap().unwrap(); assert_eq!(