Merge pull request #442 from AppFlowy-IO/feat_row_delete

Feature: support row delete
This commit is contained in:
Nathan.fooo 2022-04-10 14:57:45 +08:00 committed by GitHub
commit 5d9763ff7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1950 additions and 797 deletions

View File

@ -8,12 +8,8 @@ name: Flutter lint
on:
push:
branches: [ main ]
paths:
- 'frontend/app_flowy'
pull_request:
branches: [ main ]
paths:
- 'frontend/app_flowy'
env:
CARGO_TERM_COLOR: always

View File

@ -3,14 +3,8 @@ name: Rust lint
on:
push:
branches: [ main ]
paths:
- 'frontend/rust-lib'
- 'shared-lib'
pull_request:
branches: [ main ]
paths:
- 'frontend/rust-lib'
- 'shared-lib'
env:

View File

@ -4,15 +4,9 @@ on:
push:
branches:
- 'main'
paths:
- 'frontend/rust-lib'
- 'shared-lib'
pull_request:
branches:
- 'main'
paths:
- 'frontend/rust-lib'
- 'shared-lib'
env:
CARGO_TERM_COLOR: always

View File

@ -174,6 +174,10 @@
"addOption": "Add option",
"editProperty": "Edit property"
},
"row": {
"duplicate": "Duplicate",
"delete": "Delete"
},
"selectOption": {
"purpleColor": "Purple",
"pinkColor": "Pink",

View File

@ -5,7 +5,6 @@ import 'package:app_flowy/workspace/application/app/prelude.dart';
import 'package:app_flowy/workspace/application/doc/prelude.dart';
import 'package:app_flowy/workspace/application/grid/field/type_option/multi_select_bloc.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart';
import 'package:app_flowy/workspace/application/grid/row/row_listener.dart';
import 'package:app_flowy/workspace/application/trash/prelude.dart';
import 'package:app_flowy/workspace/application/workspace/prelude.dart';
import 'package:app_flowy/workspace/application/edit_pannel/edit_pannel_bloc.dart';
@ -148,13 +147,12 @@ void _resolveDocDeps(GetIt getIt) {
void _resolveGridDeps(GetIt getIt) {
// Grid
getIt.registerFactoryParam<GridBloc, View, void>(
(view, _) => GridBloc(view: view, service: GridService()),
(view, _) => GridBloc(view: view),
);
getIt.registerFactoryParam<RowBloc, RowData, void>(
(data, _) => RowBloc(
rowData: data,
rowlistener: RowListener(rowId: data.rowId),
),
);

View File

@ -110,7 +110,7 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
void _loadOptions() async {
_delayOperation?.cancel();
_delayOperation = Timer(
const Duration(milliseconds: 300),
const Duration(milliseconds: 1),
() async {
final result = await _selectOptionService.getOpitonContext(
gridId: state.gridId,
@ -119,10 +119,14 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
);
result.fold(
(selectOptionContext) => add(SelectOptionEditorEvent.didReceiveOptions(
selectOptionContext.options,
selectOptionContext.selectOptions,
)),
(selectOptionContext) {
if (!isClosed) {
add(SelectOptionEditorEvent.didReceiveOptions(
selectOptionContext.options,
selectOptionContext.selectOptions,
));
}
},
(err) => Log.error(err),
);
},

View File

@ -5,14 +5,14 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import 'field_service.dart';
part 'action_sheet_bloc.freezed.dart';
part 'field_action_sheet_bloc.freezed.dart';
class FieldActionSheetBloc extends Bloc<ActionSheetEvent, ActionSheetState> {
class FieldActionSheetBloc extends Bloc<FieldActionSheetEvent, FieldActionSheetState> {
final FieldService service;
FieldActionSheetBloc({required Field field, required this.service})
: super(ActionSheetState.initial(EditFieldContext.create()..gridField = field)) {
on<ActionSheetEvent>(
: super(FieldActionSheetState.initial(EditFieldContext.create()..gridField = field)) {
on<FieldActionSheetEvent>(
(event, emit) async {
await event.map(
updateFieldName: (_UpdateFieldName value) async {
@ -56,23 +56,23 @@ class FieldActionSheetBloc extends Bloc<ActionSheetEvent, ActionSheetState> {
}
@freezed
class ActionSheetEvent with _$ActionSheetEvent {
const factory ActionSheetEvent.updateFieldName(String name) = _UpdateFieldName;
const factory ActionSheetEvent.hideField() = _HideField;
const factory ActionSheetEvent.duplicateField() = _DuplicateField;
const factory ActionSheetEvent.deleteField() = _DeleteField;
const factory ActionSheetEvent.saveField() = _SaveField;
class FieldActionSheetEvent with _$FieldActionSheetEvent {
const factory FieldActionSheetEvent.updateFieldName(String name) = _UpdateFieldName;
const factory FieldActionSheetEvent.hideField() = _HideField;
const factory FieldActionSheetEvent.duplicateField() = _DuplicateField;
const factory FieldActionSheetEvent.deleteField() = _DeleteField;
const factory FieldActionSheetEvent.saveField() = _SaveField;
}
@freezed
class ActionSheetState with _$ActionSheetState {
const factory ActionSheetState({
class FieldActionSheetState with _$FieldActionSheetState {
const factory FieldActionSheetState({
required EditFieldContext editContext,
required String errorText,
required String fieldName,
}) = _ActionSheetState;
}) = _FieldActionSheetState;
factory ActionSheetState.initial(EditFieldContext editContext) => ActionSheetState(
factory FieldActionSheetState.initial(EditFieldContext editContext) => FieldActionSheetState(
editContext: editContext,
errorText: '',
fieldName: editContext.gridField.name,

View File

@ -6,33 +6,33 @@ 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 'package:equatable/equatable.dart';
import 'grid_block_service.dart';
import 'field/grid_listenr.dart';
import 'grid_listener.dart';
import 'grid_service.dart';
part 'grid_bloc.freezed.dart';
class GridBloc extends Bloc<GridEvent, GridState> {
final View view;
final GridService service;
final GridService _gridService;
final GridListener _gridListener;
final GridFieldsListener _fieldListener;
GridBlockService? _blockService;
GridBloc({required this.view, required this.service})
GridBloc({required this.view})
: _fieldListener = GridFieldsListener(gridId: view.id),
_gridService = GridService(),
_gridListener = GridListener(gridId: view.id),
super(GridState.initial()) {
on<GridEvent>(
(event, emit) async {
await event.map(
initial: (InitialGrid value) async {
await _initGrid(emit);
_startListening();
},
createRow: (_CreateRow value) {
service.createRow(gridId: view.id);
_gridService.createRow(gridId: view.id);
},
delete: (_Delete value) {},
rename: (_Rename value) {},
updateDesc: (_Desc value) {},
didReceiveRowUpdate: (_DidReceiveRowUpdate value) {
emit(state.copyWith(rows: value.rows));
@ -48,7 +48,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
@override
Future<void> close() async {
await _fieldListener.stop();
await _blockService?.stop();
await _gridListener.stop();
return super.close();
}
@ -64,22 +64,29 @@ class GridBloc extends Bloc<GridEvent, GridState> {
await _loadGrid(emit);
}
Future<void> _initGridBlock(Grid grid) async {
_blockService = GridBlockService(
gridId: grid.id,
blockOrders: grid.blockOrders,
);
void _startListening() {
_gridListener.rowsUpdateNotifier.addPublishListener((result) {
result.fold((gridBlockChangeset) {
for (final changeset in gridBlockChangeset) {
if (changeset.insertedRows.isNotEmpty) {
_insertRows(changeset.insertedRows);
}
_blockService?.blocksUpdateNotifier?.addPublishListener((result) {
result.fold(
(blockMap) => add(GridEvent.didReceiveRowUpdate(_buildRows(blockMap))),
(err) => Log.error('$err'),
);
if (changeset.deletedRows.isNotEmpty) {
_deleteRows(changeset.deletedRows);
}
if (changeset.updatedRows.isNotEmpty) {
_updateRows(changeset.updatedRows);
}
}
}, (err) => Log.error(err));
});
_gridListener.start();
}
Future<void> _loadGrid(Emitter<GridState> emit) async {
final result = await service.openGrid(gridId: view.id);
final result = await _gridService.loadGrid(gridId: view.id);
return Future(
() => result.fold(
(grid) async => await _loadFields(grid, emit),
@ -89,14 +96,14 @@ class GridBloc extends Bloc<GridEvent, GridState> {
}
Future<void> _loadFields(Grid grid, Emitter<GridState> emit) async {
final result = await service.getFields(gridId: grid.id, fieldOrders: grid.fieldOrders);
final result = await _gridService.getFields(gridId: grid.id, fieldOrders: grid.fieldOrders);
return Future(
() => result.fold(
(fields) {
_initGridBlock(grid);
emit(state.copyWith(
grid: Some(grid),
fields: fields.items,
rows: _buildRows(grid.blockOrders),
loadingState: GridLoadingState.finish(left(unit)),
));
},
@ -105,30 +112,50 @@ class GridBloc extends Bloc<GridEvent, GridState> {
);
}
List<GridBlockRow> _buildRows(GridBlockMap blockMap) {
List<GridBlockRow> rows = [];
blockMap.forEach((_, GridBlock gridBlock) {
rows.addAll(gridBlock.rowOrders.map(
(rowOrder) => GridBlockRow(
gridId: view.id,
blockId: gridBlock.id,
rowId: rowOrder.rowId,
height: rowOrder.height.toDouble(),
),
));
});
return rows;
void _deleteRows(List<RowOrder> deletedRows) {
final List<RowOrder> rows = List.from(state.rows);
rows.retainWhere(
(row) => deletedRows.where((deletedRow) => deletedRow.rowId == row.rowId).isEmpty,
);
add(GridEvent.didReceiveRowUpdate(rows));
}
void _insertRows(List<IndexRowOrder> createdRows) {
final List<RowOrder> rows = List.from(state.rows);
for (final newRow in createdRows) {
if (newRow.hasIndex()) {
rows.insert(newRow.index, newRow.rowOrder);
} else {
rows.add(newRow.rowOrder);
}
}
add(GridEvent.didReceiveRowUpdate(rows));
}
void _updateRows(List<RowOrder> updatedRows) {
final List<RowOrder> rows = List.from(state.rows);
for (final updatedRow in updatedRows) {
final index = rows.indexWhere((row) => row.rowId == updatedRow.rowId);
if (index != -1) {
rows.removeAt(index);
rows.insert(index, updatedRow);
}
}
add(GridEvent.didReceiveRowUpdate(rows));
}
List<RowOrder> _buildRows(List<GridBlockOrder> blockOrders) {
return blockOrders.expand((blockOrder) => blockOrder.rowOrders).toList();
}
}
@freezed
class GridEvent with _$GridEvent {
const factory GridEvent.initial() = InitialGrid;
const factory GridEvent.rename(String gridId, String name) = _Rename;
const factory GridEvent.updateDesc(String gridId, String desc) = _Desc;
const factory GridEvent.delete(String gridId) = _Delete;
const factory GridEvent.createRow() = _CreateRow;
const factory GridEvent.didReceiveRowUpdate(List<GridBlockRow> rows) = _DidReceiveRowUpdate;
const factory GridEvent.didReceiveRowUpdate(List<RowOrder> rows) = _DidReceiveRowUpdate;
const factory GridEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
}
@ -137,7 +164,7 @@ class GridState with _$GridState {
const factory GridState({
required GridLoadingState loadingState,
required List<Field> fields,
required List<GridBlockRow> rows,
required List<RowOrder> rows,
required Option<Grid> grid,
}) = _GridState;
@ -154,46 +181,3 @@ class GridLoadingState with _$GridLoadingState {
const factory GridLoadingState.loading() = _Loading;
const factory GridLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish;
}
class GridBlockRow {
final String gridId;
final String rowId;
final String blockId;
final double height;
const GridBlockRow({
required this.gridId,
required this.rowId,
required this.blockId,
required this.height,
});
}
class RowData extends Equatable {
final String gridId;
final String rowId;
final String blockId;
final List<Field> fields;
final double height;
const RowData({
required this.gridId,
required this.rowId,
required this.blockId,
required this.fields,
required this.height,
});
factory RowData.fromBlockRow(GridBlockRow row, List<Field> fields) {
return RowData(
gridId: row.gridId,
rowId: row.rowId,
blockId: row.blockId,
fields: fields,
height: row.height,
);
}
@override
List<Object> get props => [rowId, fields];
}

View File

@ -1,92 +0,0 @@
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/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
import 'package:flowy_infra/notifier.dart';
import 'dart:async';
import 'dart:typed_data';
import 'package:app_flowy/core/notification_helper.dart';
typedef GridBlockMap = LinkedHashMap<String, GridBlock>;
typedef BlocksUpdateNotifierValue = Either<GridBlockMap, FlowyError>;
class GridBlockService {
String gridId;
GridBlockMap blockMap = GridBlockMap();
late GridBlockListener _blockListener;
PublishNotifier<BlocksUpdateNotifierValue>? blocksUpdateNotifier = PublishNotifier();
GridBlockService({required this.gridId, required List<GridBlockOrder> blockOrders}) {
_loadGridBlocks(blockOrders);
_blockListener = GridBlockListener(gridId: gridId);
_blockListener.blockUpdateNotifier.addPublishListener((result) {
result.fold(
(blockOrder) => _loadGridBlocks(blockOrder),
(err) => Log.error(err),
);
});
_blockListener.start();
}
Future<void> stop() async {
await _blockListener.stop();
blocksUpdateNotifier?.dispose();
blocksUpdateNotifier = null;
}
void _loadGridBlocks(List<GridBlockOrder> 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;
}
blocksUpdateNotifier?.value = left(blockMap);
},
(err) => blocksUpdateNotifier?.value = right(err),
);
});
}
}
class GridBlockListener {
final String gridId;
PublishNotifier<Either<List<GridBlockOrder>, FlowyError>> blockUpdateNotifier = PublishNotifier(comparable: null);
GridNotificationListener? _listener;
GridBlockListener({required this.gridId});
void start() {
_listener = GridNotificationListener(
objectId: gridId,
handler: _handler,
);
}
void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
switch (ty) {
case GridNotification.DidUpdateBlock:
result.fold(
(payload) => blockUpdateNotifier.value = left([GridBlockOrder.fromBuffer(payload)]),
(error) => blockUpdateNotifier.value = right(error),
);
break;
default:
break;
}
}
Future<void> stop() async {
await _listener?.stop();
blockUpdateNotifier.dispose();
}
}

View File

@ -0,0 +1,43 @@
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
import 'package:flowy_infra/notifier.dart';
import 'dart:async';
import 'dart:typed_data';
import 'package:app_flowy/core/notification_helper.dart';
class GridListener {
final String gridId;
PublishNotifier<Either<List<GridBlockOrderChangeset>, FlowyError>> rowsUpdateNotifier =
PublishNotifier(comparable: null);
GridNotificationListener? _listener;
GridListener({required this.gridId});
void start() {
_listener = GridNotificationListener(
objectId: gridId,
handler: _handler,
);
}
void _handler(GridNotification ty, Either<Uint8List, FlowyError> result) {
switch (ty) {
case GridNotification.DidUpdateGridBlock:
result.fold(
(payload) => rowsUpdateNotifier.value = left([GridBlockOrderChangeset.fromBuffer(payload)]),
(error) => rowsUpdateNotifier.value = right(error),
);
break;
default:
break;
}
}
Future<void> stop() async {
await _listener?.stop();
rowsUpdateNotifier.dispose();
}
}

View File

@ -5,7 +5,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:dartz/dartz.dart';
class GridService {
Future<Either<Grid, FlowyError>> openGrid({required String gridId}) async {
Future<Either<Grid, FlowyError>> loadGrid({required String gridId}) async {
await FolderEventSetLatestView(ViewId(value: gridId)).send();
final payload = GridId(value: gridId);
@ -18,14 +18,6 @@ class GridService {
return GridEventCreateRow(payload).send();
}
Future<Either<RepeatedGridBlock, FlowyError>> getGridBlocks(
{required String gridId, required List<GridBlockOrder> blockOrders}) {
final payload = QueryGridBlocksPayload.create()
..gridId = gridId
..blockOrders.addAll(blockOrders);
return GridEventGetGridBlocks(payload).send();
}
Future<Either<RepeatedField, FlowyError>> getFields({required String gridId, required List<FieldOrder> fieldOrders}) {
final payload = QueryFieldPayload.create()
..gridId = gridId

View File

@ -7,7 +7,7 @@ export 'data.dart';
// Field
export 'field/field_service.dart';
export 'field/grid_header_bloc.dart';
export 'field/action_sheet_bloc.dart';
export 'field/field_action_sheet_bloc.dart';
export 'field/field_editor_bloc.dart';
export 'field/field_switch_bloc.dart';

View File

@ -0,0 +1,58 @@
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:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import 'package:dartz/dartz.dart';
part 'row_action_sheet_bloc.freezed.dart';
class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState> {
final RowService _rowService;
RowActionSheetBloc({required RowData rowData})
: _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
super(RowActionSheetState.initial(rowData)) {
on<RowActionSheetEvent>(
(event, emit) async {
await event.map(
deleteRow: (_DeleteRow value) async {
final result = await _rowService.deleteRow();
logResult(result);
},
duplicateRow: (_DuplicateRow value) async {
final result = await _rowService.duplicateRow();
logResult(result);
},
);
},
);
}
@override
Future<void> close() async {
return super.close();
}
void logResult(Either<Unit, FlowyError> result) {
result.fold((l) => null, (err) => Log.error(err));
}
}
@freezed
class RowActionSheetEvent with _$RowActionSheetEvent {
const factory RowActionSheetEvent.duplicateRow() = _DuplicateRow;
const factory RowActionSheetEvent.deleteRow() = _DeleteRow;
}
@freezed
class RowActionSheetState with _$RowActionSheetState {
const factory RowActionSheetState({
required RowData rowData,
}) = _RowActionSheetState;
factory RowActionSheetState.initial(RowData rowData) => RowActionSheetState(
rowData: rowData,
);
}

View File

@ -1,7 +1,6 @@
import 'dart:collection';
import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart';
import 'package:app_flowy/workspace/application/grid/grid_bloc.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -16,19 +15,14 @@ part 'row_bloc.freezed.dart';
typedef CellDataMap = LinkedHashMap<String, CellData>;
class RowBloc extends Bloc<RowEvent, RowState> {
final RowService rowService;
final RowListener rowlistener;
final GridFieldsListener fieldListener;
final RowService _rowService;
final RowListener _rowlistener;
final GridFieldsListener _fieldListener;
RowBloc({required RowData rowData, required this.rowlistener})
: rowService = RowService(
gridId: rowData.gridId,
blockId: rowData.blockId,
rowId: rowData.rowId,
),
fieldListener = GridFieldsListener(
gridId: rowData.gridId,
),
RowBloc({required RowData rowData})
: _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
_fieldListener = GridFieldsListener(gridId: rowData.gridId),
_rowlistener = RowListener(rowId: rowData.rowId),
super(RowState.initial(rowData)) {
on<RowEvent>(
(event, emit) async {
@ -38,7 +32,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
await _loadRow(emit);
},
createRow: (_CreateRow value) {
rowService.createRow();
_rowService.createRow();
},
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) async {
await _handleFieldUpdate(emit, value);
@ -52,7 +46,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
}
void _handleRowUpdate(_DidUpdateRow value, Emitter<RowState> emit) {
final CellDataMap cellDataMap = _makeCellDatas(value.row, state.fields);
final CellDataMap cellDataMap = _makeCellDatas(value.row, state.rowData.fields);
emit(state.copyWith(
row: Future(() => Some(value.row)),
cellDataMap: Some(cellDataMap),
@ -67,39 +61,39 @@ class RowBloc extends Bloc<RowEvent, RowState> {
);
emit(state.copyWith(
fields: value.fields,
rowData: state.rowData.copyWith(fields: value.fields),
cellDataMap: Some(cellDataMap),
));
}
@override
Future<void> close() async {
await rowlistener.stop();
await fieldListener.stop();
await _rowlistener.stop();
await _fieldListener.stop();
return super.close();
}
Future<void> _startListening() async {
rowlistener.updateRowNotifier.addPublishListener((result) {
_rowlistener.updateRowNotifier.addPublishListener((result) {
result.fold(
(row) => add(RowEvent.didUpdateRow(row)),
(err) => Log.error(err),
);
});
fieldListener.updateFieldsNotifier.addPublishListener((result) {
_fieldListener.updateFieldsNotifier.addPublishListener((result) {
result.fold(
(fields) => add(RowEvent.didReceiveFieldUpdate(fields)),
(err) => Log.error(err),
);
});
rowlistener.start();
fieldListener.start();
_rowlistener.start();
_fieldListener.start();
}
Future<void> _loadRow(Emitter<RowState> emit) async {
rowService.getRow().then((result) {
_rowService.getRow().then((result) {
return result.fold(
(row) => add(RowEvent.didUpdateRow(row)),
(err) => Log.error(err),
@ -113,7 +107,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
if (field.visibility) {
map[field.id] = CellData(
rowId: row.id,
gridId: rowService.gridId,
gridId: _rowService.gridId,
cell: row.cellByFieldId[field.id],
field: field,
);
@ -134,17 +128,13 @@ class RowEvent with _$RowEvent {
@freezed
class RowState with _$RowState {
const factory RowState({
required String rowId,
required double rowHeight,
required List<Field> fields,
required RowData rowData,
required Future<Option<Row>> row,
required Option<CellDataMap> cellDataMap,
}) = _RowState;
factory RowState.initial(RowData data) => RowState(
rowId: data.rowId,
rowHeight: data.height,
fields: data.fields,
factory RowState.initial(RowData rowData) => RowState(
rowData: rowData,
row: Future(() => none()),
cellDataMap: none(),
);

View File

@ -1,5 +1,4 @@
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';
@ -11,9 +10,8 @@ part 'row_service.freezed.dart';
class RowService {
final String gridId;
final String rowId;
final String blockId;
RowService({required this.gridId, required this.rowId, required this.blockId});
RowService({required this.gridId, required this.rowId});
Future<Either<Row, FlowyError>> createRow() {
CreateRowPayload payload = CreateRowPayload.create()
@ -30,6 +28,22 @@ class RowService {
return GridEventGetRow(payload).send();
}
Future<Either<Unit, FlowyError>> deleteRow() {
final payload = RowIdentifierPayload.create()
..gridId = gridId
..rowId = rowId;
return GridEventDeleteRow(payload).send();
}
Future<Either<Unit, FlowyError>> duplicateRow() {
final payload = RowIdentifierPayload.create()
..gridId = gridId
..rowId = rowId;
return GridEventDuplicateRow(payload).send();
}
}
@freezed
@ -41,3 +55,22 @@ class CellData with _$CellData {
Cell? cell,
}) = _CellData;
}
@freezed
class RowData with _$RowData {
const factory RowData({
required String gridId,
required String rowId,
required List<Field> fields,
required double height,
}) = _RowData;
factory RowData.fromBlockRow(String gridId, RowOrder row, List<Field> fields) {
return RowData(
gridId: gridId,
rowId: row.rowId,
fields: fields,
height: row.height.toDouble(),
);
}
}

View File

@ -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_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';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scrollview.dart';
@ -72,6 +73,7 @@ class FlowyGrid extends StatefulWidget {
class _FlowyGridState extends State<FlowyGrid> {
final _scrollController = GridScrollController();
// final _key = GlobalKey<SliverAnimatedListState>();
@override
void dispose() {
@ -90,6 +92,7 @@ class _FlowyGridState extends State<FlowyGrid> {
return const Center(child: CircularProgressIndicator.adaptive());
}
// _key.currentState.insertItem(index)
final child = BlocBuilder<GridBloc, GridState>(
builder: (context, state) {
return SizedBox(
@ -102,7 +105,7 @@ class _FlowyGridState extends State<FlowyGrid> {
slivers: [
_renderToolbar(gridId),
GridHeader(gridId: gridId, fields: List.from(state.fields)),
_renderRows(context),
_renderRows(gridId: gridId, context: context),
const GridFooter(),
],
),
@ -144,7 +147,7 @@ class _FlowyGridState extends State<FlowyGrid> {
);
}
Widget _renderRows(BuildContext context) {
Widget _renderRows({required String gridId, required BuildContext context}) {
return BlocBuilder<GridBloc, GridState>(
buildWhen: (previous, current) {
final rowChanged = previous.rows.length != current.rows.length;
@ -153,19 +156,36 @@ class _FlowyGridState extends State<FlowyGrid> {
},
builder: (context, state) {
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
final blockRow = context.read<GridBloc>().state.rows[index];
final fields = context.read<GridBloc>().state.fields;
final rowData = RowData.fromBlockRow(blockRow, fields);
return GridRowWidget(data: rowData, key: ValueKey(rowData.rowId));
},
childCount: context.read<GridBloc>().state.rows.length,
addRepaintBoundaries: true,
addAutomaticKeepAlives: true,
),
);
delegate: SliverChildBuilderDelegate(
(context, index) {
final blockRow = context.read<GridBloc>().state.rows[index];
final fields = context.read<GridBloc>().state.fields;
final rowData = RowData.fromBlockRow(gridId, blockRow, fields);
return GridRowWidget(data: rowData, key: ValueKey(rowData.rowId));
},
childCount: context.read<GridBloc>().state.rows.length,
addRepaintBoundaries: true,
addAutomaticKeepAlives: true,
));
// return SliverAnimatedList(
// key: _key,
// initialItemCount: context.read<GridBloc>().state.rows.length,
// itemBuilder: (BuildContext context, int index, Animation<double> animation) {
// final blockRow = context.read<GridBloc>().state.rows[index];
// final fields = context.read<GridBloc>().state.fields;
// final rowData = RowData.fromBlockRow(blockRow, fields);
// return _renderRow(rowData, animation);
// },
// );
},
);
}
// Widget _renderRow(RowData rowData, Animation<double> animation) {
// return SizeTransition(
// sizeFactor: animation,
// child: GridRowWidget(data: rowData, key: ValueKey(rowData.rowId)),
// );
// }
}

View File

@ -6,7 +6,7 @@ class GridSize {
static double get scrollBarSize => 12 * scale;
static double get headerHeight => 40 * scale;
static double get footerHeight => 40 * scale;
static double get leadingHeaderPadding => 30 * scale;
static double get leadingHeaderPadding => 50 * scale;
static double get trailHeaderPadding => 140 * scale;
static double get headerContainerPadding => 0 * scale;
static double get cellHPadding => 10 * scale;

View File

@ -1,6 +1,3 @@
import 'dart:collection';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
@ -8,7 +5,6 @@ import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:textfield_tags/textfield_tags.dart';
extension SelectOptionColorExtension on SelectOptionColor {
Color make(BuildContext context) {
@ -63,98 +59,6 @@ extension SelectOptionColorExtension on SelectOptionColor {
}
}
class SelectOptionTextField extends StatelessWidget {
final FocusNode _focusNode;
final TextEditingController _controller;
final TextfieldTagsController tagController;
final List<SelectOption> options;
final LinkedHashMap<String, SelectOption> selectedOptionMap;
final double distanceToText;
final Function(String) onNewTag;
SelectOptionTextField({
required this.options,
required this.selectedOptionMap,
required this.distanceToText,
required this.tagController,
required this.onNewTag,
TextEditingController? controller,
FocusNode? focusNode,
Key? key,
}) : _controller = controller ?? TextEditingController(),
_focusNode = focusNode ?? FocusNode(),
super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return TextFieldTags(
textEditingController: _controller,
textfieldTagsController: tagController,
initialTags: selectedOptionMap.keys.toList(),
focusNode: _focusNode,
textSeparators: const [' ', ','],
inputfieldBuilder: (BuildContext context, editController, focusNode, error, onChanged, onSubmitted) {
return ((context, sc, tags, onTagDelegate) {
tags.retainWhere((name) {
return options.where((option) => option.name == name).isEmpty;
});
if (tags.isNotEmpty) {
assert(tags.length == 1);
onNewTag(tags.first);
}
return TextField(
autofocus: true,
controller: editController,
focusNode: focusNode,
onChanged: onChanged,
onSubmitted: onSubmitted,
maxLines: 1,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: theme.main1, width: 1.0),
borderRadius: Corners.s10Border,
),
isDense: true,
prefixIcon: _renderTags(sc),
hintText: LocaleKeys.grid_selectOption_searchOption.tr(),
prefixIconConstraints: BoxConstraints(maxWidth: distanceToText),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: theme.main1,
width: 1.0,
),
borderRadius: Corners.s10Border,
),
),
);
});
},
);
}
Widget? _renderTags(ScrollController sc) {
if (selectedOptionMap.isEmpty) {
return null;
}
final children = selectedOptionMap.values.map((option) => SelectOptionTag(option: option)).toList();
return Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
controller: sc,
scrollDirection: Axis.horizontal,
child: Row(children: children),
),
);
}
}
class SelectOptionTag extends StatelessWidget {
final SelectOption option;
final bool isSelected;

View File

@ -1,5 +1,4 @@
import 'dart:collection';
import 'package:app_flowy/workspace/application/grid/cell_bloc/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';
@ -21,6 +20,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:textfield_tags/textfield_tags.dart';
import 'extension.dart';
import 'text_field.dart';
const double _editorPannelWidth = 300;
@ -135,8 +135,7 @@ class _TextField extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocConsumer<SelectOptionEditorBloc, SelectOptionEditorState>(
listener: (context, state) {},
return BlocBuilder<SelectOptionEditorBloc, SelectOptionEditorState>(
builder: (context, state) {
final optionMap = LinkedHashMap<String, SelectOption>.fromIterable(state.selectedOptions,
key: (option) => option.name, value: (option) => option);

View File

@ -0,0 +1,101 @@
import 'dart:collection';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:textfield_tags/textfield_tags.dart';
import 'extension.dart';
class SelectOptionTextField extends StatelessWidget {
final FocusNode _focusNode;
final TextEditingController _controller;
final TextfieldTagsController tagController;
final List<SelectOption> options;
final LinkedHashMap<String, SelectOption> selectedOptionMap;
final double distanceToText;
final Function(String) onNewTag;
SelectOptionTextField({
required this.options,
required this.selectedOptionMap,
required this.distanceToText,
required this.tagController,
required this.onNewTag,
TextEditingController? controller,
FocusNode? focusNode,
Key? key,
}) : _controller = controller ?? TextEditingController(),
_focusNode = focusNode ?? FocusNode(),
super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return TextFieldTags(
textEditingController: _controller,
textfieldTagsController: tagController,
initialTags: selectedOptionMap.keys.toList(),
focusNode: _focusNode,
textSeparators: const [' ', ','],
inputfieldBuilder: (BuildContext context, editController, focusNode, error, onChanged, onSubmitted) {
return ((context, sc, tags, onTagDelegate) {
return TextField(
autofocus: true,
controller: editController,
focusNode: focusNode,
onChanged: onChanged,
onSubmitted: (text) {
if (onSubmitted != null) {
onSubmitted(text);
}
if (text.isNotEmpty) {
onNewTag(text);
}
},
maxLines: 1,
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: theme.main1, width: 1.0),
borderRadius: Corners.s10Border,
),
isDense: true,
prefixIcon: _renderTags(sc),
hintText: LocaleKeys.grid_selectOption_searchOption.tr(),
prefixIconConstraints: BoxConstraints(maxWidth: distanceToText),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: theme.main1, width: 1.0),
borderRadius: Corners.s10Border,
),
),
);
});
},
);
}
Widget? _renderTags(ScrollController sc) {
if (selectedOptionMap.isEmpty) {
return null;
}
final children = selectedOptionMap.values.map((option) => SelectOptionTag(option: option)).toList();
return Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
controller: sc,
scrollDirection: Axis.horizontal,
child: Row(children: children),
),
);
}
}

View File

@ -23,7 +23,7 @@ class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate
child: this,
constraints: BoxConstraints.loose(const Size(240, 200)),
),
identifier: identifier(),
identifier: GridFieldCellActionSheet.identifier(),
anchorContext: overlayContext,
anchorDirection: AnchorDirection.bottomWithLeftAligned,
delegate: this,
@ -68,7 +68,7 @@ class _EditFieldButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return BlocBuilder<FieldActionSheetBloc, ActionSheetState>(
return BlocBuilder<FieldActionSheetBloc, FieldActionSheetState>(
builder: (context, state) {
return SizedBox(
height: GridSize.typeOptionItemHeight,
@ -100,16 +100,6 @@ class _FieldOperationList extends StatelessWidget {
)
.toList();
return FieldOperationList(actions: actions);
}
}
class FieldOperationList extends StatelessWidget {
final List<FieldActionCell> actions;
const FieldOperationList({required this.actions, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return GridView(
// https://api.flutter.dev/flutter/widgets/AnimatedList/shrinkWrap.html
shrinkWrap: true,
@ -182,13 +172,13 @@ extension _FieldActionExtension on FieldAction {
void run(BuildContext context) {
switch (this) {
case FieldAction.hide:
context.read<FieldActionSheetBloc>().add(const ActionSheetEvent.hideField());
context.read<FieldActionSheetBloc>().add(const FieldActionSheetEvent.hideField());
break;
case FieldAction.duplicate:
context.read<FieldActionSheetBloc>().add(const ActionSheetEvent.duplicateField());
context.read<FieldActionSheetBloc>().add(const FieldActionSheetEvent.duplicateField());
break;
case FieldAction.delete:
context.read<FieldActionSheetBloc>().add(const ActionSheetEvent.deleteField());
context.read<FieldActionSheetBloc>().add(const FieldActionSheetEvent.deleteField());
break;
}
}

View File

@ -9,6 +9,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'row_action_sheet.dart';
class GridRowWidget extends StatefulWidget {
final RowData data;
const GridRowWidget({required this.data, Key? key}) : super(key: key);
@ -39,10 +41,10 @@ class _GridRowWidgetState extends State<GridRowWidget> {
onEnter: (p) => _rowStateNotifier.onEnter = true,
onExit: (p) => _rowStateNotifier.onEnter = false,
child: BlocBuilder<RowBloc, RowState>(
buildWhen: (p, c) => p.rowHeight != c.rowHeight,
buildWhen: (p, c) => p.rowData.height != c.rowData.height,
builder: (context, state) {
return SizedBox(
height: _rowBloc.state.rowHeight,
height: _rowBloc.state.rowData.height,
child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: const [
@ -83,7 +85,8 @@ class _RowLeading extends StatelessWidget {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
AppendRowButton(),
_InsertRowButton(),
_DeleteRowButton(),
],
);
}
@ -98,15 +101,16 @@ class _RowTrailing extends StatelessWidget {
}
}
class AppendRowButton extends StatelessWidget {
const AppendRowButton({Key? key}) : super(key: key);
class _InsertRowButton extends StatelessWidget {
const _InsertRowButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return FlowyIconButton(
hoverColor: theme.hover,
width: 22,
width: 20,
height: 30,
onPressed: () => context.read<RowBloc>().add(const RowEvent.createRow()),
iconPadding: const EdgeInsets.all(3),
icon: svgWidget("home/add"),
@ -114,6 +118,25 @@ class AppendRowButton extends StatelessWidget {
}
}
class _DeleteRowButton extends StatelessWidget {
const _DeleteRowButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return FlowyIconButton(
hoverColor: theme.hover,
width: 20,
height: 30,
onPressed: () => GridRowActionSheet(
rowData: context.read<RowBloc>().state.rowData,
).show(context),
iconPadding: const EdgeInsets.all(3),
icon: svgWidget("editor/details"),
);
}
}
class _RowCells extends StatelessWidget {
const _RowCells({Key? key}) : super(key: key);

View File

@ -0,0 +1,148 @@
import 'package:app_flowy/workspace/application/grid/row/row_action_sheet_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:easy_localization/easy_localization.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
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/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class GridRowActionSheet extends StatelessWidget {
final RowData rowData;
const GridRowActionSheet({required this.rowData, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => RowActionSheetBloc(rowData: rowData),
child: BlocBuilder<RowActionSheetBloc, RowActionSheetState>(
builder: (context, state) {
final cells = _RowAction.values
.map(
(action) => _RowActionCell(
action: action,
onDismissed: () => remove(context),
),
)
.toList();
//
final list = ListView.separated(
shrinkWrap: true,
controller: ScrollController(),
itemCount: cells.length,
separatorBuilder: (context, index) {
return VSpace(GridSize.typeOptionSeparatorHeight);
},
physics: StyledScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return cells[index];
},
);
return list;
},
),
);
}
void show(BuildContext overlayContext) {
FlowyOverlay.of(overlayContext).insertWithAnchor(
widget: OverlayContainer(
child: this,
constraints: BoxConstraints.loose(const Size(140, 200)),
),
identifier: GridRowActionSheet.identifier(),
anchorContext: overlayContext,
anchorDirection: AnchorDirection.leftWithCenterAligned,
);
}
void remove(BuildContext overlayContext) {
FlowyOverlay.of(overlayContext).remove(GridRowActionSheet.identifier());
}
static String identifier() {
return (GridRowActionSheet).toString();
}
}
class _RowActionCell extends StatelessWidget {
final _RowAction action;
final VoidCallback onDismissed;
const _RowActionCell({required this.action, required this.onDismissed, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return SizedBox(
height: GridSize.typeOptionItemHeight,
child: FlowyButton(
text: FlowyText.medium(
action.title(),
fontSize: 12,
color: action.enable() ? theme.textColor : theme.shader3,
),
hoverColor: theme.hover,
onTap: () {
if (action.enable()) {
action.performAction(context);
}
onDismissed();
},
leftIcon: svgWidget(action.iconName(), color: theme.iconColor),
),
);
}
}
enum _RowAction {
delete,
duplicate,
}
extension _RowActionExtension on _RowAction {
String iconName() {
switch (this) {
case _RowAction.duplicate:
return 'grid/duplicate';
case _RowAction.delete:
return 'grid/delete';
}
}
String title() {
switch (this) {
case _RowAction.duplicate:
return LocaleKeys.grid_row_duplicate.tr();
case _RowAction.delete:
return LocaleKeys.grid_row_delete.tr();
}
}
bool enable() {
switch (this) {
case _RowAction.duplicate:
return false;
case _RowAction.delete:
return true;
}
}
void performAction(BuildContext context) {
switch (this) {
case _RowAction.duplicate:
context.read<RowActionSheetBloc>().add(const RowActionSheetEvent.duplicateRow());
break;
case _RowAction.delete:
context.read<RowActionSheetBloc>().add(const RowActionSheetEvent.deleteRow());
break;
}
}
}

View File

@ -239,6 +239,40 @@ class GridEventGetRow {
}
}
class GridEventDeleteRow {
RowIdentifierPayload request;
GridEventDeleteRow(this.request);
Future<Either<Unit, FlowyError>> send() {
final request = FFIRequest.create()
..event = GridEvent.DeleteRow.toString()
..payload = requestToBytes(this.request);
return Dispatch.asyncRequest(request)
.then((bytesResult) => bytesResult.fold(
(bytes) => left(unit),
(errBytes) => right(FlowyError.fromBuffer(errBytes)),
));
}
}
class GridEventDuplicateRow {
RowIdentifierPayload request;
GridEventDuplicateRow(this.request);
Future<Either<Unit, FlowyError>> send() {
final request = FFIRequest.create()
..event = GridEvent.DuplicateRow.toString()
..payload = requestToBytes(this.request);
return Dispatch.asyncRequest(request)
.then((bytesResult) => bytesResult.fold(
(bytes) => left(unit),
(errBytes) => right(FlowyError.fromBuffer(errBytes)),
));
}
}
class GridEventGetCell {
CellIdentifierPayload request;
GridEventGetCell(this.request);

View File

@ -803,17 +803,22 @@ class RepeatedGridBlock extends $pb.GeneratedMessage {
class GridBlockOrder extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlockOrder', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..pc<RowOrder>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrders', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
..hasRequiredFields = false
;
GridBlockOrder._() : super();
factory GridBlockOrder({
$core.String? blockId,
$core.Iterable<RowOrder>? rowOrders,
}) {
final _result = create();
if (blockId != null) {
_result.blockId = blockId;
}
if (rowOrders != null) {
_result.rowOrders.addAll(rowOrders);
}
return _result;
}
factory GridBlockOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
@ -845,6 +850,156 @@ class GridBlockOrder extends $pb.GeneratedMessage {
$core.bool hasBlockId() => $_has(0);
@$pb.TagNumber(1)
void clearBlockId() => clearField(1);
@$pb.TagNumber(2)
$core.List<RowOrder> 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)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..pc<IndexRowOrder>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertedRows', $pb.PbFieldType.PM, subBuilder: IndexRowOrder.create)
..pc<RowOrder>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deletedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
..pc<RowOrder>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'updatedRows', $pb.PbFieldType.PM, subBuilder: RowOrder.create)
..hasRequiredFields = false
;
GridBlockOrderChangeset._() : super();
factory GridBlockOrderChangeset({
$core.String? blockId,
$core.Iterable<IndexRowOrder>? insertedRows,
$core.Iterable<RowOrder>? deletedRows,
$core.Iterable<RowOrder>? 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 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);
@$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);
@$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
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static GridBlockOrderChangeset create() => GridBlockOrderChangeset._();
GridBlockOrderChangeset createEmptyInstance() => create();
static $pb.PbList<GridBlockOrderChangeset> createRepeated() => $pb.PbList<GridBlockOrderChangeset>();
@$core.pragma('dart2js:noInline')
static GridBlockOrderChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GridBlockOrderChangeset>(create);
static GridBlockOrderChangeset? _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<IndexRowOrder> get insertedRows => $_getList(1);
@$pb.TagNumber(3)
$core.List<RowOrder> get deletedRows => $_getList(2);
@$pb.TagNumber(4)
$core.List<RowOrder> get updatedRows => $_getList(3);
}
enum IndexRowOrder_OneOfIndex {
index_,
notSet
}
class IndexRowOrder extends $pb.GeneratedMessage {
static const $core.Map<$core.int, IndexRowOrder_OneOfIndex> _IndexRowOrder_OneOfIndexByTag = {
2 : IndexRowOrder_OneOfIndex.index_,
0 : IndexRowOrder_OneOfIndex.notSet
};
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'IndexRowOrder', createEmptyInstance: create)
..oo(0, [2])
..aOM<RowOrder>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowOrder', subBuilder: RowOrder.create)
..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'index', $pb.PbFieldType.O3)
..hasRequiredFields = false
;
IndexRowOrder._() : super();
factory IndexRowOrder({
RowOrder? rowOrder,
$core.int? index,
}) {
final _result = create();
if (rowOrder != null) {
_result.rowOrder = rowOrder;
}
if (index != null) {
_result.index = index;
}
return _result;
}
factory IndexRowOrder.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory IndexRowOrder.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')
IndexRowOrder clone() => IndexRowOrder()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
IndexRowOrder copyWith(void Function(IndexRowOrder) updates) => super.copyWith((message) => updates(message as IndexRowOrder)) as IndexRowOrder; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static IndexRowOrder create() => IndexRowOrder._();
IndexRowOrder createEmptyInstance() => create();
static $pb.PbList<IndexRowOrder> createRepeated() => $pb.PbList<IndexRowOrder>();
@$core.pragma('dart2js:noInline')
static IndexRowOrder getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<IndexRowOrder>(create);
static IndexRowOrder? _defaultInstance;
IndexRowOrder_OneOfIndex whichOneOfIndex() => _IndexRowOrder_OneOfIndexByTag[$_whichOneof(0)]!;
void clearOneOfIndex() => clearField($_whichOneof(0));
@$pb.TagNumber(1)
RowOrder get rowOrder => $_getN(0);
@$pb.TagNumber(1)
set rowOrder(RowOrder v) { setField(1, v); }
@$pb.TagNumber(1)
$core.bool hasRowOrder() => $_has(0);
@$pb.TagNumber(1)
void clearRowOrder() => clearField(1);
@$pb.TagNumber(1)
RowOrder ensureRowOrder() => $_ensure(0);
@$pb.TagNumber(2)
$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);
}
class GridBlock extends $pb.GeneratedMessage {

View File

@ -165,11 +165,39 @@ const GridBlockOrder$json = const {
'1': 'GridBlockOrder',
'2': const [
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
const {'1': 'row_orders', '3': 2, '4': 3, '5': 11, '6': '.RowOrder', '10': 'rowOrders'},
],
};
/// Descriptor for `GridBlockOrder`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridBlockOrderDescriptor = $convert.base64Decode('Cg5HcmlkQmxvY2tPcmRlchIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZA==');
final $typed_data.Uint8List gridBlockOrderDescriptor = $convert.base64Decode('Cg5HcmlkQmxvY2tPcmRlchIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIoCgpyb3dfb3JkZXJzGAIgAygLMgkuUm93T3JkZXJSCXJvd09yZGVycw==');
@$core.Deprecated('Use gridBlockOrderChangesetDescriptor instead')
const GridBlockOrderChangeset$json = const {
'1': 'GridBlockOrderChangeset',
'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 `GridBlockOrderChangeset`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridBlockOrderChangesetDescriptor = $convert.base64Decode('ChdHcmlkQmxvY2tPcmRlckNoYW5nZXNldBIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIzCg1pbnNlcnRlZF9yb3dzGAIgAygLMg4uSW5kZXhSb3dPcmRlclIMaW5zZXJ0ZWRSb3dzEiwKDGRlbGV0ZWRfcm93cxgDIAMoCzIJLlJvd09yZGVyUgtkZWxldGVkUm93cxIsCgx1cGRhdGVkX3Jvd3MYBCADKAsyCS5Sb3dPcmRlclILdXBkYXRlZFJvd3M=');
@$core.Deprecated('Use indexRowOrderDescriptor instead')
const IndexRowOrder$json = const {
'1': 'IndexRowOrder',
'2': const [
const {'1': 'row_order', '3': 1, '4': 1, '5': 11, '6': '.RowOrder', '10': 'rowOrder'},
const {'1': 'index', '3': 2, '4': 1, '5': 5, '9': 0, '10': 'index'},
],
'8': const [
const {'1': 'one_of_index'},
],
};
/// Descriptor for `IndexRowOrder`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List indexRowOrderDescriptor = $convert.base64Decode('Cg1JbmRleFJvd09yZGVyEiYKCXJvd19vcmRlchgBIAEoCzIJLlJvd09yZGVyUghyb3dPcmRlchIWCgVpbmRleBgCIAEoBUgAUgVpbmRleEIOCgxvbmVfb2ZfaW5kZXg=');
@$core.Deprecated('Use gridBlockDescriptor instead')
const GridBlock$json = const {
'1': 'GridBlock',

View File

@ -17,7 +17,7 @@ class GridMeta extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridMeta', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId')
..pc<FieldMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fields', $pb.PbFieldType.PM, subBuilder: FieldMeta.create)
..pc<GridBlockMeta>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockMetas', $pb.PbFieldType.PM, subBuilder: GridBlockMeta.create)
..pc<GridBlockMeta>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blocks', $pb.PbFieldType.PM, subBuilder: GridBlockMeta.create)
..hasRequiredFields = false
;
@ -25,7 +25,7 @@ class GridMeta extends $pb.GeneratedMessage {
factory GridMeta({
$core.String? gridId,
$core.Iterable<FieldMeta>? fields,
$core.Iterable<GridBlockMeta>? blockMetas,
$core.Iterable<GridBlockMeta>? blocks,
}) {
final _result = create();
if (gridId != null) {
@ -34,8 +34,8 @@ class GridMeta extends $pb.GeneratedMessage {
if (fields != null) {
_result.fields.addAll(fields);
}
if (blockMetas != null) {
_result.blockMetas.addAll(blockMetas);
if (blocks != null) {
_result.blocks.addAll(blocks);
}
return _result;
}
@ -73,7 +73,7 @@ class GridMeta extends $pb.GeneratedMessage {
$core.List<FieldMeta> get fields => $_getList(1);
@$pb.TagNumber(3)
$core.List<GridBlockMeta> get blockMetas => $_getList(2);
$core.List<GridBlockMeta> get blocks => $_getList(2);
}
class GridBlockMeta extends $pb.GeneratedMessage {
@ -154,21 +154,21 @@ class GridBlockMeta extends $pb.GeneratedMessage {
class GridBlockMetaData extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'GridBlockMetaData', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockId')
..pc<RowMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowMetas', $pb.PbFieldType.PM, subBuilder: RowMeta.create)
..pc<RowMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rows', $pb.PbFieldType.PM, subBuilder: RowMeta.create)
..hasRequiredFields = false
;
GridBlockMetaData._() : super();
factory GridBlockMetaData({
$core.String? blockId,
$core.Iterable<RowMeta>? rowMetas,
$core.Iterable<RowMeta>? rows,
}) {
final _result = create();
if (blockId != null) {
_result.blockId = blockId;
}
if (rowMetas != null) {
_result.rowMetas.addAll(rowMetas);
if (rows != null) {
_result.rows.addAll(rows);
}
return _result;
}
@ -203,7 +203,7 @@ class GridBlockMetaData extends $pb.GeneratedMessage {
void clearBlockId() => clearField(1);
@$pb.TagNumber(2)
$core.List<RowMeta> get rowMetas => $_getList(1);
$core.List<RowMeta> get rows => $_getList(1);
}
class FieldMeta extends $pb.GeneratedMessage {
@ -1014,7 +1014,7 @@ class CellMetaChangeset extends $pb.GeneratedMessage {
class BuildGridContext extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'BuildGridContext', createEmptyInstance: create)
..pc<FieldMeta>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldMetas', $pb.PbFieldType.PM, subBuilder: FieldMeta.create)
..aOM<GridBlockMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockMetas', subBuilder: GridBlockMeta.create)
..aOM<GridBlockMeta>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockMeta', subBuilder: GridBlockMeta.create)
..aOM<GridBlockMetaData>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'blockMetaData', subBuilder: GridBlockMetaData.create)
..hasRequiredFields = false
;
@ -1022,15 +1022,15 @@ class BuildGridContext extends $pb.GeneratedMessage {
BuildGridContext._() : super();
factory BuildGridContext({
$core.Iterable<FieldMeta>? fieldMetas,
GridBlockMeta? blockMetas,
GridBlockMeta? blockMeta,
GridBlockMetaData? blockMetaData,
}) {
final _result = create();
if (fieldMetas != null) {
_result.fieldMetas.addAll(fieldMetas);
}
if (blockMetas != null) {
_result.blockMetas = blockMetas;
if (blockMeta != null) {
_result.blockMeta = blockMeta;
}
if (blockMetaData != null) {
_result.blockMetaData = blockMetaData;
@ -1062,15 +1062,15 @@ class BuildGridContext extends $pb.GeneratedMessage {
$core.List<FieldMeta> get fieldMetas => $_getList(0);
@$pb.TagNumber(2)
GridBlockMeta get blockMetas => $_getN(1);
GridBlockMeta get blockMeta => $_getN(1);
@$pb.TagNumber(2)
set blockMetas(GridBlockMeta v) { setField(2, v); }
set blockMeta(GridBlockMeta v) { setField(2, v); }
@$pb.TagNumber(2)
$core.bool hasBlockMetas() => $_has(1);
$core.bool hasBlockMeta() => $_has(1);
@$pb.TagNumber(2)
void clearBlockMetas() => clearField(2);
void clearBlockMeta() => clearField(2);
@$pb.TagNumber(2)
GridBlockMeta ensureBlockMetas() => $_ensure(1);
GridBlockMeta ensureBlockMeta() => $_ensure(1);
@$pb.TagNumber(3)
GridBlockMetaData get blockMetaData => $_getN(2);

View File

@ -29,12 +29,12 @@ const GridMeta$json = const {
'2': const [
const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'},
const {'1': 'fields', '3': 2, '4': 3, '5': 11, '6': '.FieldMeta', '10': 'fields'},
const {'1': 'block_metas', '3': 3, '4': 3, '5': 11, '6': '.GridBlockMeta', '10': 'blockMetas'},
const {'1': 'blocks', '3': 3, '4': 3, '5': 11, '6': '.GridBlockMeta', '10': 'blocks'},
],
};
/// Descriptor for `GridMeta`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridMetaDescriptor = $convert.base64Decode('CghHcmlkTWV0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSIgoGZmllbGRzGAIgAygLMgouRmllbGRNZXRhUgZmaWVsZHMSLwoLYmxvY2tfbWV0YXMYAyADKAsyDi5HcmlkQmxvY2tNZXRhUgpibG9ja01ldGFz');
final $typed_data.Uint8List gridMetaDescriptor = $convert.base64Decode('CghHcmlkTWV0YRIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSIgoGZmllbGRzGAIgAygLMgouRmllbGRNZXRhUgZmaWVsZHMSJgoGYmxvY2tzGAMgAygLMg4uR3JpZEJsb2NrTWV0YVIGYmxvY2tz');
@$core.Deprecated('Use gridBlockMetaDescriptor instead')
const GridBlockMeta$json = const {
'1': 'GridBlockMeta',
@ -52,12 +52,12 @@ const GridBlockMetaData$json = const {
'1': 'GridBlockMetaData',
'2': const [
const {'1': 'block_id', '3': 1, '4': 1, '5': 9, '10': 'blockId'},
const {'1': 'row_metas', '3': 2, '4': 3, '5': 11, '6': '.RowMeta', '10': 'rowMetas'},
const {'1': 'rows', '3': 2, '4': 3, '5': 11, '6': '.RowMeta', '10': 'rows'},
],
};
/// Descriptor for `GridBlockMetaData`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List gridBlockMetaDataDescriptor = $convert.base64Decode('ChFHcmlkQmxvY2tNZXRhRGF0YRIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIlCglyb3dfbWV0YXMYAiADKAsyCC5Sb3dNZXRhUghyb3dNZXRhcw==');
final $typed_data.Uint8List gridBlockMetaDataDescriptor = $convert.base64Decode('ChFHcmlkQmxvY2tNZXRhRGF0YRIZCghibG9ja19pZBgBIAEoCVIHYmxvY2tJZBIcCgRyb3dzGAIgAygLMgguUm93TWV0YVIEcm93cw==');
@$core.Deprecated('Use fieldMetaDescriptor instead')
const FieldMeta$json = const {
'1': 'FieldMeta',
@ -208,10 +208,10 @@ const BuildGridContext$json = const {
'1': 'BuildGridContext',
'2': const [
const {'1': 'field_metas', '3': 1, '4': 3, '5': 11, '6': '.FieldMeta', '10': 'fieldMetas'},
const {'1': 'block_metas', '3': 2, '4': 1, '5': 11, '6': '.GridBlockMeta', '10': 'blockMetas'},
const {'1': 'block_meta', '3': 2, '4': 1, '5': 11, '6': '.GridBlockMeta', '10': 'blockMeta'},
const {'1': 'block_meta_data', '3': 3, '4': 1, '5': 11, '6': '.GridBlockMetaData', '10': 'blockMetaData'},
],
};
/// Descriptor for `BuildGridContext`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List buildGridContextDescriptor = $convert.base64Decode('ChBCdWlsZEdyaWRDb250ZXh0EisKC2ZpZWxkX21ldGFzGAEgAygLMgouRmllbGRNZXRhUgpmaWVsZE1ldGFzEi8KC2Jsb2NrX21ldGFzGAIgASgLMg4uR3JpZEJsb2NrTWV0YVIKYmxvY2tNZXRhcxI6Cg9ibG9ja19tZXRhX2RhdGEYAyABKAsyEi5HcmlkQmxvY2tNZXRhRGF0YVINYmxvY2tNZXRhRGF0YQ==');
final $typed_data.Uint8List buildGridContextDescriptor = $convert.base64Decode('ChBCdWlsZEdyaWRDb250ZXh0EisKC2ZpZWxkX21ldGFzGAEgAygLMgouRmllbGRNZXRhUgpmaWVsZE1ldGFzEi0KCmJsb2NrX21ldGEYAiABKAsyDi5HcmlkQmxvY2tNZXRhUglibG9ja01ldGESOgoPYmxvY2tfbWV0YV9kYXRhGAMgASgLMhIuR3JpZEJsb2NrTWV0YURhdGFSDWJsb2NrTWV0YURhdGE=');

View File

@ -12,7 +12,7 @@ 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 DidUpdateBlock = GridNotification._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DidUpdateBlock');
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');
@ -21,7 +21,7 @@ class GridNotification extends $pb.ProtobufEnum {
static const $core.List<GridNotification> values = <GridNotification> [
Unknown,
DidCreateBlock,
DidUpdateBlock,
DidUpdateGridBlock,
DidUpdateRow,
DidUpdateCell,
DidUpdateGrid,

View File

@ -14,7 +14,7 @@ const GridNotification$json = const {
'2': const [
const {'1': 'Unknown', '2': 0},
const {'1': 'DidCreateBlock', '2': 11},
const {'1': 'DidUpdateBlock', '2': 20},
const {'1': 'DidUpdateGridBlock', '2': 20},
const {'1': 'DidUpdateRow', '2': 30},
const {'1': 'DidUpdateCell', '2': 31},
const {'1': 'DidUpdateGrid', '2': 40},
@ -23,4 +23,4 @@ const GridNotification$json = const {
};
/// Descriptor for `GridNotification`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhIKDkRpZFVwZGF0ZUJsb2NrEBQSEAoMRGlkVXBkYXRlUm93EB4SEQoNRGlkVXBkYXRlQ2VsbBAfEhEKDURpZFVwZGF0ZUdyaWQQKBISCg5EaWRVcGRhdGVGaWVsZBAp');
final $typed_data.Uint8List gridNotificationDescriptor = $convert.base64Decode('ChBHcmlkTm90aWZpY2F0aW9uEgsKB1Vua25vd24QABISCg5EaWRDcmVhdGVCbG9jaxALEhYKEkRpZFVwZGF0ZUdyaWRCbG9jaxAUEhAKDERpZFVwZGF0ZVJvdxAeEhEKDURpZFVwZGF0ZUNlbGwQHxIRCg1EaWRVcGRhdGVHcmlkECgSEgoORGlkVXBkYXRlRmllbGQQKQ==');

View File

@ -24,6 +24,8 @@ class GridEvent extends $pb.ProtobufEnum {
static const GridEvent ApplySelectOptionChangeset = GridEvent._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ApplySelectOptionChangeset');
static const GridEvent CreateRow = GridEvent._(50, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateRow');
static const GridEvent GetRow = GridEvent._(51, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetRow');
static const GridEvent DeleteRow = GridEvent._(52, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteRow');
static const GridEvent DuplicateRow = GridEvent._(53, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateRow');
static const GridEvent GetCell = GridEvent._(70, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetCell');
static const GridEvent UpdateCell = GridEvent._(71, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCell');
static const GridEvent ApplySelectOptionCellChangeset = GridEvent._(72, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ApplySelectOptionCellChangeset');
@ -43,6 +45,8 @@ class GridEvent extends $pb.ProtobufEnum {
ApplySelectOptionChangeset,
CreateRow,
GetRow,
DeleteRow,
DuplicateRow,
GetCell,
UpdateCell,
ApplySelectOptionCellChangeset,

View File

@ -26,6 +26,8 @@ const GridEvent$json = const {
const {'1': 'ApplySelectOptionChangeset', '2': 32},
const {'1': 'CreateRow', '2': 50},
const {'1': 'GetRow', '2': 51},
const {'1': 'DeleteRow', '2': 52},
const {'1': 'DuplicateRow', '2': 53},
const {'1': 'GetCell', '2': 70},
const {'1': 'UpdateCell', '2': 71},
const {'1': 'ApplySelectOptionCellChangeset', '2': 72},
@ -33,4 +35,4 @@ const GridEvent$json = const {
};
/// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtDcmVhdGVGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEQoNU3dpdGNoVG9GaWVsZBAOEhIKDkR1cGxpY2F0ZUZpZWxkEA8SFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAQEhMKD05ld1NlbGVjdE9wdGlvbhAeEhoKFkdldFNlbGVjdE9wdGlvbkNvbnRleHQQHxIeChpBcHBseVNlbGVjdE9wdGlvbkNoYW5nZXNldBAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSIgoeQXBwbHlTZWxlY3RPcHRpb25DZWxsQ2hhbmdlc2V0EEg=');
final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtDcmVhdGVGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEQoNU3dpdGNoVG9GaWVsZBAOEhIKDkR1cGxpY2F0ZUZpZWxkEA8SFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAQEhMKD05ld1NlbGVjdE9wdGlvbhAeEhoKFkdldFNlbGVjdE9wdGlvbkNvbnRleHQQHxIeChpBcHBseVNlbGVjdE9wdGlvbkNoYW5nZXNldBAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSIgoeQXBwbHlTZWxlY3RPcHRpb25DZWxsQ2hhbmdlc2V0EEg=');

View File

@ -6,7 +6,7 @@ const OBSERVABLE_CATEGORY: &str = "Grid";
pub enum GridNotification {
Unknown = 0,
DidCreateBlock = 11,
DidUpdateBlock = 20,
DidUpdateGridBlock = 20,
DidUpdateRow = 30,
DidUpdateCell = 31,
DidUpdateGrid = 40,

View File

@ -179,6 +179,28 @@ pub(crate) async fn get_row_handler(
}
}
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn delete_row_handler(
data: Data<RowIdentifierPayload>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: RowIdentifier = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.delete_row(&params.row_id).await?;
Ok(())
}
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn duplicate_row_handler(
data: Data<RowIdentifierPayload>,
manager: AppData<Arc<GridManager>>,
) -> Result<(), FlowyError> {
let params: RowIdentifier = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
let _ = editor.duplicate_row(&params.row_id).await?;
Ok(())
}
#[tracing::instrument(level = "debug", skip(data, manager), err)]
pub(crate) async fn create_row_handler(
data: Data<CreateRowPayload>,

View File

@ -20,6 +20,8 @@ pub fn create(grid_manager: Arc<GridManager>) -> Module {
// Row
.event(GridEvent::CreateRow, create_row_handler)
.event(GridEvent::GetRow, get_row_handler)
.event(GridEvent::DeleteRow, delete_row_handler)
.event(GridEvent::DuplicateRow, duplicate_row_handler)
// Cell
.event(GridEvent::GetCell, get_cell_handler)
.event(GridEvent::UpdateCell, update_cell_handler)
@ -81,6 +83,12 @@ pub enum GridEvent {
#[event(input = "RowIdentifierPayload", output = "Row")]
GetRow = 51,
#[event(input = "RowIdentifierPayload")]
DeleteRow = 52,
#[event(input = "RowIdentifierPayload")]
DuplicateRow = 53,
#[event(input = "CellIdentifierPayload", output = "Cell")]
GetCell = 70,

View File

@ -110,6 +110,7 @@ impl GridManager {
}
}
#[tracing::instrument(level = "trace", skip(self, pool), err)]
async fn make_grid_editor(
&self,
grid_id: &str,
@ -175,11 +176,11 @@ pub async fn make_grid_view_data(
grid_manager: Arc<GridManager>,
build_context: BuildGridContext,
) -> FlowyResult<Bytes> {
let block_id = build_context.block_metas.block_id.clone();
let block_id = build_context.block_meta.block_id.clone();
let grid_meta = GridMeta {
grid_id: view_id.to_string(),
fields: build_context.field_metas,
block_metas: vec![build_context.block_metas],
blocks: vec![build_context.block_meta],
};
// Create grid
@ -190,7 +191,7 @@ pub async fn make_grid_view_data(
let _ = grid_manager.create_grid(view_id, repeated_revision).await?;
// Indexing the block's rows
build_context.block_meta_data.row_metas.iter().for_each(|row| {
build_context.block_meta_data.rows.iter().for_each(|row| {
let _ = grid_manager
.block_index_persistence
.insert_or_update(&row.block_id, &row.id);

View File

@ -27,7 +27,7 @@
pub enum GridNotification {
Unknown = 0,
DidCreateBlock = 11,
DidUpdateBlock = 20,
DidUpdateGridBlock = 20,
DidUpdateRow = 30,
DidUpdateCell = 31,
DidUpdateGrid = 40,
@ -43,7 +43,7 @@ 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::DidUpdateBlock),
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),
@ -56,7 +56,7 @@ impl ::protobuf::ProtobufEnum for GridNotification {
static values: &'static [GridNotification] = &[
GridNotification::Unknown,
GridNotification::DidCreateBlock,
GridNotification::DidUpdateBlock,
GridNotification::DidUpdateGridBlock,
GridNotification::DidUpdateRow,
GridNotification::DidUpdateCell,
GridNotification::DidUpdateGrid,
@ -89,11 +89,11 @@ impl ::protobuf::reflect::ProtobufValue for GridNotification {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x17dart_notification.proto*\x93\x01\n\x10GridNotification\x12\x0b\n\
\x07Unknown\x10\0\x12\x12\n\x0eDidCreateBlock\x10\x0b\x12\x12\n\x0eDidUp\
dateBlock\x10\x14\x12\x10\n\x0cDidUpdateRow\x10\x1e\x12\x11\n\rDidUpdate\
Cell\x10\x1f\x12\x11\n\rDidUpdateGrid\x10(\x12\x12\n\x0eDidUpdateField\
\x10)b\x06proto3\
\n\x17dart_notification.proto*\x97\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\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -39,6 +39,8 @@ pub enum GridEvent {
ApplySelectOptionChangeset = 32,
CreateRow = 50,
GetRow = 51,
DeleteRow = 52,
DuplicateRow = 53,
GetCell = 70,
UpdateCell = 71,
ApplySelectOptionCellChangeset = 72,
@ -65,6 +67,8 @@ impl ::protobuf::ProtobufEnum for GridEvent {
32 => ::std::option::Option::Some(GridEvent::ApplySelectOptionChangeset),
50 => ::std::option::Option::Some(GridEvent::CreateRow),
51 => ::std::option::Option::Some(GridEvent::GetRow),
52 => ::std::option::Option::Some(GridEvent::DeleteRow),
53 => ::std::option::Option::Some(GridEvent::DuplicateRow),
70 => ::std::option::Option::Some(GridEvent::GetCell),
71 => ::std::option::Option::Some(GridEvent::UpdateCell),
72 => ::std::option::Option::Some(GridEvent::ApplySelectOptionCellChangeset),
@ -88,6 +92,8 @@ impl ::protobuf::ProtobufEnum for GridEvent {
GridEvent::ApplySelectOptionChangeset,
GridEvent::CreateRow,
GridEvent::GetRow,
GridEvent::DeleteRow,
GridEvent::DuplicateRow,
GridEvent::GetCell,
GridEvent::UpdateCell,
GridEvent::ApplySelectOptionCellChangeset,
@ -119,15 +125,16 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0fevent_map.proto*\xde\x02\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\
\n\x0fevent_map.proto*\xff\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\x0bCreateField\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\x1e\n\
\x1aApplySelectOptionChangeset\x10\x20\x12\r\n\tCreateRow\x102\x12\n\n\
\x06GetRow\x103\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\nUpdateCell\x10G\x12\
\"\n\x1eApplySelectOptionCellChangeset\x10Hb\x06proto3\
\x06GetRow\x103\x12\r\n\tDeleteRow\x104\x12\x10\n\x0cDuplicateRow\x105\
\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\nUpdateCell\x10G\x12\"\n\x1eApplySe\
lectOptionCellChangeset\x10Hb\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -3,7 +3,7 @@ syntax = "proto3";
enum GridNotification {
Unknown = 0;
DidCreateBlock = 11;
DidUpdateBlock = 20;
DidUpdateGridBlock = 20;
DidUpdateRow = 30;
DidUpdateCell = 31;
DidUpdateGrid = 40;

View File

@ -15,6 +15,8 @@ enum GridEvent {
ApplySelectOptionChangeset = 32;
CreateRow = 50;
GetRow = 51;
DeleteRow = 52;
DuplicateRow = 53;
GetCell = 70;
UpdateCell = 71;
ApplySelectOptionCellChangeset = 72;

View File

@ -7,6 +7,7 @@ use flowy_sync::entities::revision::Revision;
use flowy_sync::util::make_delta_from_revisions;
use lib_infra::future::FutureResult;
use lib_ot::core::PlainTextAttributes;
use std::borrow::Cow;
use std::sync::Arc;
use tokio::sync::RwLock;
@ -41,24 +42,37 @@ impl ClientGridBlockMetaEditor {
})
}
pub(crate) async fn create_row(&self, row: RowMeta, start_row_id: Option<String>) -> FlowyResult<i32> {
/// return current number of rows and the inserted index. The inserted index will be None if the start_row_id is None
pub(crate) async fn create_row(
&self,
row: RowMeta,
start_row_id: Option<String>,
) -> FlowyResult<(i32, Option<i32>)> {
let mut row_count = 0;
let mut row_index = None;
let _ = self
.modify(|pad| {
if let Some(start_row_id) = start_row_id.as_ref() {
match 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();
Ok(change)
})
.await?;
Ok(row_count)
Ok((row_count, row_index))
}
pub async fn delete_rows(&self, ids: Vec<String>) -> FlowyResult<i32> {
pub async fn delete_rows(&self, ids: Vec<Cow<'_, String>>) -> FlowyResult<i32> {
let mut row_count = 0;
let _ = self
.modify(|pad| {
let changeset = pad.delete_rows(&ids)?;
let changeset = pad.delete_rows(ids)?;
row_count = pad.number_of_rows();
Ok(changeset)
})
@ -71,17 +85,27 @@ impl ClientGridBlockMetaEditor {
Ok(())
}
pub async fn get_row_metas(&self, row_ids: Option<Vec<String>>) -> FlowyResult<Vec<Arc<RowMeta>>> {
let row_metas = self.pad.read().await.get_row_metas(&row_ids)?;
pub async fn get_row_metas<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<Arc<RowMeta>>>
where
T: AsRef<str> + ToOwned + ?Sized,
{
let row_metas = self.pad.read().await.get_row_metas(row_ids)?;
Ok(row_metas)
}
pub async fn get_cell_metas(&self, field_id: &str, row_ids: &Option<Vec<String>>) -> FlowyResult<Vec<CellMeta>> {
pub async fn get_cell_metas(
&self,
field_id: &str,
row_ids: Option<Vec<Cow<'_, String>>>,
) -> FlowyResult<Vec<CellMeta>> {
let cell_metas = self.pad.read().await.get_cell_metas(field_id, row_ids)?;
Ok(cell_metas)
}
pub async fn get_row_orders(&self, row_ids: &Option<Vec<String>>) -> FlowyResult<Vec<RowOrder>> {
pub async fn get_row_orders<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<RowOrder>>
where
T: AsRef<str> + ToOwned + ?Sized,
{
let row_orders = self
.pad
.read()

View File

@ -2,13 +2,14 @@ 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::{make_block_row_ids, make_rows_from_row_metas, GridBlockSnapshot};
use crate::services::row::{group_row_orders, make_rows_from_row_metas, GridBlockSnapshot};
use std::borrow::Cow;
use dashmap::DashMap;
use flowy_error::FlowyResult;
use flowy_grid_data_model::entities::{
CellMeta, CellMetaChangeset, CellNotificationData, FieldMeta, GridBlockMeta, GridBlockMetaChangeset,
GridBlockOrder, RowMeta, RowMetaChangeset, RowOrder,
GridBlockOrderChangeset, IndexRowOrder, RowMeta, RowMetaChangeset, RowOrder,
};
use flowy_revision::disk::SQLiteGridBlockMetaRevisionPersistence;
use flowy_revision::{RevisionManager, RevisionPersistence};
@ -18,6 +19,7 @@ use std::sync::Arc;
pub(crate) struct GridBlockMetaEditorManager {
grid_id: String,
user: Arc<dyn GridUser>,
// Key: block_id
editor_map: DashMap<String, Arc<ClientGridBlockMetaEditor>>,
persistence: Arc<BlockIndexPersistence>,
}
@ -68,8 +70,14 @@ impl GridBlockMetaEditorManager {
) -> FlowyResult<i32> {
let _ = self.persistence.insert_or_update(&row_meta.block_id, &row_meta.id)?;
let editor = self.get_editor(&row_meta.block_id).await?;
let row_count = editor.create_row(row_meta, start_row_id).await?;
self.notify_block_did_update_row(block_id).await?;
let mut index_row_order = IndexRowOrder::from(&row_meta);
let (row_count, row_index) = editor.create_row(row_meta, start_row_id).await?;
index_row_order.index = row_index;
let _ = self
.notify_did_update_grid_rows(GridBlockOrderChangeset::from_insert(block_id, vec![index_row_order]))
.await?;
Ok(row_count)
}
@ -79,27 +87,19 @@ impl GridBlockMetaEditorManager {
) -> FlowyResult<Vec<GridBlockMetaChangeset>> {
let mut changesets = vec![];
for (block_id, row_metas) in rows_by_block_id {
let mut inserted_row_orders = vec![];
let editor = self.get_editor(&block_id).await?;
let mut row_count = 0;
for row in &row_metas {
for row in row_metas {
let _ = self.persistence.insert_or_update(&row.block_id, &row.id)?;
row_count = editor.create_row(row.clone(), None).await?;
inserted_row_orders.push(IndexRowOrder::from(&row));
row_count = editor.create_row(row, None).await?.0;
}
changesets.push(GridBlockMetaChangeset::from_row_count(&block_id, row_count));
let _ = self.notify_block_did_update_row(&block_id).await?;
}
Ok(changesets)
}
pub(crate) async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<Vec<GridBlockMetaChangeset>> {
let mut changesets = vec![];
for block_row_ids in make_block_row_ids(&row_orders) {
let editor = self.get_editor(&block_row_ids.block_id).await?;
let row_count = editor.delete_rows(block_row_ids.row_ids).await?;
let changeset = GridBlockMetaChangeset::from_row_count(&block_row_ids.block_id, row_count);
changesets.push(changeset);
let _ = self
.notify_did_update_grid_rows(GridBlockOrderChangeset::from_insert(&block_id, inserted_row_orders))
.await?;
}
Ok(changesets)
@ -108,10 +108,52 @@ 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_block_did_update_row(&editor.block_id).await?;
match editor
.get_row_orders(Some(vec![Cow::Borrowed(&changeset.row_id)]))
.await?
.pop()
{
None => {}
Some(row_order) => {
let block_order_changeset = GridBlockOrderChangeset::from_update(&editor.block_id, vec![row_order]);
let _ = self.notify_did_update_grid_rows(block_order_changeset).await?;
}
}
Ok(())
}
pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> {
let row_id = row_id.to_owned();
let block_id = self.persistence.get_block_id(&row_id)?;
let editor = self.get_editor(&block_id).await?;
let row_orders = editor.get_row_orders(Some(vec![Cow::Borrowed(&row_id)])).await?;
let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?;
let _ = self
.notify_did_update_grid_rows(GridBlockOrderChangeset::from_delete(&block_id, row_orders))
.await?;
Ok(())
}
pub(crate) async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<Vec<GridBlockMetaChangeset>> {
let mut changesets = vec![];
for block_order in group_row_orders(row_orders) {
let editor = self.get_editor(&block_order.block_id).await?;
let row_ids = block_order
.row_orders
.into_iter()
.map(|row_order| Cow::Owned(row_order.row_id))
.collect::<Vec<Cow<String>>>();
let row_count = editor.delete_rows(row_ids).await?;
let changeset = GridBlockMetaChangeset::from_row_count(&block_order.block_id, row_count);
changesets.push(changeset);
}
Ok(changesets)
}
pub async fn update_cell(&self, changeset: CellMetaChangeset) -> FlowyResult<()> {
let row_id = changeset.row_id.clone();
let editor = self.get_editor_from_row_id(&row_id).await?;
@ -130,7 +172,7 @@ impl GridBlockMetaEditorManager {
pub async fn get_row_meta(&self, row_id: &str) -> FlowyResult<Option<Arc<RowMeta>>> {
let editor = self.get_editor_from_row_id(row_id).await?;
let row_ids = vec![row_id.to_owned()];
let row_ids = vec![Cow::Borrowed(row_id)];
let mut row_metas = editor.get_row_metas(Some(row_ids)).await?;
if row_metas.is_empty() {
Ok(None)
@ -139,11 +181,16 @@ impl GridBlockMetaEditorManager {
}
}
pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<RowOrder>> {
let editor = self.get_editor(block_id).await?;
editor.get_row_orders::<&str>(None).await
}
pub(crate) async fn make_block_snapshots(&self, block_ids: Vec<String>) -> FlowyResult<Vec<GridBlockSnapshot>> {
let mut snapshots = vec![];
for block_id in block_ids {
let editor = self.get_editor(&block_id).await?;
let row_metas = editor.get_row_metas(None).await?;
let row_metas = editor.get_row_metas::<&str>(None).await?;
snapshots.push(GridBlockSnapshot { block_id, row_metas });
}
Ok(snapshots)
@ -155,21 +202,20 @@ impl GridBlockMetaEditorManager {
&self,
block_ids: Vec<String>,
field_id: &str,
row_ids: Option<Vec<String>>,
row_ids: Option<Vec<Cow<'_, String>>>,
) -> FlowyResult<Vec<CellMeta>> {
let mut block_cell_metas = vec![];
for block_id in block_ids {
let editor = self.get_editor(&block_id).await?;
let cell_metas = editor.get_cell_metas(field_id, &row_ids).await?;
let cell_metas = editor.get_cell_metas(field_id, row_ids.clone()).await?;
block_cell_metas.extend(cell_metas);
}
Ok(block_cell_metas)
}
async fn notify_block_did_update_row(&self, block_id: &str) -> FlowyResult<()> {
let block_order: GridBlockOrder = block_id.into();
send_dart_notification(&self.grid_id, GridNotification::DidUpdateBlock)
.payload(block_order)
async fn notify_did_update_grid_rows(&self, changeset: GridBlockOrderChangeset) -> FlowyResult<()> {
send_dart_notification(&self.grid_id, GridNotification::DidUpdateGridBlock)
.payload(changeset)
.send();
Ok(())
}
@ -196,30 +242,6 @@ impl GridBlockMetaEditorManager {
}
}
Ok(())
//
// let field_meta_map = field_metas
// .iter()
// .map(|field_meta| (&field_meta.id, field_meta))
// .collect::<HashMap<&String, &FieldMeta>>();
//
// let mut cells = vec![];
// changeset
// .cell_by_field_id
// .into_iter()
// .for_each(
// |(field_id, cell_meta)| match make_cell_by_field_id(&field_meta_map, field_id, cell_meta) {
// None => {}
// Some((_, cell)) => cells.push(cell),
// },
// );
//
// if !cells.is_empty() {
// send_dart_notification(&changeset.row_id, GridNotification::DidUpdateRow)
// .payload(RepeatedCell::from(cells))
// .send();
// }
// Ok(())
}
}

View File

@ -70,7 +70,7 @@ impl CellDataOperation for DateTypeOption {
) -> Result<String, FlowyError> {
let changeset = changeset.into();
if changeset.parse::<f64>().is_err() || changeset.parse::<i64>().is_err() {
return Err(FlowyError::internal().context(format!("Parse {} failed", changeset.to_string())));
return Err(FlowyError::internal().context(format!("Parse {} failed", changeset)));
};
Ok(TypeOptionCellData::new(changeset, self.field_type()).json())

View File

@ -16,9 +16,28 @@ use std::str::FromStr;
pub const SELECTION_IDS_SEPARATOR: &str = ",";
pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync {
fn insert_option(&mut self, new_option: SelectOption);
fn delete_option(&mut self, delete_option: SelectOption);
fn insert_option(&mut self, new_option: SelectOption) {
let options = self.mut_options();
if let Some(index) = options
.iter()
.position(|option| option.id == new_option.id || option.name == new_option.name)
{
options.remove(index);
options.insert(index, new_option);
} else {
options.insert(0, new_option);
}
}
fn delete_option(&mut self, delete_option: SelectOption) {
let options = self.mut_options();
if let Some(index) = options.iter().position(|option| option.id == delete_option.id) {
options.remove(index);
}
}
fn option_context(&self, cell_meta: &Option<CellMeta>) -> SelectOptionContext;
fn mut_options(&mut self) -> &mut Vec<SelectOption>;
}
// Single select
@ -33,21 +52,6 @@ pub struct SingleSelectTypeOption {
impl_type_option!(SingleSelectTypeOption, FieldType::SingleSelect);
impl SelectOptionOperation for SingleSelectTypeOption {
fn insert_option(&mut self, new_option: SelectOption) {
if let Some(index) = self.options.iter().position(|option| option.id == new_option.id) {
self.options.remove(index);
self.options.insert(index, new_option);
} else {
self.options.insert(0, new_option);
}
}
fn delete_option(&mut self, delete_option: SelectOption) {
if let Some(index) = self.options.iter().position(|option| option.id == delete_option.id) {
self.options.remove(index);
}
}
fn option_context(&self, cell_meta: &Option<CellMeta>) -> SelectOptionContext {
let select_options = make_select_context_from(cell_meta, &self.options);
SelectOptionContext {
@ -55,6 +59,10 @@ impl SelectOptionOperation for SingleSelectTypeOption {
select_options,
}
}
fn mut_options(&mut self) -> &mut Vec<SelectOption> {
&mut self.options
}
}
impl CellDataOperation for SingleSelectTypeOption {
@ -139,21 +147,6 @@ impl MultiSelectTypeOption {
}
impl SelectOptionOperation for MultiSelectTypeOption {
fn insert_option(&mut self, new_option: SelectOption) {
if let Some(index) = self.options.iter().position(|option| option.id == new_option.id) {
self.options.remove(index);
self.options.insert(index, new_option);
} else {
self.options.insert(0, new_option);
}
}
fn delete_option(&mut self, delete_option: SelectOption) {
if let Some(index) = self.options.iter().position(|option| option.id == delete_option.id) {
self.options.remove(index);
}
}
fn option_context(&self, cell_meta: &Option<CellMeta>) -> SelectOptionContext {
let select_options = make_select_context_from(cell_meta, &self.options);
SelectOptionContext {
@ -161,6 +154,10 @@ impl SelectOptionOperation for MultiSelectTypeOption {
select_options,
}
}
fn mut_options(&mut self) -> &mut Vec<SelectOption> {
&mut self.options
}
}
impl CellDataOperation for MultiSelectTypeOption {
@ -472,7 +469,7 @@ mod tests {
let single_select = SingleSelectTypeOptionBuilder::default()
.option(google_option.clone())
.option(facebook_option.clone())
.option(twitter_option.clone());
.option(twitter_option);
let field_meta = FieldBuilder::new(single_select)
.name("Platform")
@ -481,7 +478,7 @@ mod tests {
let type_option = SingleSelectTypeOption::from(&field_meta);
let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR);
let option_ids = vec![google_option.id.clone(), facebook_option.id].join(SELECTION_IDS_SEPARATOR);
let data = SelectOptionCellChangeset::from_insert(&option_ids).cell_data();
let cell_data = type_option.apply_changeset(data, None).unwrap();
assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), google_option.name,);
@ -514,7 +511,7 @@ mod tests {
let multi_select = MultiSelectTypeOptionBuilder::default()
.option(google_option.clone())
.option(facebook_option.clone())
.option(twitter_option.clone());
.option(twitter_option);
let field_meta = FieldBuilder::new(multi_select)
.name("Platform")
@ -528,7 +525,7 @@ mod tests {
let cell_data = type_option.apply_changeset(data, None).unwrap();
assert_eq!(
type_option.decode_cell_data(cell_data, &field_meta),
vec![google_option.name.clone(), facebook_option.name.clone()].join(SELECTION_IDS_SEPARATOR),
vec![google_option.name.clone(), facebook_option.name].join(SELECTION_IDS_SEPARATOR),
);
let data = SelectOptionCellChangeset::from_insert(&google_option.id).cell_data();

View File

@ -267,6 +267,14 @@ impl ClientGridEditor {
}
}
}
pub async fn delete_row(&self, row_id: &str) -> FlowyResult<()> {
let _ = self.block_meta_manager.delete_row(row_id).await?;
Ok(())
}
pub async fn duplicate_row(&self, _row_id: &str) -> FlowyResult<()> {
Ok(())
}
pub async fn get_cell(&self, params: &CellIdentifier) -> Option<Cell> {
let field_meta = self.get_field_meta(&params.field_id).await?;
@ -316,6 +324,11 @@ impl ClientGridEditor {
Ok(grid_blocks)
}
// pub async fn get_field_metas<T>(&self, field_ids: Option<Vec<T>>) -> FlowyResult<Vec<FieldMeta>>
// where
// T: Into<FieldOrder>,
// {
pub async fn delete_rows(&self, row_orders: Vec<RowOrder>) -> FlowyResult<()> {
let changesets = self.block_meta_manager.delete_rows(row_orders).await?;
for changeset in changesets {
@ -325,17 +338,18 @@ impl ClientGridEditor {
}
pub async fn grid_data(&self) -> FlowyResult<Grid> {
let field_orders = self.pad.read().await.get_field_orders();
let block_orders = self
.pad
.read()
.await
.get_block_metas()
.into_iter()
.map(|grid_block_meta| GridBlockOrder {
block_id: grid_block_meta.block_id,
})
.collect::<Vec<_>>();
let pad_read_guard = self.pad.read().await;
let field_orders = pad_read_guard.get_field_orders();
let mut block_orders = vec![];
for block_order in pad_read_guard.get_block_metas() {
let row_orders = self.block_meta_manager.get_row_orders(&block_order.block_id).await?;
let block_order = GridBlockOrder {
block_id: block_order.block_id,
row_orders,
};
block_orders.push(block_order);
}
Ok(Grid {
id: self.grid_id.clone(),
field_orders,
@ -416,7 +430,7 @@ impl ClientGridEditor {
debug_assert!(field_metas.len() == 1);
if let Some(field_meta) = field_metas.pop() {
send_dart_notification(&field_id, GridNotification::DidUpdateField)
send_dart_notification(field_id, GridNotification::DidUpdateField)
.payload(field_meta)
.send();
}

View File

@ -1,41 +1,28 @@
use crate::services::row::decode_cell_data;
use flowy_error::FlowyResult;
use flowy_grid_data_model::entities::{
Cell, CellMeta, FieldMeta, GridBlock, RepeatedGridBlock, Row, RowMeta, RowOrder,
Cell, CellMeta, FieldMeta, GridBlock, GridBlockOrder, RepeatedGridBlock, Row, RowMeta, RowOrder,
};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use std::collections::HashMap;
use std::sync::Arc;
pub(crate) struct BlockRowIds {
pub(crate) block_id: String,
pub(crate) row_ids: Vec<String>,
}
impl BlockRowIds {
pub fn new(block_id: &str) -> Self {
BlockRowIds {
block_id: block_id.to_owned(),
row_ids: vec![],
}
}
}
pub struct GridBlockSnapshot {
pub(crate) block_id: String,
pub row_metas: Vec<Arc<RowMeta>>,
}
pub(crate) fn make_block_row_ids(row_orders: &[RowOrder]) -> Vec<BlockRowIds> {
let mut map: HashMap<&String, BlockRowIds> = HashMap::new();
row_orders.iter().for_each(|row_order| {
let block_id = &row_order.block_id;
let row_id = row_order.row_id.clone();
pub(crate) fn group_row_orders(row_orders: Vec<RowOrder>) -> Vec<GridBlockOrder> {
let mut map: HashMap<String, GridBlockOrder> = HashMap::new();
row_orders.into_iter().for_each(|row_order| {
// Memory Optimization: escape clone block_id
let block_id = row_order.block_id.clone();
map.entry(block_id)
.or_insert_with(|| BlockRowIds::new(block_id))
.row_ids
.push(row_id);
.or_insert_with(|| GridBlockOrder::new(&row_order.block_id))
.row_orders
.push(row_order);
});
map.into_values().collect::<Vec<_>>()
}

View File

@ -4,7 +4,7 @@ use chrono::NaiveDateTime;
use flowy_grid::services::field::{
MultiSelectTypeOption, SelectOption, SelectOptionCellChangeset, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR,
};
use flowy_grid::services::row::{apply_cell_data_changeset, decode_cell_data, CellDataOperation, CreateRowMetaBuilder};
use flowy_grid::services::row::{decode_cell_data, CreateRowMetaBuilder};
use flowy_grid_data_model::entities::{
CellMetaChangeset, FieldChangesetParams, FieldType, GridBlockMeta, GridBlockMetaChangeset, RowMetaChangeset,
TypeOptionDataEntry,

View File

@ -260,11 +260,83 @@ impl std::convert::From<Vec<GridBlock>> for RepeatedGridBlock {
pub struct GridBlockOrder {
#[pb(index = 1)]
pub block_id: String,
#[pb(index = 2)]
pub row_orders: Vec<RowOrder>,
}
impl std::convert::From<&str> for GridBlockOrder {
fn from(s: &str) -> Self {
GridBlockOrder { block_id: s.to_owned() }
impl GridBlockOrder {
pub fn new(block_id: &str) -> Self {
GridBlockOrder {
block_id: block_id.to_owned(),
row_orders: vec![],
}
}
}
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct GridBlockOrderChangeset {
#[pb(index = 1)]
pub block_id: String,
#[pb(index = 2)]
pub inserted_rows: Vec<IndexRowOrder>,
#[pb(index = 3)]
pub deleted_rows: Vec<RowOrder>,
#[pb(index = 4)]
pub updated_rows: Vec<RowOrder>,
}
#[derive(Debug, Clone, Default, ProtoBuf)]
pub struct IndexRowOrder {
#[pb(index = 1)]
pub row_order: RowOrder,
#[pb(index = 2, one_of)]
pub index: Option<i32>,
}
impl std::convert::From<RowOrder> for IndexRowOrder {
fn from(row_order: RowOrder) -> Self {
Self { row_order, index: None }
}
}
impl std::convert::From<&RowMeta> for IndexRowOrder {
fn from(row: &RowMeta) -> Self {
let row_order = RowOrder::from(row);
Self::from(row_order)
}
}
impl GridBlockOrderChangeset {
pub fn from_insert(block_id: &str, inserted_rows: Vec<IndexRowOrder>) -> Self {
Self {
block_id: block_id.to_owned(),
inserted_rows,
deleted_rows: vec![],
updated_rows: vec![],
}
}
pub fn from_delete(block_id: &str, deleted_rows: Vec<RowOrder>) -> Self {
Self {
block_id: block_id.to_owned(),
inserted_rows: vec![],
deleted_rows,
updated_rows: vec![],
}
}
pub fn from_update(block_id: &str, updated_rows: Vec<RowOrder>) -> Self {
Self {
block_id: block_id.to_owned(),
inserted_rows: vec![],
deleted_rows: vec![],
updated_rows,
}
}
}

View File

@ -18,7 +18,7 @@ pub struct GridMeta {
pub fields: Vec<FieldMeta>,
#[pb(index = 3)]
pub block_metas: Vec<GridBlockMeta>,
pub blocks: Vec<GridBlockMeta>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, ProtoBuf)]
@ -74,7 +74,7 @@ pub struct GridBlockMetaData {
pub block_id: String,
#[pb(index = 2)]
pub row_metas: Vec<RowMeta>,
pub rows: Vec<RowMeta>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, ProtoBuf, Eq, PartialEq)]
@ -398,7 +398,7 @@ impl std::convert::From<CellMetaChangeset> for RowMetaChangeset {
row_id: changeset.row_id,
height: None,
visibility: None,
cell_by_field_id: cell_by_field_id,
cell_by_field_id,
}
}
}
@ -409,7 +409,7 @@ pub struct BuildGridContext {
pub field_metas: Vec<FieldMeta>,
#[pb(index = 2)]
pub block_metas: GridBlockMeta,
pub block_meta: GridBlockMeta,
#[pb(index = 3)]
pub block_meta_data: GridBlockMetaData,
@ -417,16 +417,16 @@ pub struct BuildGridContext {
impl std::default::Default for BuildGridContext {
fn default() -> Self {
let grid_block = GridBlockMeta::new();
let grid_block_meta_data = GridBlockMetaData {
block_id: grid_block.block_id.clone(),
row_metas: vec![],
let block_meta = GridBlockMeta::new();
let block_meta_data = GridBlockMetaData {
block_id: block_meta.block_id.clone(),
rows: vec![],
};
Self {
field_metas: vec![],
block_metas: grid_block,
block_meta_data: grid_block_meta_data,
block_meta,
block_meta_data,
}
}
}

View File

@ -2715,6 +2715,7 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedGridBlock {
pub struct GridBlockOrder {
// message fields
pub block_id: ::std::string::String,
pub row_orders: ::protobuf::RepeatedField<RowOrder>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -2756,10 +2757,40 @@ impl GridBlockOrder {
pub fn take_block_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.block_id, ::std::string::String::new())
}
// repeated .RowOrder row_orders = 2;
pub fn get_row_orders(&self) -> &[RowOrder] {
&self.row_orders
}
pub fn clear_row_orders(&mut self) {
self.row_orders.clear();
}
// Param is passed by value, moved
pub fn set_row_orders(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
self.row_orders = v;
}
// Mutable pointer to the field.
pub fn mut_row_orders(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
&mut self.row_orders
}
// Take field
pub fn take_row_orders(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
::std::mem::replace(&mut self.row_orders, ::protobuf::RepeatedField::new())
}
}
impl ::protobuf::Message for GridBlockOrder {
fn is_initialized(&self) -> bool {
for v in &self.row_orders {
if !v.is_initialized() {
return false;
}
};
true
}
@ -2770,6 +2801,9 @@ impl ::protobuf::Message for GridBlockOrder {
1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?;
},
2 => {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.row_orders)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
},
@ -2785,6 +2819,10 @@ impl ::protobuf::Message for GridBlockOrder {
if !self.block_id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.block_id);
}
for value in &self.row_orders {
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
@ -2794,6 +2832,11 @@ impl ::protobuf::Message for GridBlockOrder {
if !self.block_id.is_empty() {
os.write_string(1, &self.block_id)?;
}
for v in &self.row_orders {
os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
};
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
}
@ -2837,6 +2880,11 @@ impl ::protobuf::Message for GridBlockOrder {
|m: &GridBlockOrder| { &m.block_id },
|m: &mut GridBlockOrder| { &mut m.block_id },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
"row_orders",
|m: &GridBlockOrder| { &m.row_orders },
|m: &mut GridBlockOrder| { &mut m.row_orders },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlockOrder>(
"GridBlockOrder",
fields,
@ -2854,6 +2902,7 @@ impl ::protobuf::Message for GridBlockOrder {
impl ::protobuf::Clear for GridBlockOrder {
fn clear(&mut self) {
self.block_id.clear();
self.row_orders.clear();
self.unknown_fields.clear();
}
}
@ -2870,6 +2919,544 @@ impl ::protobuf::reflect::ProtobufValue for GridBlockOrder {
}
}
#[derive(PartialEq,Clone,Default)]
pub struct GridBlockOrderChangeset {
// message fields
pub block_id: ::std::string::String,
pub inserted_rows: ::protobuf::RepeatedField<IndexRowOrder>,
pub deleted_rows: ::protobuf::RepeatedField<RowOrder>,
pub updated_rows: ::protobuf::RepeatedField<RowOrder>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a GridBlockOrderChangeset {
fn default() -> &'a GridBlockOrderChangeset {
<GridBlockOrderChangeset as ::protobuf::Message>::default_instance()
}
}
impl GridBlockOrderChangeset {
pub fn new() -> GridBlockOrderChangeset {
::std::default::Default::default()
}
// string block_id = 1;
pub fn get_block_id(&self) -> &str {
&self.block_id
}
pub fn clear_block_id(&mut self) {
self.block_id.clear();
}
// Param is passed by value, moved
pub fn set_block_id(&mut self, v: ::std::string::String) {
self.block_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
}
// Take field
pub fn take_block_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.block_id, ::std::string::String::new())
}
// repeated .IndexRowOrder inserted_rows = 2;
pub fn get_inserted_rows(&self) -> &[IndexRowOrder] {
&self.inserted_rows
}
pub fn clear_inserted_rows(&mut self) {
self.inserted_rows.clear();
}
// Param is passed by value, moved
pub fn set_inserted_rows(&mut self, v: ::protobuf::RepeatedField<IndexRowOrder>) {
self.inserted_rows = v;
}
// Mutable pointer to the field.
pub fn mut_inserted_rows(&mut self) -> &mut ::protobuf::RepeatedField<IndexRowOrder> {
&mut self.inserted_rows
}
// Take field
pub fn take_inserted_rows(&mut self) -> ::protobuf::RepeatedField<IndexRowOrder> {
::std::mem::replace(&mut self.inserted_rows, ::protobuf::RepeatedField::new())
}
// repeated .RowOrder deleted_rows = 3;
pub fn get_deleted_rows(&self) -> &[RowOrder] {
&self.deleted_rows
}
pub fn clear_deleted_rows(&mut self) {
self.deleted_rows.clear();
}
// Param is passed by value, moved
pub fn set_deleted_rows(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
self.deleted_rows = v;
}
// Mutable pointer to the field.
pub fn mut_deleted_rows(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
&mut self.deleted_rows
}
// Take field
pub fn take_deleted_rows(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
::std::mem::replace(&mut self.deleted_rows, ::protobuf::RepeatedField::new())
}
// repeated .RowOrder updated_rows = 4;
pub fn get_updated_rows(&self) -> &[RowOrder] {
&self.updated_rows
}
pub fn clear_updated_rows(&mut self) {
self.updated_rows.clear();
}
// Param is passed by value, moved
pub fn set_updated_rows(&mut self, v: ::protobuf::RepeatedField<RowOrder>) {
self.updated_rows = v;
}
// Mutable pointer to the field.
pub fn mut_updated_rows(&mut self) -> &mut ::protobuf::RepeatedField<RowOrder> {
&mut self.updated_rows
}
// Take field
pub fn take_updated_rows(&mut self) -> ::protobuf::RepeatedField<RowOrder> {
::std::mem::replace(&mut self.updated_rows, ::protobuf::RepeatedField::new())
}
}
impl ::protobuf::Message for GridBlockOrderChangeset {
fn is_initialized(&self) -> bool {
for v in &self.inserted_rows {
if !v.is_initialized() {
return false;
}
};
for v in &self.deleted_rows {
if !v.is_initialized() {
return false;
}
};
for v in &self.updated_rows {
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.block_id)?;
},
2 => {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.inserted_rows)?;
},
3 => {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.deleted_rows)?;
},
4 => {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.updated_rows)?;
},
_ => {
::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.block_id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.block_id);
}
for value in &self.inserted_rows {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
};
for value in &self.deleted_rows {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
};
for value in &self.updated_rows {
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.block_id.is_empty() {
os.write_string(1, &self.block_id)?;
}
for v in &self.inserted_rows {
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_rows {
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_rows {
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<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
self
}
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
Self::descriptor_static()
}
fn new() -> GridBlockOrderChangeset {
GridBlockOrderChangeset::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>(
"block_id",
|m: &GridBlockOrderChangeset| { &m.block_id },
|m: &mut GridBlockOrderChangeset| { &mut m.block_id },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<IndexRowOrder>>(
"inserted_rows",
|m: &GridBlockOrderChangeset| { &m.inserted_rows },
|m: &mut GridBlockOrderChangeset| { &mut m.inserted_rows },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
"deleted_rows",
|m: &GridBlockOrderChangeset| { &m.deleted_rows },
|m: &mut GridBlockOrderChangeset| { &mut m.deleted_rows },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowOrder>>(
"updated_rows",
|m: &GridBlockOrderChangeset| { &m.updated_rows },
|m: &mut GridBlockOrderChangeset| { &mut m.updated_rows },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlockOrderChangeset>(
"GridBlockOrderChangeset",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static GridBlockOrderChangeset {
static instance: ::protobuf::rt::LazyV2<GridBlockOrderChangeset> = ::protobuf::rt::LazyV2::INIT;
instance.get(GridBlockOrderChangeset::new)
}
}
impl ::protobuf::Clear for GridBlockOrderChangeset {
fn clear(&mut self) {
self.block_id.clear();
self.inserted_rows.clear();
self.deleted_rows.clear();
self.updated_rows.clear();
self.unknown_fields.clear();
}
}
impl ::std::fmt::Debug for GridBlockOrderChangeset {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for GridBlockOrderChangeset {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
#[derive(PartialEq,Clone,Default)]
pub struct IndexRowOrder {
// message fields
pub row_order: ::protobuf::SingularPtrField<RowOrder>,
// message oneof groups
pub one_of_index: ::std::option::Option<IndexRowOrder_oneof_one_of_index>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a IndexRowOrder {
fn default() -> &'a IndexRowOrder {
<IndexRowOrder as ::protobuf::Message>::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(|| <RowOrder as ::protobuf::Message>::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<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
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<RowOrder>>(
"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>(
"IndexRowOrder",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static IndexRowOrder {
static instance: ::protobuf::rt::LazyV2<IndexRowOrder> = ::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
@ -5283,31 +5870,38 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\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\"+\n\x0eGridBlockOrder\
\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\"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\x14CellNotificationData\x12\x17\n\x07grid_id\x18\
\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07\
fieldId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowId\x12\x1a\n\x07co\
ntent\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\x05i\
tems\"'\n\x11CreateGridPayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04\
name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"\
#\n\x0bGridBlockId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\
\x10CreateRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\
\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13on\
e_of_start_row_id\"\xb6\x01\n\x12CreateFieldPayload\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_field_id\x18\x04\x20\x01(\tH\0R\x0cst\
artFieldIdB\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\x16Qu\
eryGridBlocksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\
\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblo\
ckOrdersb\x06proto3\
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\"\xc5\x01\n\x17GridBlockOr\
derChangeset\x12\x19\n\x08block_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\
\"_\n\rIndexRowOrder\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_index\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02\
id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\
\x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\
\x07content\x18\x02\x20\x01(\tR\x07content\"\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\x12Cre\
ateFieldPayload\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\x0bblockOrdersb\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -28,7 +28,7 @@ pub struct GridMeta {
// message fields
pub grid_id: ::std::string::String,
pub fields: ::protobuf::RepeatedField<FieldMeta>,
pub block_metas: ::protobuf::RepeatedField<GridBlockMeta>,
pub blocks: ::protobuf::RepeatedField<GridBlockMeta>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -96,29 +96,29 @@ impl GridMeta {
::std::mem::replace(&mut self.fields, ::protobuf::RepeatedField::new())
}
// repeated .GridBlockMeta block_metas = 3;
// repeated .GridBlockMeta blocks = 3;
pub fn get_block_metas(&self) -> &[GridBlockMeta] {
&self.block_metas
pub fn get_blocks(&self) -> &[GridBlockMeta] {
&self.blocks
}
pub fn clear_block_metas(&mut self) {
self.block_metas.clear();
pub fn clear_blocks(&mut self) {
self.blocks.clear();
}
// Param is passed by value, moved
pub fn set_block_metas(&mut self, v: ::protobuf::RepeatedField<GridBlockMeta>) {
self.block_metas = v;
pub fn set_blocks(&mut self, v: ::protobuf::RepeatedField<GridBlockMeta>) {
self.blocks = v;
}
// Mutable pointer to the field.
pub fn mut_block_metas(&mut self) -> &mut ::protobuf::RepeatedField<GridBlockMeta> {
&mut self.block_metas
pub fn mut_blocks(&mut self) -> &mut ::protobuf::RepeatedField<GridBlockMeta> {
&mut self.blocks
}
// Take field
pub fn take_block_metas(&mut self) -> ::protobuf::RepeatedField<GridBlockMeta> {
::std::mem::replace(&mut self.block_metas, ::protobuf::RepeatedField::new())
pub fn take_blocks(&mut self) -> ::protobuf::RepeatedField<GridBlockMeta> {
::std::mem::replace(&mut self.blocks, ::protobuf::RepeatedField::new())
}
}
@ -129,7 +129,7 @@ impl ::protobuf::Message for GridMeta {
return false;
}
};
for v in &self.block_metas {
for v in &self.blocks {
if !v.is_initialized() {
return false;
}
@ -148,7 +148,7 @@ impl ::protobuf::Message for GridMeta {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.fields)?;
},
3 => {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.block_metas)?;
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.blocks)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -169,7 +169,7 @@ impl ::protobuf::Message for GridMeta {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
};
for value in &self.block_metas {
for value in &self.blocks {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
};
@ -187,7 +187,7 @@ impl ::protobuf::Message for GridMeta {
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
};
for v in &self.block_metas {
for v in &self.blocks {
os.write_tag(3, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
@ -241,9 +241,9 @@ impl ::protobuf::Message for GridMeta {
|m: &mut GridMeta| { &mut m.fields },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<GridBlockMeta>>(
"block_metas",
|m: &GridMeta| { &m.block_metas },
|m: &mut GridMeta| { &mut m.block_metas },
"blocks",
|m: &GridMeta| { &m.blocks },
|m: &mut GridMeta| { &mut m.blocks },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<GridMeta>(
"GridMeta",
@ -263,7 +263,7 @@ impl ::protobuf::Clear for GridMeta {
fn clear(&mut self) {
self.grid_id.clear();
self.fields.clear();
self.block_metas.clear();
self.blocks.clear();
self.unknown_fields.clear();
}
}
@ -513,7 +513,7 @@ impl ::protobuf::reflect::ProtobufValue for GridBlockMeta {
pub struct GridBlockMetaData {
// message fields
pub block_id: ::std::string::String,
pub row_metas: ::protobuf::RepeatedField<RowMeta>,
pub rows: ::protobuf::RepeatedField<RowMeta>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
@ -556,35 +556,35 @@ impl GridBlockMetaData {
::std::mem::replace(&mut self.block_id, ::std::string::String::new())
}
// repeated .RowMeta row_metas = 2;
// repeated .RowMeta rows = 2;
pub fn get_row_metas(&self) -> &[RowMeta] {
&self.row_metas
pub fn get_rows(&self) -> &[RowMeta] {
&self.rows
}
pub fn clear_row_metas(&mut self) {
self.row_metas.clear();
pub fn clear_rows(&mut self) {
self.rows.clear();
}
// Param is passed by value, moved
pub fn set_row_metas(&mut self, v: ::protobuf::RepeatedField<RowMeta>) {
self.row_metas = v;
pub fn set_rows(&mut self, v: ::protobuf::RepeatedField<RowMeta>) {
self.rows = v;
}
// Mutable pointer to the field.
pub fn mut_row_metas(&mut self) -> &mut ::protobuf::RepeatedField<RowMeta> {
&mut self.row_metas
pub fn mut_rows(&mut self) -> &mut ::protobuf::RepeatedField<RowMeta> {
&mut self.rows
}
// Take field
pub fn take_row_metas(&mut self) -> ::protobuf::RepeatedField<RowMeta> {
::std::mem::replace(&mut self.row_metas, ::protobuf::RepeatedField::new())
pub fn take_rows(&mut self) -> ::protobuf::RepeatedField<RowMeta> {
::std::mem::replace(&mut self.rows, ::protobuf::RepeatedField::new())
}
}
impl ::protobuf::Message for GridBlockMetaData {
fn is_initialized(&self) -> bool {
for v in &self.row_metas {
for v in &self.rows {
if !v.is_initialized() {
return false;
}
@ -600,7 +600,7 @@ impl ::protobuf::Message for GridBlockMetaData {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.block_id)?;
},
2 => {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.row_metas)?;
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.rows)?;
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -617,7 +617,7 @@ impl ::protobuf::Message for GridBlockMetaData {
if !self.block_id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.block_id);
}
for value in &self.row_metas {
for value in &self.rows {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
};
@ -630,7 +630,7 @@ impl ::protobuf::Message for GridBlockMetaData {
if !self.block_id.is_empty() {
os.write_string(1, &self.block_id)?;
}
for v in &self.row_metas {
for v in &self.rows {
os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
@ -679,9 +679,9 @@ impl ::protobuf::Message for GridBlockMetaData {
|m: &mut GridBlockMetaData| { &mut m.block_id },
));
fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<RowMeta>>(
"row_metas",
|m: &GridBlockMetaData| { &m.row_metas },
|m: &mut GridBlockMetaData| { &mut m.row_metas },
"rows",
|m: &GridBlockMetaData| { &m.rows },
|m: &mut GridBlockMetaData| { &mut m.rows },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<GridBlockMetaData>(
"GridBlockMetaData",
@ -700,7 +700,7 @@ impl ::protobuf::Message for GridBlockMetaData {
impl ::protobuf::Clear for GridBlockMetaData {
fn clear(&mut self) {
self.block_id.clear();
self.row_metas.clear();
self.rows.clear();
self.unknown_fields.clear();
}
}
@ -3114,7 +3114,7 @@ impl ::protobuf::reflect::ProtobufValue for CellMetaChangeset {
pub struct BuildGridContext {
// message fields
pub field_metas: ::protobuf::RepeatedField<FieldMeta>,
pub block_metas: ::protobuf::SingularPtrField<GridBlockMeta>,
pub block_meta: ::protobuf::SingularPtrField<GridBlockMeta>,
pub block_meta_data: ::protobuf::SingularPtrField<GridBlockMetaData>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
@ -3157,37 +3157,37 @@ impl BuildGridContext {
::std::mem::replace(&mut self.field_metas, ::protobuf::RepeatedField::new())
}
// .GridBlockMeta block_metas = 2;
// .GridBlockMeta block_meta = 2;
pub fn get_block_metas(&self) -> &GridBlockMeta {
self.block_metas.as_ref().unwrap_or_else(|| <GridBlockMeta as ::protobuf::Message>::default_instance())
pub fn get_block_meta(&self) -> &GridBlockMeta {
self.block_meta.as_ref().unwrap_or_else(|| <GridBlockMeta as ::protobuf::Message>::default_instance())
}
pub fn clear_block_metas(&mut self) {
self.block_metas.clear();
pub fn clear_block_meta(&mut self) {
self.block_meta.clear();
}
pub fn has_block_metas(&self) -> bool {
self.block_metas.is_some()
pub fn has_block_meta(&self) -> bool {
self.block_meta.is_some()
}
// Param is passed by value, moved
pub fn set_block_metas(&mut self, v: GridBlockMeta) {
self.block_metas = ::protobuf::SingularPtrField::some(v);
pub fn set_block_meta(&mut self, v: GridBlockMeta) {
self.block_meta = ::protobuf::SingularPtrField::some(v);
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_block_metas(&mut self) -> &mut GridBlockMeta {
if self.block_metas.is_none() {
self.block_metas.set_default();
pub fn mut_block_meta(&mut self) -> &mut GridBlockMeta {
if self.block_meta.is_none() {
self.block_meta.set_default();
}
self.block_metas.as_mut().unwrap()
self.block_meta.as_mut().unwrap()
}
// Take field
pub fn take_block_metas(&mut self) -> GridBlockMeta {
self.block_metas.take().unwrap_or_else(|| GridBlockMeta::new())
pub fn take_block_meta(&mut self) -> GridBlockMeta {
self.block_meta.take().unwrap_or_else(|| GridBlockMeta::new())
}
// .GridBlockMetaData block_meta_data = 3;
@ -3231,7 +3231,7 @@ impl ::protobuf::Message for BuildGridContext {
return false;
}
};
for v in &self.block_metas {
for v in &self.block_meta {
if !v.is_initialized() {
return false;
}
@ -3252,7 +3252,7 @@ impl ::protobuf::Message for BuildGridContext {
::protobuf::rt::read_repeated_message_into(wire_type, is, &mut self.field_metas)?;
},
2 => {
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.block_metas)?;
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.block_meta)?;
},
3 => {
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.block_meta_data)?;
@ -3273,7 +3273,7 @@ impl ::protobuf::Message for BuildGridContext {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
};
if let Some(ref v) = self.block_metas.as_ref() {
if let Some(ref v) = self.block_meta.as_ref() {
let len = v.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
}
@ -3292,7 +3292,7 @@ impl ::protobuf::Message for BuildGridContext {
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
};
if let Some(ref v) = self.block_metas.as_ref() {
if let Some(ref v) = self.block_meta.as_ref() {
os.write_tag(2, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?;
@ -3346,9 +3346,9 @@ impl ::protobuf::Message for BuildGridContext {
|m: &mut BuildGridContext| { &mut m.field_metas },
));
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<GridBlockMeta>>(
"block_metas",
|m: &BuildGridContext| { &m.block_metas },
|m: &mut BuildGridContext| { &mut m.block_metas },
"block_meta",
|m: &BuildGridContext| { &m.block_meta },
|m: &mut BuildGridContext| { &mut m.block_meta },
));
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<GridBlockMetaData>>(
"block_meta_data",
@ -3372,7 +3372,7 @@ impl ::protobuf::Message for BuildGridContext {
impl ::protobuf::Clear for BuildGridContext {
fn clear(&mut self) {
self.field_metas.clear();
self.block_metas.clear();
self.block_meta.clear();
self.block_meta_data.clear();
self.unknown_fields.clear();
}
@ -3453,26 +3453,26 @@ impl ::protobuf::reflect::ProtobufValue for FieldType {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\nmeta.proto\"x\n\x08GridMeta\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
\n\nmeta.proto\"o\n\x08GridMeta\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\
\x06gridId\x12\"\n\x06fields\x18\x02\x20\x03(\x0b2\n.FieldMetaR\x06field\
s\x12/\n\x0bblock_metas\x18\x03\x20\x03(\x0b2\x0e.GridBlockMetaR\nblockM\
etas\"o\n\rGridBlockMeta\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07bl\
ockId\x12&\n\x0fstart_row_index\x18\x02\x20\x01(\x05R\rstartRowIndex\x12\
\x1b\n\trow_count\x18\x03\x20\x01(\x05R\x08rowCount\"U\n\x11GridBlockMet\
aData\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12%\n\trow_m\
etas\x18\x02\x20\x03(\x0b2\x08.RowMetaR\x08rowMetas\"\xbc\x02\n\tFieldMe\
ta\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x12\n\x04name\x18\x02\
\x20\x01(\tR\x04name\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12)\
\n\nfield_type\x18\x04\x20\x01(\x0e2\n.FieldTypeR\tfieldType\x12\x16\n\
\x06frozen\x18\x05\x20\x01(\x08R\x06frozen\x12\x1e\n\nvisibility\x18\x06\
\x20\x01(\x08R\nvisibility\x12\x14\n\x05width\x18\x07\x20\x01(\x05R\x05w\
idth\x12>\n\x0ctype_options\x18\x08\x20\x03(\x0b2\x1b.FieldMeta.TypeOpti\
onsEntryR\x0btypeOptions\x1a>\n\x10TypeOptionsEntry\x12\x10\n\x03key\x18\
\x01\x20\x01(\tR\x03key\x12\x14\n\x05value\x18\x02\x20\x01(\tR\x05value:\
\x028\x01\"\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\x06\
gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04des\
c\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\
s\x12&\n\x06blocks\x18\x03\x20\x03(\x0b2\x0e.GridBlockMetaR\x06blocks\"o\
\n\rGridBlockMeta\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\
\x12&\n\x0fstart_row_index\x18\x02\x20\x01(\x05R\rstartRowIndex\x12\x1b\
\n\trow_count\x18\x03\x20\x01(\x05R\x08rowCount\"L\n\x11GridBlockMetaDat\
a\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12\x1c\n\x04rows\
\x18\x02\x20\x03(\x0b2\x08.RowMetaR\x04rows\"\xbc\x02\n\tFieldMeta\x12\
\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12\x12\n\x04name\x18\x02\x20\x01\
(\tR\x04name\x12\x12\n\x04desc\x18\x03\x20\x01(\tR\x04desc\x12)\n\nfield\
_type\x18\x04\x20\x01(\x0e2\n.FieldTypeR\tfieldType\x12\x16\n\x06frozen\
\x18\x05\x20\x01(\x08R\x06frozen\x12\x1e\n\nvisibility\x18\x06\x20\x01(\
\x08R\nvisibility\x12\x14\n\x05width\x18\x07\x20\x01(\x05R\x05width\x12>\
\n\x0ctype_options\x18\x08\x20\x03(\x0b2\x1b.FieldMeta.TypeOptionsEntryR\
\x0btypeOptions\x1a>\n\x10TypeOptionsEntry\x12\x10\n\x03key\x18\x01\x20\
\x01(\tR\x03key\x12\x14\n\x05value\x18\x02\x20\x01(\tR\x05value:\x028\
\x01\"\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\x06grid\
Id\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\nv\
isibility\x12\x16\n\x05width\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\
@ -3498,14 +3498,13 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x01\n\x11CellMetaChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06\
gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08fie\
ld_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\x20\x01(\
\tH\0R\x04dataB\r\n\x0bone_of_data\"\xac\x01\n\x10BuildGridContext\x12+\
\n\x0bfield_metas\x18\x01\x20\x03(\x0b2\n.FieldMetaR\nfieldMetas\x12/\n\
\x0bblock_metas\x18\x02\x20\x01(\x0b2\x0e.GridBlockMetaR\nblockMetas\x12\
:\n\x0fblock_meta_data\x18\x03\x20\x01(\x0b2\x12.GridBlockMetaDataR\rblo\
ckMetaData*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\
\tH\0R\x04dataB\r\n\x0bone_of_data\"\xaa\x01\n\x10BuildGridContext\x12+\
\n\x0bfield_metas\x18\x01\x20\x03(\x0b2\n.FieldMetaR\nfieldMetas\x12-\n\
\nblock_meta\x18\x02\x20\x01(\x0b2\x0e.GridBlockMetaR\tblockMeta\x12:\n\
\x0fblock_meta_data\x18\x03\x20\x01(\x0b2\x12.GridBlockMetaDataR\rblockM\
etaData*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;

View File

@ -57,6 +57,17 @@ message RepeatedGridBlock {
}
message GridBlockOrder {
string block_id = 1;
repeated RowOrder row_orders = 2;
}
message GridBlockOrderChangeset {
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;

View File

@ -3,7 +3,7 @@ syntax = "proto3";
message GridMeta {
string grid_id = 1;
repeated FieldMeta fields = 2;
repeated GridBlockMeta block_metas = 3;
repeated GridBlockMeta blocks = 3;
}
message GridBlockMeta {
string block_id = 1;
@ -12,7 +12,7 @@ message GridBlockMeta {
}
message GridBlockMetaData {
string block_id = 1;
repeated RowMeta row_metas = 2;
repeated RowMeta rows = 2;
}
message FieldMeta {
string id = 1;
@ -63,7 +63,7 @@ message CellMetaChangeset {
}
message BuildGridContext {
repeated FieldMeta field_metas = 1;
GridBlockMeta block_metas = 2;
GridBlockMeta block_meta = 2;
GridBlockMetaData block_meta_data = 3;
}
enum FieldType {

View File

@ -1,34 +1,16 @@
use flowy_grid_data_model::entities::*;
#[test]
fn grid_serde_test() {
let grid_id = "1".to_owned();
let fields = vec![create_field("1")];
let grid = GridMeta {
grid_id,
fields,
block_metas: vec![],
};
let grid_1_json = serde_json::to_string(&grid).unwrap();
let _: GridMeta = serde_json::from_str(&grid_1_json).unwrap();
assert_eq!(
grid_1_json,
r#"{"id":"1","fields":[{"id":"1","name":"Text Field","desc":"","field_type":"RichText","frozen":false,"visibility":true,"width":150,"type_options":{"type_id":"","value":[]}}],"blocks":[]}"#
)
}
#[test]
fn grid_default_serde_test() {
let grid_id = "1".to_owned();
let grid = GridMeta {
grid_id,
fields: vec![],
block_metas: vec![],
blocks: vec![],
};
let json = serde_json::to_string(&grid).unwrap();
assert_eq!(json, r#"{"id":"1","fields":[],"blocks":[]}"#)
assert_eq!(json, r#"{"grid_id":"1","fields":[],"blocks":[]}"#)
}
fn create_field(field_id: &str) -> FieldMeta {

View File

@ -5,6 +5,7 @@ use flowy_grid_data_model::entities::{CellMeta, GridBlockMetaData, RowMeta, RowM
use lib_infra::uuid;
use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::Arc;
@ -15,7 +16,7 @@ pub type GridBlockMetaDeltaBuilder = PlainTextDeltaBuilder;
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct GridBlockMetaPad {
block_id: String,
row_metas: Vec<Arc<RowMeta>>,
rows: Vec<Arc<RowMeta>>,
#[serde(skip)]
pub(crate) delta: GridBlockMetaDelta,
@ -30,16 +31,8 @@ impl GridBlockMetaPad {
CollaborateError::internal().context(msg)
})?;
let block_id = meta_data.block_id;
let rows = meta_data
.row_metas
.into_iter()
.map(Arc::new)
.collect::<Vec<Arc<RowMeta>>>();
Ok(Self {
block_id,
row_metas: rows,
delta,
})
let rows = meta_data.rows.into_iter().map(Arc::new).collect::<Vec<Arc<RowMeta>>>();
Ok(Self { block_id, rows, delta })
}
pub fn from_revisions(_grid_id: &str, revisions: Vec<Revision>) -> CollaborateResult<Self> {
@ -55,14 +48,11 @@ impl GridBlockMetaPad {
) -> CollaborateResult<Option<GridBlockMetaChange>> {
self.modify(|rows| {
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 == start_row_id) {
rows.insert(index + 1, Arc::new(row));
return Ok(Some(()));
if !start_row_id.is_empty() {
if let Some(index) = rows.iter().position(|row| row.id == start_row_id) {
rows.insert(index + 1, Arc::new(row));
return Ok(Some(()));
}
}
}
@ -71,38 +61,48 @@ impl GridBlockMetaPad {
})
}
pub fn delete_rows(&mut self, row_ids: &[String]) -> CollaborateResult<Option<GridBlockMetaChange>> {
pub fn delete_rows(&mut self, row_ids: Vec<Cow<'_, String>>) -> CollaborateResult<Option<GridBlockMetaChange>> {
self.modify(|rows| {
rows.retain(|row| !row_ids.contains(&row.id));
rows.retain(|row| !row_ids.contains(&Cow::Borrowed(&row.id)));
Ok(Some(()))
})
}
pub fn get_row_metas(&self, row_ids: &Option<Vec<String>>) -> CollaborateResult<Vec<Arc<RowMeta>>> {
pub fn get_row_metas<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> CollaborateResult<Vec<Arc<RowMeta>>>
where
T: AsRef<str> + ToOwned + ?Sized,
{
match row_ids {
None => Ok(self.row_metas.to_vec()),
None => Ok(self.rows.to_vec()),
Some(row_ids) => {
let row_map = self
.row_metas
.rows
.iter()
.map(|row| (&row.id, row.clone()))
.collect::<HashMap<&String, Arc<RowMeta>>>();
.map(|row| (row.id.as_str(), row.clone()))
.collect::<HashMap<&str, Arc<RowMeta>>>();
Ok(row_ids
.iter()
.flat_map(|row_id| match row_map.get(row_id) {
None => {
tracing::error!("Can't find the row with id: {}", row_id);
None
.flat_map(|row_id| {
let row_id = row_id.as_ref().as_ref();
match row_map.get(row_id) {
None => {
tracing::error!("Can't find the row with id: {}", row_id);
None
}
Some(row) => Some(row.clone()),
}
Some(row) => Some(row.clone()),
})
.collect::<Vec<_>>())
}
}
}
pub fn get_cell_metas(&self, field_id: &str, row_ids: &Option<Vec<String>>) -> CollaborateResult<Vec<CellMeta>> {
pub fn get_cell_metas(
&self,
field_id: &str,
row_ids: Option<Vec<Cow<'_, String>>>,
) -> CollaborateResult<Vec<CellMeta>> {
let rows = self.get_row_metas(row_ids)?;
let cell_metas = rows
.iter()
@ -115,7 +115,14 @@ impl GridBlockMetaPad {
}
pub fn number_of_rows(&self) -> i32 {
self.row_metas.len() as i32
self.rows.len() as i32
}
pub fn index_of_row(&self, row_id: &str) -> Option<i32> {
self.rows
.iter()
.position(|row| row.id == row_id)
.map(|index| index as i32)
}
pub fn update_row(&mut self, changeset: RowMetaChangeset) -> CollaborateResult<Option<GridBlockMetaChange>> {
@ -148,7 +155,7 @@ impl GridBlockMetaPad {
F: for<'a> FnOnce(&'a mut Vec<Arc<RowMeta>>) -> CollaborateResult<Option<()>>,
{
let cloned_self = self.clone();
match f(&mut self.row_metas)? {
match f(&mut self.rows)? {
None => Ok(None),
Some(_) => {
let old = cloned_self.to_json()?;
@ -215,13 +222,13 @@ impl std::default::Default for GridBlockMetaPad {
fn default() -> Self {
let block_meta_data = GridBlockMetaData {
block_id: uuid(),
row_metas: vec![],
rows: vec![],
};
let delta = make_block_meta_delta(&block_meta_data);
GridBlockMetaPad {
block_id: block_meta_data.block_id,
row_metas: block_meta_data.row_metas.into_iter().map(Arc::new).collect::<Vec<_>>(),
rows: block_meta_data.rows.into_iter().map(Arc::new).collect::<Vec<_>>(),
delta,
}
}
@ -231,6 +238,7 @@ impl std::default::Default for GridBlockMetaPad {
mod tests {
use crate::client_grid::{GridBlockMetaDelta, GridBlockMetaPad};
use flowy_grid_data_model::entities::{RowMeta, RowMetaChangeset};
use std::borrow::Cow;
#[test]
fn block_meta_add_row() {
@ -246,7 +254,7 @@ mod tests {
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}]"#
r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
);
}
@ -260,24 +268,24 @@ mod tests {
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}]"#
r#"[{"retain":24},{"insert":"{\"id\":\"1\",\"block_id\":\"1\",\"cells\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
);
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}]"#
r#"[{"retain":90},{"insert":",{\"id\":\"2\",\"block_id\":\"1\",\"cells\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
);
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}]"#
r#"[{"retain":157},{"insert":",{\"id\":\"3\",\"block_id\":\"1\",\"cells\":{},\"height\":0,\"visibility\":false}"},{"retain":2}]"#
);
assert_eq!(*pad.row_metas[0], row_1);
assert_eq!(*pad.row_metas[1], row_3);
assert_eq!(*pad.row_metas[2], row_2);
assert_eq!(*pad.rows[0], row_1);
assert_eq!(*pad.rows[1], row_2);
assert_eq!(*pad.rows[2], row_3);
}
fn test_row_meta(id: &str, pad: &GridBlockMetaPad) -> RowMeta {
@ -301,9 +309,9 @@ mod tests {
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);
assert_eq!(*pad.row_metas[2], row_2);
assert_eq!(*pad.rows[0], row_1);
assert_eq!(*pad.rows[1], row_3);
assert_eq!(*pad.rows[2], row_2);
}
#[test]
@ -317,9 +325,9 @@ mod tests {
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);
assert_eq!(*pad.row_metas[2], row_2);
assert_eq!(*pad.rows[0], row_1);
assert_eq!(*pad.rows[1], row_2);
assert_eq!(*pad.rows[2], row_3);
}
#[test]
@ -335,10 +343,10 @@ mod tests {
};
let _ = pad.add_row_meta(row.clone(), None).unwrap().unwrap();
let change = pad.delete_rows(&[row.id]).unwrap().unwrap();
let change = pad.delete_rows(vec![Cow::Borrowed(&row.id)]).unwrap().unwrap();
assert_eq!(
change.delta.to_delta_str(),
r#"[{"retain":29},{"delete":77},{"retain":2}]"#
r#"[{"retain":24},{"delete":66},{"retain":2}]"#
);
assert_eq!(pad.delta_str(), pre_delta_str);
@ -367,18 +375,17 @@ mod tests {
assert_eq!(
change.delta.to_delta_str(),
r#"[{"retain":85},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"#
r#"[{"retain":69},{"insert":"10"},{"retain":15},{"insert":"tru"},{"delete":4},{"retain":4}]"#
);
assert_eq!(
pad.to_json().unwrap(),
r#"{"block_id":"1","row_metas":[{"id":"1","block_id":"1","cell_by_field_id":{},"height":100,"visibility":true}]}"#
r#"{"block_id":"1","rows":[{"id":"1","block_id":"1","cells":{},"height":100,"visibility":true}]}"#
);
}
fn test_pad() -> GridBlockMetaPad {
let delta =
GridBlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"row_metas\":[]}"}]"#).unwrap();
let delta = GridBlockMetaDelta::from_delta_str(r#"[{"insert":"{\"block_id\":\"1\",\"rows\":[]}"}]"#).unwrap();
GridBlockMetaPad::from_delta(delta).unwrap()
}
}

View File

@ -13,9 +13,9 @@ impl GridBuilder {
}
pub fn add_empty_row(mut self) -> Self {
let row = RowMeta::new(&self.build_context.block_metas.block_id);
self.build_context.block_meta_data.row_metas.push(row);
self.build_context.block_metas.row_count += 1;
let row = RowMeta::new(&self.build_context.block_meta.block_id);
self.build_context.block_meta_data.rows.push(row);
self.build_context.block_meta.row_count += 1;
self
}
@ -57,7 +57,7 @@ mod tests {
let grid_meta = GridMeta {
grid_id,
fields: build_context.field_metas,
block_metas: vec![build_context.block_metas],
blocks: vec![build_context.block_meta],
};
let grid_meta_delta = make_grid_delta(&grid_meta);

View File

@ -235,12 +235,12 @@ impl GridMetaPad {
pub fn create_block_meta(&mut self, block: GridBlockMeta) -> CollaborateResult<Option<GridChangeset>> {
self.modify_grid(|grid_meta| {
if grid_meta.block_metas.iter().any(|b| b.block_id == block.block_id) {
if grid_meta.blocks.iter().any(|b| b.block_id == block.block_id) {
tracing::warn!("Duplicate grid block");
Ok(None)
} else {
match grid_meta.block_metas.last() {
None => grid_meta.block_metas.push(block),
match grid_meta.blocks.last() {
None => grid_meta.blocks.push(block),
Some(last_block) => {
if last_block.start_row_index > block.start_row_index
&& last_block.len() > block.start_row_index
@ -248,7 +248,7 @@ impl GridMetaPad {
let msg = "GridBlock's start_row_index should be greater than the last_block's start_row_index and its len".to_string();
return Err(CollaborateError::internal().context(msg))
}
grid_meta.block_metas.push(block);
grid_meta.blocks.push(block);
}
}
Ok(Some(()))
@ -257,7 +257,7 @@ impl GridMetaPad {
}
pub fn get_block_metas(&self) -> Vec<GridBlockMeta> {
self.grid_meta.block_metas.clone()
self.grid_meta.blocks.clone()
}
pub fn update_block_meta(&mut self, changeset: GridBlockMetaChangeset) -> CollaborateResult<Option<GridChangeset>> {
@ -320,19 +320,15 @@ impl GridMetaPad {
where
F: FnOnce(&mut GridBlockMeta) -> CollaborateResult<Option<()>>,
{
self.modify_grid(|grid_meta| {
match grid_meta
.block_metas
.iter()
.position(|block| block.block_id == block_id)
{
self.modify_grid(
|grid_meta| match grid_meta.blocks.iter().position(|block| block.block_id == block_id) {
None => {
tracing::warn!("[GridMetaPad]: Can't find any block with id: {}", block_id);
Ok(None)
}
Some(index) => f(&mut grid_meta.block_metas[index]),
}
})
Some(index) => f(&mut grid_meta.blocks[index]),
},
)
}
pub fn modify_field<F>(&mut self, field_id: &str, f: F) -> CollaborateResult<Option<GridChangeset>>
@ -380,7 +376,7 @@ impl std::default::Default for GridMetaPad {
let grid = GridMeta {
grid_id: uuid(),
fields: vec![],
block_metas: vec![],
blocks: vec![],
};
let delta = make_grid_delta(&grid);
GridMetaPad {