From 13cb7eeb249c8f4ca58babc52d4e48e49b3c2d24 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 9 May 2022 13:23:03 +0800 Subject: [PATCH 01/14] chore: add get type option data handler --- .../application/grid/cell/cell_service.dart | 14 +- .../grid/cell/selection_editor_bloc.dart | 3 - .../widgets/header/field_editor_pannel.dart | 12 +- .../dart_event/flowy-grid/dart_event.dart | 17 ++ .../flowy-grid-data-model/grid.pb.dart | 61 ++++ .../flowy-grid-data-model/grid.pbjson.dart | 11 + .../protobuf/flowy-grid/event_map.pbenum.dart | 2 + .../protobuf/flowy-grid/event_map.pbjson.dart | 3 +- .../rust-lib/flowy-grid/src/event_handler.rs | 35 ++- frontend/rust-lib/flowy-grid/src/event_map.rs | 4 + .../src/protobuf/model/event_map.rs | 16 +- .../src/protobuf/proto/event_map.proto | 1 + .../src/services/row/cell_data_operation.rs | 1 - .../flowy-grid/src/services/row/row_loader.rs | 1 - .../src/entities/grid.rs | 9 + .../src/entities/meta.rs | 4 +- .../src/protobuf/model/grid.rs | 269 +++++++++++++++--- .../src/protobuf/proto/grid.proto | 4 + .../src/client_grid/grid_meta_pad.rs | 2 +- 19 files changed, 399 insertions(+), 70 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index 5b19a48d9c..21a40a5a5b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -59,15 +59,15 @@ class GridCellContextBuilder { } // ignore: must_be_immutable -class GridCellContext extends Equatable { +class GridCellContext extends Equatable { final GridCell gridCell; final GridCellCache cellCache; final GridCellCacheKey _cacheKey; - final GridCellDataLoader cellDataLoader; + final GridCellDataLoader cellDataLoader; final CellService _cellService = CellService(); late final CellListener _cellListener; - late final ValueNotifier _cellDataNotifier; + late final ValueNotifier _cellDataNotifier; bool isListening = false; VoidCallback? _onFieldChangedFn; Timer? _delayOperation; @@ -78,7 +78,7 @@ class GridCellContext extends Equatable { required this.cellDataLoader, }) : _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id); - GridCellContext clone() { + GridCellContext clone() { return GridCellContext( gridCell: gridCell, cellDataLoader: cellDataLoader, @@ -100,7 +100,7 @@ class GridCellContext extends Equatable { GridCellCacheKey get cacheKey => _cacheKey; - VoidCallback? startListening({required void Function(T) onCellChanged}) { + VoidCallback? startListening({required void Function(C) onCellChanged}) { if (isListening) { Log.error("Already started. It seems like you should call clone first"); return null; @@ -125,7 +125,7 @@ class GridCellContext extends Equatable { onCellChangedFn() { final value = _cellDataNotifier.value; - if (value is T) { + if (value is C) { onCellChanged(value); } @@ -142,7 +142,7 @@ class GridCellContext extends Equatable { _cellDataNotifier.removeListener(fn); } - T? getCellData() { + C? getCellData() { final data = cellCache.get(cacheKey); if (data == null) { _loadData(); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index a6cd154d7d..cefa0153a7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -1,13 +1,10 @@ import 'dart:async'; - import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; - import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; - import 'select_option_service.dart'; part 'selection_editor_bloc.freezed.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart index 1258847520..fe00fe45a6 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart @@ -119,14 +119,12 @@ class _FieldEditorPannelState extends State { context.read().add(FieldEditorPannelEvent.didUpdateTypeOptionData(data)); }); - final typeOptionContext = TypeOptionContext( - gridId: state.gridId, - field: state.field, - data: state.typeOptionData, - ); - final builder = _makeTypeOptionBuild( - typeOptionContext: typeOptionContext, + typeOptionContext: TypeOptionContext( + gridId: state.gridId, + field: state.field, + data: state.typeOptionData, + ), overlayDelegate: overlayDelegate, dataDelegate: dataDelegate, ); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart index 9f87c2ad26..75ebc7cfa9 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart @@ -171,6 +171,23 @@ class GridEventMoveItem { } } +class GridEventGetFieldTypeOption { + GetEditFieldContextPayload request; + GridEventGetFieldTypeOption(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetFieldTypeOption.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(FieldTypeOptionData.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + class GridEventNewSelectOption { CreateSelectOptionPayload request; GridEventNewSelectOption(this.request); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart index 30324be776..06685ebf9e 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart @@ -642,6 +642,67 @@ class EditFieldContext extends $pb.GeneratedMessage { void clearTypeOptionData() => clearField(3); } +class FieldTypeOptionData extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'FieldTypeOptionData', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptionData', $pb.PbFieldType.OY) + ..hasRequiredFields = false + ; + + FieldTypeOptionData._() : super(); + factory FieldTypeOptionData({ + $core.String? fieldId, + $core.List<$core.int>? typeOptionData, + }) { + final _result = create(); + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (typeOptionData != null) { + _result.typeOptionData = typeOptionData; + } + return _result; + } + factory FieldTypeOptionData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory FieldTypeOptionData.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') + FieldTypeOptionData clone() => FieldTypeOptionData()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + FieldTypeOptionData copyWith(void Function(FieldTypeOptionData) updates) => super.copyWith((message) => updates(message as FieldTypeOptionData)) as FieldTypeOptionData; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static FieldTypeOptionData create() => FieldTypeOptionData._(); + FieldTypeOptionData createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static FieldTypeOptionData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static FieldTypeOptionData? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get fieldId => $_getSZ(0); + @$pb.TagNumber(1) + set fieldId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasFieldId() => $_has(0); + @$pb.TagNumber(1) + void clearFieldId() => clearField(1); + + @$pb.TagNumber(2) + $core.List<$core.int> get typeOptionData => $_getN(1); + @$pb.TagNumber(2) + set typeOptionData($core.List<$core.int> v) { $_setBytes(1, v); } + @$pb.TagNumber(2) + $core.bool hasTypeOptionData() => $_has(1); + @$pb.TagNumber(2) + void clearTypeOptionData() => clearField(2); +} + class RepeatedField extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'RepeatedField', createEmptyInstance: create) ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'items', $pb.PbFieldType.PM, subBuilder: Field.create) diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart index 8ec90dddf9..ae8a01e87b 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart @@ -136,6 +136,17 @@ const EditFieldContext$json = const { /// Descriptor for `EditFieldContext`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List editFieldContextDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRDb250ZXh0EhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIlCgpncmlkX2ZpZWxkGAIgASgLMgYuRmllbGRSCWdyaWRGaWVsZBIoChB0eXBlX29wdGlvbl9kYXRhGAMgASgMUg50eXBlT3B0aW9uRGF0YQ=='); +@$core.Deprecated('Use fieldTypeOptionDataDescriptor instead') +const FieldTypeOptionData$json = const { + '1': 'FieldTypeOptionData', + '2': const [ + const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'type_option_data', '3': 2, '4': 1, '5': 12, '10': 'typeOptionData'}, + ], +}; + +/// Descriptor for `FieldTypeOptionData`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List fieldTypeOptionDataDescriptor = $convert.base64Decode('ChNGaWVsZFR5cGVPcHRpb25EYXRhEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEigKEHR5cGVfb3B0aW9uX2RhdGEYAiABKAxSDnR5cGVPcHRpb25EYXRh'); @$core.Deprecated('Use repeatedFieldDescriptor instead') const RepeatedField$json = const { '1': 'RepeatedField', diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart index 4c898182c7..b907873844 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart @@ -20,6 +20,7 @@ class GridEvent extends $pb.ProtobufEnum { static const GridEvent DuplicateField = GridEvent._(15, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField'); static const GridEvent GetEditFieldContext = GridEvent._(16, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetEditFieldContext'); static const GridEvent MoveItem = GridEvent._(17, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem'); + static const GridEvent GetFieldTypeOption = GridEvent._(18, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFieldTypeOption'); static const GridEvent NewSelectOption = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewSelectOption'); static const GridEvent GetSelectOptionContext = GridEvent._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetSelectOptionContext'); static const GridEvent UpdateSelectOption = GridEvent._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOption'); @@ -42,6 +43,7 @@ class GridEvent extends $pb.ProtobufEnum { DuplicateField, GetEditFieldContext, MoveItem, + GetFieldTypeOption, NewSelectOption, GetSelectOptionContext, UpdateSelectOption, diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart index b03ea1cc64..9d63053af5 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart @@ -22,6 +22,7 @@ const GridEvent$json = const { const {'1': 'DuplicateField', '2': 15}, const {'1': 'GetEditFieldContext', '2': 16}, const {'1': 'MoveItem', '2': 17}, + const {'1': 'GetFieldTypeOption', '2': 18}, const {'1': 'NewSelectOption', '2': 30}, const {'1': 'GetSelectOptionContext', '2': 31}, const {'1': 'UpdateSelectOption', '2': 32}, @@ -36,4 +37,4 @@ const GridEvent$json = const { }; /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtJbnNlcnRGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEQoNU3dpdGNoVG9GaWVsZBAOEhIKDkR1cGxpY2F0ZUZpZWxkEA8SFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAQEgwKCE1vdmVJdGVtEBESEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlQ2VsbFNlbGVjdE9wdGlvbhBI'); +final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtJbnNlcnRGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEQoNU3dpdGNoVG9GaWVsZBAOEhIKDkR1cGxpY2F0ZUZpZWxkEA8SFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAQEgwKCE1vdmVJdGVtEBESFgoSR2V0RmllbGRUeXBlT3B0aW9uEBISEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlQ2VsbFNlbGVjdE9wdGlvbhBI'); diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 2ef933f039..eb6d2ef5ba 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -128,6 +128,22 @@ pub(crate) async fn get_field_context_handler( data_result(edit_context) } +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_field_type_option_data_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params = data.into_inner(); + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let field_meta = get_or_create_field_meta(params.field_id, ¶ms.field_type, editor).await?; + let type_option_data = get_type_option_data(&field_meta, &field_meta.field_type).await?; + + data_result(FieldTypeOptionData { + field_id: field_meta.id.clone(), + type_option_data, + }) +} + #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn move_item_handler( data: Data, @@ -147,12 +163,7 @@ async fn make_field_edit_context( field_meta: Option, ) -> FlowyResult { let field_meta = field_meta.unwrap_or(get_or_create_field_meta(field_id, &field_type, editor).await?); - let s = field_meta - .get_type_option_str(None) - .unwrap_or_else(|| default_type_option_builder_from_type(&field_type).entry().json_str()); - - let builder = type_option_builder_from_json_str(&s, &field_meta.field_type); - let type_option_data = builder.entry().protobuf_bytes().to_vec(); + let type_option_data = get_type_option_data(&field_meta, &field_type).await?; let field: Field = field_meta.into(); Ok(EditFieldContext { grid_id: grid_id.to_string(), @@ -161,6 +172,16 @@ async fn make_field_edit_context( }) } +async fn get_type_option_data(field_meta: &FieldMeta, field_type: &FieldType) -> FlowyResult> { + let s = field_meta + .get_type_option_str(&field_type) + .unwrap_or_else(|| default_type_option_builder_from_type(&field_type).entry().json_str()); + let builder = type_option_builder_from_json_str(&s, &field_meta.field_type); + let type_option_data = builder.entry().protobuf_bytes().to_vec(); + + Ok(type_option_data) +} + async fn get_or_create_field_meta( field_id: Option, field_type: &FieldType, @@ -221,7 +242,7 @@ pub(crate) async fn create_row_handler( Ok(()) } -#[tracing::instrument(level = "debug", skip_all, err)] +// #[tracing::instrument(level = "debug", skip_all, err)] pub(crate) async fn get_cell_handler( data: Data, manager: AppData>, diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index 46513a43c9..4262bbe2f0 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -19,6 +19,7 @@ pub fn create(grid_manager: Arc) -> Module { .event(GridEvent::DuplicateField, duplicate_field_handler) .event(GridEvent::GetEditFieldContext, get_field_context_handler) .event(GridEvent::MoveItem, move_item_handler) + .event(GridEvent::GetFieldTypeOption, get_field_type_option_data_handler) // Row .event(GridEvent::CreateRow, create_row_handler) .event(GridEvent::GetRow, get_row_handler) @@ -69,6 +70,9 @@ pub enum GridEvent { #[event(input = "MoveItemPayload")] MoveItem = 17, + #[event(input = "GetEditFieldContextPayload", output = "FieldTypeOptionData")] + GetFieldTypeOption = 18, + #[event(input = "CreateSelectOptionPayload", output = "SelectOption")] NewSelectOption = 30, diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs index b4792931ae..739f8d9767 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs @@ -35,6 +35,7 @@ pub enum GridEvent { DuplicateField = 15, GetEditFieldContext = 16, MoveItem = 17, + GetFieldTypeOption = 18, NewSelectOption = 30, GetSelectOptionContext = 31, UpdateSelectOption = 32, @@ -64,6 +65,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { 15 => ::std::option::Option::Some(GridEvent::DuplicateField), 16 => ::std::option::Option::Some(GridEvent::GetEditFieldContext), 17 => ::std::option::Option::Some(GridEvent::MoveItem), + 18 => ::std::option::Option::Some(GridEvent::GetFieldTypeOption), 30 => ::std::option::Option::Some(GridEvent::NewSelectOption), 31 => ::std::option::Option::Some(GridEvent::GetSelectOptionContext), 32 => ::std::option::Option::Some(GridEvent::UpdateSelectOption), @@ -90,6 +92,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { GridEvent::DuplicateField, GridEvent::GetEditFieldContext, GridEvent::MoveItem, + GridEvent::GetFieldTypeOption, GridEvent::NewSelectOption, GridEvent::GetSelectOptionContext, GridEvent::UpdateSelectOption, @@ -128,16 +131,17 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\xfd\x02\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ + \n\x0fevent_map.proto*\x95\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\ \x0bUpdateField\x10\x0b\x12\x0f\n\x0bInsertField\x10\x0c\x12\x0f\n\x0bDe\ leteField\x10\r\x12\x11\n\rSwitchToField\x10\x0e\x12\x12\n\x0eDuplicateF\ ield\x10\x0f\x12\x17\n\x13GetEditFieldContext\x10\x10\x12\x0c\n\x08MoveI\ - tem\x10\x11\x12\x13\n\x0fNewSelectOption\x10\x1e\x12\x1a\n\x16GetSelectO\ - ptionContext\x10\x1f\x12\x16\n\x12UpdateSelectOption\x10\x20\x12\r\n\tCr\ - eateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteRow\x104\x12\x10\n\ - \x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\nUpdateCell\ - \x10G\x12\x1a\n\x16UpdateCellSelectOption\x10Hb\x06proto3\ + tem\x10\x11\x12\x16\n\x12GetFieldTypeOption\x10\x12\x12\x13\n\x0fNewSele\ + ctOption\x10\x1e\x12\x1a\n\x16GetSelectOptionContext\x10\x1f\x12\x16\n\ + \x12UpdateSelectOption\x10\x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\ + \x103\x12\r\n\tDeleteRow\x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\ + \x07GetCell\x10F\x12\x0e\n\nUpdateCell\x10G\x12\x1a\n\x16UpdateCellSelec\ + tOption\x10Hb\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto index 7f45db5761..233de825a2 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto @@ -11,6 +11,7 @@ enum GridEvent { DuplicateField = 15; GetEditFieldContext = 16; MoveItem = 17; + GetFieldTypeOption = 18; NewSelectOption = 30; GetSelectOptionContext = 31; UpdateSelectOption = 32; diff --git a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs index 7384173b60..9d92de574e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs @@ -121,7 +121,6 @@ pub fn apply_cell_data_changeset>( // Ok(s) // } -#[tracing::instrument(level = "trace", skip(field_meta, data), fields(content))] pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &FieldType) -> Option { let s = match field_type { FieldType::RichText => field_meta diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs index 93b40f4d51..b4cb0476ef 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs @@ -36,7 +36,6 @@ pub fn make_cell_by_field_id( Some((field_id, cell)) } -#[allow(dead_code)] pub fn make_cell(field_id: &str, field_meta: &FieldMeta, row_meta: &RowMeta) -> Option { let cell_meta = row_meta.cells.get(field_id)?.clone(); let content = decode_cell_data(cell_meta.data, field_meta, &field_meta.field_type)?; diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs index c2f6d3841b..b742508f7c 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -206,6 +206,15 @@ pub struct EditFieldContext { pub type_option_data: Vec, } +#[derive(Debug, Default, ProtoBuf)] +pub struct FieldTypeOptionData { + #[pb(index = 1)] + pub field_id: String, + + #[pb(index = 2)] + pub type_option_data: Vec, +} + #[derive(Debug, Default, ProtoBuf)] pub struct RepeatedField { #[pb(index = 1)] diff --git a/shared-lib/flowy-grid-data-model/src/entities/meta.rs b/shared-lib/flowy-grid-data-model/src/entities/meta.rs index d5570a58e5..328b368fbc 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/meta.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/meta.rs @@ -95,7 +95,6 @@ pub struct FieldMeta { pub width: i32, - // #[pb(index = 8)] /// type_options contains key/value pairs /// key: id of the FieldType /// value: type option data that can be parsed into specified TypeOptionStruct. @@ -144,8 +143,7 @@ impl FieldMeta { self.type_options.insert(field_type.type_id(), json_str); } - pub fn get_type_option_str(&self, field_type: Option) -> Option { - let field_type = field_type.as_ref().unwrap_or(&self.field_type); + pub fn get_type_option_str(&self, field_type: &FieldType) -> Option { self.type_options.get(&field_type.type_id()).map(|s| s.to_owned()) } } diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs index ccf489b8fd..d6f4c9f21a 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs @@ -2130,6 +2130,207 @@ impl ::protobuf::reflect::ProtobufValue for EditFieldContext { } } +#[derive(PartialEq,Clone,Default)] +pub struct FieldTypeOptionData { + // message fields + pub field_id: ::std::string::String, + pub type_option_data: ::std::vec::Vec, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a FieldTypeOptionData { + fn default() -> &'a FieldTypeOptionData { + ::default_instance() + } +} + +impl FieldTypeOptionData { + pub fn new() -> FieldTypeOptionData { + ::std::default::Default::default() + } + + // string field_id = 1; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // bytes type_option_data = 2; + + + pub fn get_type_option_data(&self) -> &[u8] { + &self.type_option_data + } + pub fn clear_type_option_data(&mut self) { + self.type_option_data.clear(); + } + + // Param is passed by value, moved + pub fn set_type_option_data(&mut self, v: ::std::vec::Vec) { + self.type_option_data = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_type_option_data(&mut self) -> &mut ::std::vec::Vec { + &mut self.type_option_data + } + + // Take field + pub fn take_type_option_data(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.type_option_data, ::std::vec::Vec::new()) + } +} + +impl ::protobuf::Message for FieldTypeOptionData { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.type_option_data)?; + }, + _ => { + ::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.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.field_id); + } + if !self.type_option_data.is_empty() { + my_size += ::protobuf::rt::bytes_size(2, &self.type_option_data); + } + 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.field_id.is_empty() { + os.write_string(1, &self.field_id)?; + } + if !self.type_option_data.is_empty() { + os.write_bytes(2, &self.type_option_data)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> FieldTypeOptionData { + FieldTypeOptionData::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>( + "field_id", + |m: &FieldTypeOptionData| { &m.field_id }, + |m: &mut FieldTypeOptionData| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "type_option_data", + |m: &FieldTypeOptionData| { &m.type_option_data }, + |m: &mut FieldTypeOptionData| { &mut m.type_option_data }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "FieldTypeOptionData", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static FieldTypeOptionData { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(FieldTypeOptionData::new) + } +} + +impl ::protobuf::Clear for FieldTypeOptionData { + fn clear(&mut self) { + self.field_id.clear(); + self.type_option_data.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for FieldTypeOptionData { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for FieldTypeOptionData { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct RepeatedField { // message fields @@ -7733,39 +7934,41 @@ static file_descriptor_proto_data: &'static [u8] = b"\ e\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldType\"|\n\x10EditFieldContext\ \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngrid_field\ \x18\x02\x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\x10type_option_data\ - \x18\x03\x20\x01(\x0cR\x0etypeOptionData\"-\n\rRepeatedField\x12\x1c\n\ - \x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12RepeatedFiel\ - dOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05items\"T\ - \n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\x12\x19\ - \n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06height\x18\ - \x03\x20\x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\x01\ - \x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\x17.\ - Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\x20\ - \x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\x18\ - \x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05.Cel\ - lR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\x20\ - \x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05item\ - s\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\x12\ - \x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\x18\ - \x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\x12&\n\tro\ - w_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05index\ - \x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"Q\n\x0fUpdate\ - dRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrde\ - r\x12\x16\n\x03row\x18\x02\x20\x01(\x0b2\x04.RowR\x03row\"\xc6\x01\n\x11\ - GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\ - \x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cinser\ - tedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bdele\ - tedRows\x123\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\x10.UpdatedRowOrder\ - R\x0bupdatedRows\"E\n\tGridBlock\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02\ - id\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\";\n\ - \x04Cell\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\ - \x07content\x18\x02\x20\x01(\tR\x07content\"+\n\x0cRepeatedCell\x12\x1b\ - \n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateGridP\ - ayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06GridId\ - \x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\x12\ - \x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayload\ - \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_row\ - _id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\ + \x18\x03\x20\x01(\x0cR\x0etypeOptionData\"Z\n\x13FieldTypeOptionData\x12\ + \x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12(\n\x10type_option_\ + data\x18\x02\x20\x01(\x0cR\x0etypeOptionData\"-\n\rRepeatedField\x12\x1c\ + \n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12RepeatedFi\ + eldOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05items\ + \"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\x12\ + \x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06height\ + \x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\ + \x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\ + \x17.Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\ + \x20\x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\ + \x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05\ + .CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\ + \x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05\ + items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\ + \x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\ + \x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\x12&\n\ + \trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05i\ + ndex\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"Q\n\x0fUp\ + datedRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08row\ + Order\x12\x16\n\x03row\x18\x02\x20\x01(\x0b2\x04.RowR\x03row\"\xc6\x01\n\ + \x11GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07block\ + Id\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cins\ + ertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bde\ + letedRows\x123\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\x10.UpdatedRowOrd\ + erR\x0bupdatedRows\"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\"+\n\x0cRepeatedCell\x12\ + \x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateG\ + ridPayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06Grid\ + Id\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\ + \x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayloa\ + d\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_ro\ + w_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\ \xb6\x01\n\x12InsertFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\t\ R\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\ \x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\ diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto index 5d72f77302..ccfd8e58bb 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto +++ b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto @@ -43,6 +43,10 @@ message EditFieldContext { Field grid_field = 2; bytes type_option_data = 3; } +message FieldTypeOptionData { + string field_id = 1; + bytes type_option_data = 2; +} message RepeatedField { repeated Field items = 1; } diff --git a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs index bda9e056ca..791648cf14 100644 --- a/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs +++ b/shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs @@ -118,7 +118,7 @@ impl GridMetaPad { Ok(None) } Some(field_meta) => { - if field_meta.get_type_option_str(Some(field_type.clone())).is_none() { + if field_meta.get_type_option_str(&field_type).is_none() { let type_option_json = type_option_json_builder(&field_type); field_meta.insert_type_option_str(&field_type, type_option_json); } From f21ca6c52a50bdf2d86075a13713eaeb7ab8fb4c Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 9 May 2022 14:59:26 +0800 Subject: [PATCH 02/14] refactor: CellCalendar with bloc --- .../app_flowy/lib/startup/deps_resolver.dart | 4 +- .../application/grid/cell/cell_service.dart | 38 +-- .../application/grid/cell/date_cal_bloc.dart | 95 ++++++++ .../application/grid/cell/date_cell_bloc.dart | 2 - .../grid/field/field_action_sheet_bloc.dart | 12 +- .../grid/field/field_cell_bloc.dart | 4 +- .../grid/field/field_editor_bloc.dart | 13 +- .../application/grid/field/field_service.dart | 47 ++-- .../application/grid/grid_header_bloc.dart | 11 +- .../grid/setting/property_bloc.dart | 7 +- .../grid/src/widgets/cell/cell_builder.dart | 2 +- .../grid/src/widgets/cell/date_cell.dart | 217 ----------------- .../src/widgets/cell/date_cell/calendar.dart | 139 +++++++++++ .../src/widgets/cell/date_cell/date_cell.dart | 90 +++++++ .../grid/src/widgets/cell/prelude.dart | 2 +- .../dart_event/flowy-grid/dart_event.dart | 4 +- .../flowy-grid-data-model/grid.pb.dart | 13 ++ .../flowy-grid-data-model/grid.pbjson.dart | 7 +- .../rust-lib/flowy-grid/src/event_handler.rs | 33 ++- frontend/rust-lib/flowy-grid/src/event_map.rs | 4 +- .../src/entities/grid.rs | 10 +- .../src/protobuf/model/grid.rs | 221 +++++++++++------- .../src/protobuf/proto/grid.proto | 2 +- 23 files changed, 575 insertions(+), 402 deletions(-) create mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart delete mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 76b694542b..976665c8cb 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -153,13 +153,13 @@ void _resolveGridDeps(GetIt getIt) { getIt.registerFactoryParam( (data, _) => FieldActionSheetBloc( field: data.field, - service: FieldService(gridId: data.gridId), + fieldService: FieldService(gridId: data.gridId, fieldId: data.field.id), ), ); getIt.registerFactoryParam( (gridId, fieldLoader) => FieldEditorBloc( - service: FieldService(gridId: gridId), + gridId: gridId, fieldLoader: fieldLoader, ), ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index 21a40a5a5b..06cfa8c0e9 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:collection'; import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:dartz/dartz.dart'; import 'package:equatable/equatable.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; @@ -12,7 +13,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; - import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; part 'cell_service.freezed.dart'; @@ -59,15 +59,16 @@ class GridCellContextBuilder { } // ignore: must_be_immutable -class GridCellContext extends Equatable { +class GridCellContext extends Equatable { final GridCell gridCell; final GridCellCache cellCache; final GridCellCacheKey _cacheKey; - final GridCellDataLoader cellDataLoader; + final GridCellDataLoader cellDataLoader; final CellService _cellService = CellService(); + final FieldService _fieldService; late final CellListener _cellListener; - late final ValueNotifier _cellDataNotifier; + late final ValueNotifier _cellDataNotifier; bool isListening = false; VoidCallback? _onFieldChangedFn; Timer? _delayOperation; @@ -76,9 +77,10 @@ class GridCellContext extends Equatable { required this.gridCell, required this.cellCache, required this.cellDataLoader, - }) : _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id); + }) : _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), + _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id); - GridCellContext clone() { + GridCellContext clone() { return GridCellContext( gridCell: gridCell, cellDataLoader: cellDataLoader, @@ -98,16 +100,14 @@ class GridCellContext extends Equatable { FieldType get fieldType => gridCell.field.fieldType; - GridCellCacheKey get cacheKey => _cacheKey; - - VoidCallback? startListening({required void Function(C) onCellChanged}) { + VoidCallback? startListening({required void Function(T) onCellChanged}) { if (isListening) { Log.error("Already started. It seems like you should call clone first"); return null; } isListening = true; - _cellDataNotifier = ValueNotifier(cellCache.get(cacheKey)); + _cellDataNotifier = ValueNotifier(cellCache.get(_cacheKey)); _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); _cellListener.start(onCellChanged: (result) { result.fold( @@ -120,12 +120,12 @@ class GridCellContext extends Equatable { _onFieldChangedFn = () { _loadData(); }; - cellCache.addListener(cacheKey, _onFieldChangedFn!); + cellCache.addListener(_cacheKey, _onFieldChangedFn!); } onCellChangedFn() { final value = _cellDataNotifier.value; - if (value is C) { + if (value is T) { onCellChanged(value); } @@ -142,14 +142,18 @@ class GridCellContext extends Equatable { _cellDataNotifier.removeListener(fn); } - C? getCellData() { - final data = cellCache.get(cacheKey); + T? getCellData() { + final data = cellCache.get(_cacheKey); if (data == null) { _loadData(); } return data; } + Future, FlowyError>> getTypeOptionData() { + return _fieldService.getTypeOptionData(fieldType: fieldType); + } + void saveCellData(String data) { _cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data).then((result) { result.fold((l) => null, (err) => Log.error(err)); @@ -161,7 +165,7 @@ class GridCellContext extends Equatable { _delayOperation = Timer(const Duration(milliseconds: 10), () { cellDataLoader.loadData().then((data) { _cellDataNotifier.value = data; - cellCache.insert(GridCellCacheData(key: cacheKey, object: data)); + cellCache.insert(GridCellCacheData(key: _cacheKey, object: data)); }); }); } @@ -170,13 +174,13 @@ class GridCellContext extends Equatable { _delayOperation?.cancel(); if (_onFieldChangedFn != null) { - cellCache.removeListener(cacheKey, _onFieldChangedFn!); + cellCache.removeListener(_cacheKey, _onFieldChangedFn!); _onFieldChangedFn = null; } } @override - List get props => [cellCache.get(cacheKey) ?? "", cellId]; + List get props => [cellCache.get(_cacheKey) ?? "", cellId]; } abstract class GridCellDataLoader { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart new file mode 100644 index 0000000000..2214ddb875 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -0,0 +1,95 @@ +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'dart:async'; +import 'cell_service.dart'; +import 'package:dartz/dartz.dart'; +part 'date_cal_bloc.freezed.dart'; + +class DateCalBloc extends Bloc { + final GridDefaultCellContext cellContext; + void Function()? _onCellChangedFn; + + DateCalBloc({required this.cellContext}) : super(DateCalState.initial(cellContext)) { + on( + (event, emit) async { + event.map( + initial: (_Initial value) { + _startListening(); + }, + selectDay: (_SelectDay value) { + if (!isSameDay(state.selectedDay, value.day)) { + _updateCellData(value.day); + emit(state.copyWith(selectedDay: value.day)); + } + }, + setFormat: (_CalendarFormat value) { + emit(state.copyWith(format: value.format)); + }, + setFocusedDay: (_FocusedDay value) { + emit(state.copyWith(focusedDay: value.day)); + }, + didReceiveCellUpdate: (_DidReceiveCellUpdate value) {}, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(field: value.field)); + }, + ); + }, + ); + } + + @override + Future close() async { + if (_onCellChangedFn != null) { + cellContext.removeListener(_onCellChangedFn!); + _onCellChangedFn = null; + } + cellContext.dispose(); + return super.close(); + } + + void _startListening() { + _onCellChangedFn = cellContext.startListening( + onCellChanged: ((cell) { + if (!isClosed) { + add(DateCalEvent.didReceiveCellUpdate(cell)); + } + }), + ); + } + + void _updateCellData(DateTime day) { + final data = day.millisecondsSinceEpoch ~/ 1000; + cellContext.saveCellData(data.toString()); + } +} + +@freezed +class DateCalEvent with _$DateCalEvent { + const factory DateCalEvent.initial() = _Initial; + const factory DateCalEvent.selectDay(DateTime day) = _SelectDay; + const factory DateCalEvent.setFormat(CalendarFormat format) = _CalendarFormat; + const factory DateCalEvent.setFocusedDay(DateTime day) = _FocusedDay; + const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; + const factory DateCalEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; +} + +@freezed +class DateCalState with _$DateCalState { + const factory DateCalState({ + required Field field, + required Option typeOptinoData, + required CalendarFormat format, + required DateTime focusedDay, + DateTime? selectedDay, + }) = _DateCalState; + + factory DateCalState.initial(GridCellContext context) => DateCalState( + field: context.field, + typeOptinoData: none(), + format: CalendarFormat.month, + focusedDay: DateTime.now(), + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index f21fe38f2d..002bc945bc 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -3,7 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; import 'cell_service.dart'; - part 'date_cell_bloc.freezed.dart'; class DateCellBloc extends Bloc { @@ -72,7 +71,6 @@ class DateCellState with _$DateCellState { const factory DateCellState({ required String content, required Field field, - DateTime? selectedDay, }) = _DateCellState; factory DateCellState.initial(GridCellContext context) => DateCellState( diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart index 40ac699e7f..6513fe85c3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_action_sheet_bloc.dart @@ -8,36 +8,36 @@ import 'field_service.dart'; part 'field_action_sheet_bloc.freezed.dart'; class FieldActionSheetBloc extends Bloc { - final FieldService service; + final FieldService fieldService; - FieldActionSheetBloc({required Field field, required this.service}) + FieldActionSheetBloc({required Field field, required this.fieldService}) : super(FieldActionSheetState.initial(EditFieldContext.create()..gridField = field)) { on( (event, emit) async { await event.map( updateFieldName: (_UpdateFieldName value) async { - final result = await service.updateField(fieldId: field.id, name: value.name); + final result = await fieldService.updateField(name: value.name); result.fold( (l) => null, (err) => Log.error(err), ); }, hideField: (_HideField value) async { - final result = await service.updateField(fieldId: field.id, visibility: false); + final result = await fieldService.updateField(visibility: false); result.fold( (l) => null, (err) => Log.error(err), ); }, deleteField: (_DeleteField value) async { - final result = await service.deleteField(fieldId: field.id); + final result = await fieldService.deleteField(); result.fold( (l) => null, (err) => Log.error(err), ); }, duplicateField: (_DuplicateField value) async { - final result = await service.duplicateField(fieldId: field.id); + final result = await fieldService.duplicateField(); result.fold( (l) => null, (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart index d0d2999b6c..f5fc41e57f 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart @@ -15,7 +15,7 @@ class FieldCellBloc extends Bloc { FieldCellBloc({ required GridFieldCellContext cellContext, }) : _fieldListener = SingleFieldListener(fieldId: cellContext.field.id), - _fieldService = FieldService(gridId: cellContext.gridId), + _fieldService = FieldService(gridId: cellContext.gridId, fieldId: cellContext.field.id), super(FieldCellState.initial(cellContext)) { on( (event, emit) async { @@ -30,7 +30,7 @@ class FieldCellBloc extends Bloc { final defaultWidth = state.field.width.toDouble(); final width = defaultWidth + value.offset; if (width > defaultWidth && width < 300) { - _fieldService.updateField(fieldId: state.field.id, width: width); + _fieldService.updateField(width: width); } }, ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart index b3c37dbd76..d52fb8c312 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart @@ -11,14 +11,14 @@ import 'package:protobuf/protobuf.dart'; part 'field_editor_bloc.freezed.dart'; class FieldEditorBloc extends Bloc { - final FieldService service; + final String gridId; final EditFieldContextLoader _loader; FieldEditorBloc({ - required this.service, + required this.gridId, required EditFieldContextLoader fieldLoader, }) : _loader = fieldLoader, - super(FieldEditorState.initial(service.gridId)) { + super(FieldEditorState.initial(gridId)) { on( (event, emit) async { await event.map( @@ -73,7 +73,9 @@ class FieldEditorBloc extends Bloc { newContext.typeOptionData = typeOptionData; } }); - service.insertField( + + FieldService.insertField( + gridId: gridId, field: newContext.gridField, typeOptionData: newContext.typeOptionData, ); @@ -87,7 +89,8 @@ class FieldEditorBloc extends Bloc { await state.editFieldContext.fold( () async => null, (context) async { - final result = await service.insertField( + final result = await FieldService.insertField( + gridId: gridId, field: context.gridField, typeOptionData: context.typeOptionData, ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index c909bf1b31..7ee2863ef0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -8,10 +8,11 @@ part 'field_service.freezed.dart'; class FieldService { final String gridId; + final String fieldId; - FieldService({required this.gridId}); + FieldService({required this.gridId, required this.fieldId}); - Future> switchToField(String fieldId, FieldType fieldType) { + Future> switchToField(FieldType fieldType) { final payload = EditFieldPayload.create() ..gridId = gridId ..fieldId = fieldId @@ -20,8 +21,8 @@ class FieldService { return GridEventSwitchToField(payload).send(); } - Future> getEditFieldContext(String fieldId, FieldType fieldType) { - final payload = GetEditFieldContextPayload.create() + Future> getEditFieldContext(FieldType fieldType) { + final payload = EditFieldPayload.create() ..gridId = gridId ..fieldId = fieldId ..fieldType = fieldType; @@ -29,7 +30,7 @@ class FieldService { return GridEventGetEditFieldContext(payload).send(); } - Future> moveField(String fieldId, int fromIndex, int toIndex) { + Future> moveField(int fromIndex, int toIndex) { final payload = MoveItemPayload.create() ..gridId = gridId ..itemId = fieldId @@ -41,7 +42,6 @@ class FieldService { } Future> updateField({ - required String fieldId, String? name, FieldType? fieldType, bool? frozen, @@ -81,7 +81,8 @@ class FieldService { } // Create the field if it does not exist. Otherwise, update the field. - Future> insertField({ + static Future> insertField({ + required String gridId, required Field field, List? typeOptionData, String? startFieldId, @@ -98,9 +99,7 @@ class FieldService { return GridEventInsertField(payload).send(); } - Future> deleteField({ - required String fieldId, - }) { + Future> deleteField() { final payload = FieldIdentifierPayload.create() ..gridId = gridId ..fieldId = fieldId; @@ -108,15 +107,27 @@ class FieldService { return GridEventDeleteField(payload).send(); } - Future> duplicateField({ - required String fieldId, - }) { + Future> duplicateField() { final payload = FieldIdentifierPayload.create() ..gridId = gridId ..fieldId = fieldId; return GridEventDuplicateField(payload).send(); } + + Future, FlowyError>> getTypeOptionData({ + required FieldType fieldType, + }) { + final payload = EditFieldPayload.create() + ..fieldId = fieldId + ..fieldType = fieldType; + return GridEventGetFieldTypeOption(payload).send().then((result) { + return result.fold( + (data) => left(data.typeOptionData), + (err) => right(err), + ); + }); + } } @freezed @@ -141,7 +152,7 @@ class NewFieldContextLoader extends EditFieldContextLoader { @override Future> load() { - final payload = GetEditFieldContextPayload.create() + final payload = EditFieldPayload.create() ..gridId = gridId ..fieldType = FieldType.RichText; @@ -150,7 +161,7 @@ class NewFieldContextLoader extends EditFieldContextLoader { @override Future> switchToField(String fieldId, FieldType fieldType) { - final payload = GetEditFieldContextPayload.create() + final payload = EditFieldPayload.create() ..gridId = gridId ..fieldType = fieldType; @@ -169,7 +180,7 @@ class FieldContextLoaderAdaptor extends EditFieldContextLoader { @override Future> load() { - final payload = GetEditFieldContextPayload.create() + final payload = EditFieldPayload.create() ..gridId = gridId ..fieldId = field.id ..fieldType = field.fieldType; @@ -179,7 +190,7 @@ class FieldContextLoaderAdaptor extends EditFieldContextLoader { @override Future> switchToField(String fieldId, FieldType fieldType) async { - final fieldService = FieldService(gridId: gridId); - return fieldService.switchToField(fieldId, fieldType); + final fieldService = FieldService(gridId: gridId, fieldId: fieldId); + return fieldService.switchToField(fieldType); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index 2473bc607f..3195715413 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -9,14 +9,13 @@ import 'grid_service.dart'; part 'grid_header_bloc.freezed.dart'; class GridHeaderBloc extends Bloc { - final FieldService _fieldService; final GridFieldCache fieldCache; + final String gridId; GridHeaderBloc({ - required String gridId, + required this.gridId, required this.fieldCache, - }) : _fieldService = FieldService(gridId: gridId), - super(GridHeaderState.initial(fieldCache.clonedFields)) { + }) : super(GridHeaderState.initial(fieldCache.clonedFields)) { on( (event, emit) async { await event.map( @@ -39,8 +38,8 @@ class GridHeaderBloc extends Bloc { fields.insert(value.toIndex, fields.removeAt(value.fromIndex)); emit(state.copyWith(fields: fields)); - final result = await _fieldService.moveField( - value.field.id, + final fieldService = FieldService(gridId: gridId, fieldId: value.field.id); + final result = await fieldService.moveField( value.fromIndex, value.toIndex, ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart index c69b8062bf..42d2327f5b 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -9,13 +9,11 @@ import 'dart:async'; part 'property_bloc.freezed.dart'; class GridPropertyBloc extends Bloc { - final FieldService _service; final GridFieldCache _fieldCache; Function()? _listenFieldCallback; GridPropertyBloc({required String gridId, required GridFieldCache fieldCache}) - : _service = FieldService(gridId: gridId), - _fieldCache = fieldCache, + : _fieldCache = fieldCache, super(GridPropertyState.initial(gridId, fieldCache.clonedFields)) { on( (event, emit) async { @@ -24,7 +22,8 @@ class GridPropertyBloc extends Bloc { _startListening(); }, setFieldVisibility: (_SetFieldVisibility value) async { - final result = await _service.updateField(fieldId: value.fieldId, visibility: value.visibility); + final fieldService = FieldService(gridId: gridId, fieldId: value.fieldId); + final result = await fieldService.updateField(visibility: value.visibility); result.fold( (l) => null, (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index 8efdffdb32..aba03ba837 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -9,7 +9,7 @@ import 'package:provider/provider.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:styled_widget/styled_widget.dart'; import 'checkbox_cell.dart'; -import 'date_cell.dart'; +import 'date_cell/date_cell.dart'; import 'number_cell.dart'; import 'selection_cell/selection_cell.dart'; import 'text_cell.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart deleted file mode 100644 index 194e5adf6a..0000000000 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart +++ /dev/null @@ -1,217 +0,0 @@ -import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/workspace/application/grid/prelude.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:flowy_infra_ui/flowy_infra_ui.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:table_calendar/table_calendar.dart'; -import 'cell_builder.dart'; - -class DateCellStyle extends GridCellStyle { - Alignment alignment; - - DateCellStyle({this.alignment = Alignment.center}); -} - -abstract class GridCellDelegate { - void onFocus(bool isFocus); - GridCellDelegate get delegate; -} - -class DateCell extends GridCellWidget { - final GridCellContextBuilder cellContextBuilder; - late final DateCellStyle? cellStyle; - - DateCell({ - GridCellStyle? style, - required this.cellContextBuilder, - Key? key, - }) : super(key: key) { - if (style != null) { - cellStyle = (style as DateCellStyle); - } else { - cellStyle = null; - } - } - - @override - State createState() => _DateCellState(); -} - -class _DateCellState extends State { - late DateCellBloc _cellBloc; - - @override - void initState() { - final cellContext = widget.cellContextBuilder.build(); - _cellBloc = getIt(param1: cellContext)..add(const DateCellEvent.initial()); - super.initState(); - } - - @override - Widget build(BuildContext context) { - final alignment = widget.cellStyle != null ? widget.cellStyle!.alignment : Alignment.center; - return BlocProvider.value( - value: _cellBloc, - child: BlocBuilder( - builder: (context, state) { - return SizedBox.expand( - child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - widget.onFocus.value = true; - _CellCalendar.show( - context, - onSelected: (day) { - context.read().add(DateCellEvent.selectDay(day)); - }, - onDismissed: () => widget.onFocus.value = false, - ); - }, - child: MouseRegion( - opaque: false, - cursor: SystemMouseCursors.click, - child: Align(alignment: alignment, child: FlowyText.medium(state.content, fontSize: 12)), - ), - ), - ); - }, - ), - ); - } - - @override - Future dispose() async { - _cellBloc.close(); - super.dispose(); - } -} - -final kToday = DateTime.now(); -final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); -final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); - -class _CellCalendar extends StatefulWidget with FlowyOverlayDelegate { - final void Function(DateTime) onSelected; - final VoidCallback onDismissed; - final bool includeTime; - const _CellCalendar({ - required this.onSelected, - required this.onDismissed, - required this.includeTime, - Key? key, - }) : super(key: key); - - @override - State<_CellCalendar> createState() => _CellCalendarState(); - - static Future show( - BuildContext context, { - required void Function(DateTime) onSelected, - required VoidCallback onDismissed, - }) async { - _CellCalendar.remove(context); - - final calendar = _CellCalendar( - onSelected: onSelected, - onDismissed: onDismissed, - includeTime: false, - ); - // const size = Size(460, 400); - // final window = await getWindowInfo(); - // FlowyOverlay.of(context).insertWithRect( - // widget: OverlayContainer( - // child: calendar, - // constraints: BoxConstraints.loose(const Size(460, 400)), - // ), - // identifier: _CellCalendar.identifier(), - // anchorPosition: Offset(-size.width / 2.0, -size.height / 2.0), - // anchorSize: window.frame.size, - // anchorDirection: AnchorDirection.center, - // style: FlowyOverlayStyle(blur: false), - // delegate: calendar, - // ); - - FlowyOverlay.of(context).insertWithAnchor( - widget: OverlayContainer( - child: calendar, - constraints: BoxConstraints.tight(const Size(320, 320)), - ), - identifier: _CellCalendar.identifier(), - anchorContext: context, - anchorDirection: AnchorDirection.leftWithCenterAligned, - style: FlowyOverlayStyle(blur: false), - delegate: calendar, - ); - } - - static void remove(BuildContext context) { - FlowyOverlay.of(context).remove(identifier()); - } - - static String identifier() { - return (_CellCalendar).toString(); - } - - @override - void didRemove() => onDismissed(); -} - -class _CellCalendarState extends State<_CellCalendar> { - CalendarFormat _calendarFormat = CalendarFormat.month; - DateTime _focusedDay = DateTime.now(); - DateTime? _selectedDay; - - @override - Widget build(BuildContext context) { - final theme = context.watch(); - return TableCalendar( - firstDay: kFirstDay, - lastDay: kLastDay, - focusedDay: _focusedDay, - rowHeight: 40, - calendarFormat: _calendarFormat, - headerStyle: const HeaderStyle(formatButtonVisible: false), - calendarStyle: CalendarStyle( - selectedDecoration: BoxDecoration( - color: theme.main1, - shape: BoxShape.circle, - ), - todayDecoration: BoxDecoration( - color: theme.shader4, - shape: BoxShape.circle, - ), - selectedTextStyle: TextStyle( - color: theme.surface, - fontSize: 14.0, - ), - todayTextStyle: TextStyle( - color: theme.surface, - fontSize: 14.0, - ), - ), - selectedDayPredicate: (day) { - return isSameDay(_selectedDay, day); - }, - onDaySelected: (selectedDay, focusedDay) { - if (!isSameDay(_selectedDay, selectedDay)) { - // Call `setState()` when updating the selected day - setState(() { - _selectedDay = selectedDay; - _focusedDay = focusedDay; - widget.onSelected(selectedDay); - }); - } - }, - onFormatChanged: (format) { - setState(() { - _calendarFormat = format; - }); - }, - onPageChanged: (focusedDay) { - _focusedDay = focusedDay; - }, - ); - } -} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart new file mode 100644 index 0000000000..7b052078d0 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -0,0 +1,139 @@ +import 'package:app_flowy/workspace/application/grid/cell/date_cal_bloc.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:table_calendar/table_calendar.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; + +final kToday = DateTime.now(); +final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); +final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); + +class CellCalendar with FlowyOverlayDelegate { + final VoidCallback onDismissed; + + const CellCalendar({ + required this.onDismissed, + }); + + Future show( + BuildContext context, { + required GridDefaultCellContext cellContext, + required void Function(DateTime) onSelected, + }) async { + CellCalendar.remove(context); + + final calendar = _CellCalendarWidget( + onSelected: onSelected, + includeTime: false, + cellContext: cellContext, + ); + // const size = Size(460, 400); + // final window = await getWindowInfo(); + // FlowyOverlay.of(context).insertWithRect( + // widget: OverlayContainer( + // child: calendar, + // constraints: BoxConstraints.loose(const Size(460, 400)), + // ), + // identifier: _CellCalendar.identifier(), + // anchorPosition: Offset(-size.width / 2.0, -size.height / 2.0), + // anchorSize: window.frame.size, + // anchorDirection: AnchorDirection.center, + // style: FlowyOverlayStyle(blur: false), + // delegate: calendar, + // ); + + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: calendar, + constraints: BoxConstraints.tight(const Size(320, 320)), + ), + identifier: CellCalendar.identifier(), + anchorContext: context, + anchorDirection: AnchorDirection.leftWithCenterAligned, + style: FlowyOverlayStyle(blur: false), + delegate: this, + ); + } + + static void remove(BuildContext context) { + FlowyOverlay.of(context).remove(identifier()); + } + + static String identifier() { + return (CellCalendar).toString(); + } + + @override + void didRemove() => onDismissed(); +} + +class _CellCalendarWidget extends StatelessWidget { + final bool includeTime; + final GridDefaultCellContext cellContext; + final void Function(DateTime) onSelected; + + const _CellCalendarWidget({ + required this.onSelected, + required this.includeTime, + required this.cellContext, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return BlocProvider( + create: (context) => DateCalBloc(cellContext: cellContext)..add(const DateCalEvent.initial()), + child: BlocConsumer( + listener: (context, state) { + if (state.selectedDay != null) { + onSelected(state.selectedDay!); + } + }, + listenWhen: (p, c) => p.selectedDay != c.selectedDay, + builder: (context, state) { + return TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: state.focusedDay, + rowHeight: 40, + calendarFormat: state.format, + headerStyle: const HeaderStyle(formatButtonVisible: false), + calendarStyle: CalendarStyle( + selectedDecoration: BoxDecoration( + color: theme.main1, + shape: BoxShape.circle, + ), + todayDecoration: BoxDecoration( + color: theme.shader4, + shape: BoxShape.circle, + ), + selectedTextStyle: TextStyle( + color: theme.surface, + fontSize: 14.0, + ), + todayTextStyle: TextStyle( + color: theme.surface, + fontSize: 14.0, + ), + ), + selectedDayPredicate: (day) { + return isSameDay(state.selectedDay, day); + }, + onDaySelected: (selectedDay, focusedDay) { + context.read().add(DateCalEvent.selectDay(selectedDay)); + }, + onFormatChanged: (format) { + context.read().add(DateCalEvent.setFormat(format)); + }, + onPageChanged: (focusedDay) { + context.read().add(DateCalEvent.setFocusedDay(focusedDay)); + }, + ); + }, + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart new file mode 100644 index 0000000000..bbf0f55ffc --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart @@ -0,0 +1,90 @@ +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; + +import '../cell_builder.dart'; +import 'calendar.dart'; + +class DateCellStyle extends GridCellStyle { + Alignment alignment; + + DateCellStyle({this.alignment = Alignment.center}); +} + +abstract class GridCellDelegate { + void onFocus(bool isFocus); + GridCellDelegate get delegate; +} + +class DateCell extends GridCellWidget { + final GridCellContextBuilder cellContextBuilder; + late final DateCellStyle? cellStyle; + + DateCell({ + GridCellStyle? style, + required this.cellContextBuilder, + Key? key, + }) : super(key: key) { + if (style != null) { + cellStyle = (style as DateCellStyle); + } else { + cellStyle = null; + } + } + + @override + State createState() => _DateCellState(); +} + +class _DateCellState extends State { + late DateCellBloc _cellBloc; + + @override + void initState() { + final cellContext = widget.cellContextBuilder.build(); + _cellBloc = getIt(param1: cellContext)..add(const DateCellEvent.initial()); + super.initState(); + } + + @override + Widget build(BuildContext context) { + final alignment = widget.cellStyle != null ? widget.cellStyle!.alignment : Alignment.center; + return BlocProvider.value( + value: _cellBloc, + child: BlocBuilder( + builder: (context, state) { + return SizedBox.expand( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => _showCalendar(context), + child: MouseRegion( + opaque: false, + cursor: SystemMouseCursors.click, + child: Align(alignment: alignment, child: FlowyText.medium(state.content, fontSize: 12)), + ), + ), + ); + }, + ), + ); + } + + void _showCalendar(BuildContext context) { + final bloc = context.read(); + widget.onFocus.value = true; + final calendar = CellCalendar(onDismissed: () => widget.onFocus.value = false); + calendar.show( + context, + cellContext: bloc.cellContext.clone(), + onSelected: (day) => bloc.add(DateCellEvent.selectDay(day)), + ); + } + + @override + Future dispose() async { + _cellBloc.close(); + super.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart index 8f1e13de94..3c7e43ecc0 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart @@ -1,6 +1,6 @@ export 'cell_builder.dart'; export 'text_cell.dart'; export 'number_cell.dart'; -export 'date_cell.dart'; +export 'date_cell/date_cell.dart'; export 'checkbox_cell.dart'; export 'selection_cell/selection_cell.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart index 75ebc7cfa9..339f2b451c 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart @@ -138,7 +138,7 @@ class GridEventDuplicateField { } class GridEventGetEditFieldContext { - GetEditFieldContextPayload request; + EditFieldPayload request; GridEventGetEditFieldContext(this.request); Future> send() { @@ -172,7 +172,7 @@ class GridEventMoveItem { } class GridEventGetFieldTypeOption { - GetEditFieldContextPayload request; + EditFieldPayload request; GridEventGetFieldTypeOption(this.request); Future> send() { diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart index 06685ebf9e..f88989a841 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart @@ -490,8 +490,18 @@ class GetEditFieldContextPayload extends $pb.GeneratedMessage { void clearFieldType() => clearField(3); } +enum EditFieldPayload_OneOfFieldId { + fieldId, + notSet +} + class EditFieldPayload extends $pb.GeneratedMessage { + static const $core.Map<$core.int, EditFieldPayload_OneOfFieldId> _EditFieldPayload_OneOfFieldIdByTag = { + 2 : EditFieldPayload_OneOfFieldId.fieldId, + 0 : EditFieldPayload_OneOfFieldId.notSet + }; static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'EditFieldPayload', createEmptyInstance: create) + ..oo(0, [2]) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') ..e(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldType', $pb.PbFieldType.OE, defaultOrMaker: FieldType.RichText, valueOf: FieldType.valueOf, enumValues: FieldType.values) @@ -537,6 +547,9 @@ class EditFieldPayload extends $pb.GeneratedMessage { static EditFieldPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static EditFieldPayload? _defaultInstance; + EditFieldPayload_OneOfFieldId whichOneOfFieldId() => _EditFieldPayload_OneOfFieldIdByTag[$_whichOneof(0)]!; + void clearOneOfFieldId() => clearField($_whichOneof(0)); + @$pb.TagNumber(1) $core.String get gridId => $_getSZ(0); @$pb.TagNumber(1) diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart index ae8a01e87b..d59dd68b25 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart @@ -117,13 +117,16 @@ const EditFieldPayload$json = const { '1': 'EditFieldPayload', '2': const [ const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, - const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'fieldId'}, const {'1': 'field_type', '3': 3, '4': 1, '5': 14, '6': '.FieldType', '10': 'fieldType'}, ], + '8': const [ + const {'1': 'one_of_field_id'}, + ], }; /// Descriptor for `EditFieldPayload`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List editFieldPayloadDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRQYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIZCghmaWVsZF9pZBgCIAEoCVIHZmllbGRJZBIpCgpmaWVsZF90eXBlGAMgASgOMgouRmllbGRUeXBlUglmaWVsZFR5cGU='); +final $typed_data.Uint8List editFieldPayloadDescriptor = $convert.base64Decode('ChBFZGl0RmllbGRQYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIbCghmaWVsZF9pZBgCIAEoCUgAUgdmaWVsZElkEikKCmZpZWxkX3R5cGUYAyABKA4yCi5GaWVsZFR5cGVSCWZpZWxkVHlwZUIRCg9vbmVfb2ZfZmllbGRfaWQ='); @$core.Deprecated('Use editFieldContextDescriptor instead') const EditFieldContext$json = const { '1': 'EditFieldContext', diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index eb6d2ef5ba..43bed6b053 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -87,20 +87,15 @@ pub(crate) async fn switch_to_field_handler( manager: AppData>, ) -> DataResult { let params: EditFieldParams = data.into_inner().try_into()?; + if params.field_id.is_none() { + return Err(ErrorCode::FieldIdIsEmpty.into()); + } + let field_id = params.field_id.unwrap(); let editor = manager.get_grid_editor(¶ms.grid_id)?; - editor - .switch_to_field_type(¶ms.field_id, ¶ms.field_type) - .await?; - - let field_meta = editor.get_field_meta(¶ms.field_id).await; - let edit_context = make_field_edit_context( - ¶ms.grid_id, - Some(params.field_id), - params.field_type, - editor, - field_meta, - ) - .await?; + editor.switch_to_field_type(&field_id, ¶ms.field_type).await?; + let field_meta = editor.get_field_meta(&field_id).await; + let edit_context = + make_edit_field_context(¶ms.grid_id, Some(field_id), params.field_type, editor, field_meta).await?; data_result(edit_context) } @@ -117,23 +112,23 @@ pub(crate) async fn duplicate_field_handler( #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn get_field_context_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { - let params = data.into_inner(); + let params: EditFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let edit_context = - make_field_edit_context(¶ms.grid_id, params.field_id, params.field_type, editor, None).await?; + make_edit_field_context(¶ms.grid_id, params.field_id, params.field_type, editor, None).await?; data_result(edit_context) } #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn get_field_type_option_data_handler( - data: Data, + data: Data, manager: AppData>, ) -> DataResult { - let params = data.into_inner(); + let params: EditFieldParams = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; let field_meta = get_or_create_field_meta(params.field_id, ¶ms.field_type, editor).await?; let type_option_data = get_type_option_data(&field_meta, &field_meta.field_type).await?; @@ -155,7 +150,7 @@ pub(crate) async fn move_item_handler( Ok(()) } -async fn make_field_edit_context( +async fn make_edit_field_context( grid_id: &str, field_id: Option, field_type: FieldType, diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index 4262bbe2f0..a90c90ebe2 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -64,13 +64,13 @@ pub enum GridEvent { #[event(input = "FieldIdentifierPayload")] DuplicateField = 15, - #[event(input = "GetEditFieldContextPayload", output = "EditFieldContext")] + #[event(input = "EditFieldPayload", output = "EditFieldContext")] GetEditFieldContext = 16, #[event(input = "MoveItemPayload")] MoveItem = 17, - #[event(input = "GetEditFieldContextPayload", output = "FieldTypeOptionData")] + #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")] GetFieldTypeOption = 18, #[event(input = "CreateSelectOptionPayload", output = "SelectOption")] diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs index b742508f7c..2a287c941a 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -167,8 +167,8 @@ pub struct EditFieldPayload { #[pb(index = 1)] pub grid_id: String, - #[pb(index = 2)] - pub field_id: String, + #[pb(index = 2, one_of)] + pub field_id: Option, #[pb(index = 3)] pub field_type: FieldType, @@ -176,7 +176,7 @@ pub struct EditFieldPayload { pub struct EditFieldParams { pub grid_id: String, - pub field_id: String, + pub field_id: Option, pub field_type: FieldType, } @@ -185,10 +185,10 @@ impl TryInto for EditFieldPayload { fn try_into(self) -> Result { let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + // let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; Ok(EditFieldParams { grid_id: grid_id.0, - field_id: field_id.0, + field_id: self.field_id, field_type: self.field_type, }) } diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs index d6f4c9f21a..072c4a4e49 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs @@ -1644,8 +1644,9 @@ impl ::protobuf::reflect::ProtobufValue for GetEditFieldContextPayload { pub struct EditFieldPayload { // message fields pub grid_id: ::std::string::String, - pub field_id: ::std::string::String, pub field_type: FieldType, + // message oneof groups + pub one_of_field_id: ::std::option::Option, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -1657,6 +1658,11 @@ impl<'a> ::std::default::Default for &'a EditFieldPayload { } } +#[derive(Clone,PartialEq,Debug)] +pub enum EditFieldPayload_oneof_one_of_field_id { + field_id(::std::string::String), +} + impl EditFieldPayload { pub fn new() -> EditFieldPayload { ::std::default::Default::default() @@ -1692,26 +1698,49 @@ impl EditFieldPayload { pub fn get_field_id(&self) -> &str { - &self.field_id + match self.one_of_field_id { + ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(ref v)) => v, + _ => "", + } } pub fn clear_field_id(&mut self) { - self.field_id.clear(); + self.one_of_field_id = ::std::option::Option::None; + } + + pub fn has_field_id(&self) -> bool { + match self.one_of_field_id { + ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(..)) => true, + _ => false, + } } // Param is passed by value, moved pub fn set_field_id(&mut self, v: ::std::string::String) { - self.field_id = v; + self.one_of_field_id = ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(v)) } // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. pub fn mut_field_id(&mut self) -> &mut ::std::string::String { - &mut self.field_id + if let ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(_)) = self.one_of_field_id { + } else { + self.one_of_field_id = ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(::std::string::String::new())); + } + match self.one_of_field_id { + ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(ref mut v)) => v, + _ => panic!(), + } } // Take field pub fn take_field_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + if self.has_field_id() { + match self.one_of_field_id.take() { + ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } } // .FieldType field_type = 3; @@ -1743,7 +1772,10 @@ impl ::protobuf::Message for EditFieldPayload { ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; }, 2 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_field_id = ::std::option::Option::Some(EditFieldPayload_oneof_one_of_field_id::field_id(is.read_string()?)); }, 3 => { ::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.field_type, 3, &mut self.unknown_fields)? @@ -1763,12 +1795,16 @@ impl ::protobuf::Message for EditFieldPayload { if !self.grid_id.is_empty() { my_size += ::protobuf::rt::string_size(1, &self.grid_id); } - if !self.field_id.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.field_id); - } if self.field_type != FieldType::RichText { my_size += ::protobuf::rt::enum_size(3, self.field_type); } + if let ::std::option::Option::Some(ref v) = self.one_of_field_id { + match v { + &EditFieldPayload_oneof_one_of_field_id::field_id(ref v) => { + my_size += ::protobuf::rt::string_size(2, &v); + }, + }; + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size @@ -1778,12 +1814,16 @@ impl ::protobuf::Message for EditFieldPayload { if !self.grid_id.is_empty() { os.write_string(1, &self.grid_id)?; } - if !self.field_id.is_empty() { - os.write_string(2, &self.field_id)?; - } if self.field_type != FieldType::RichText { os.write_enum(3, ::protobuf::ProtobufEnum::value(&self.field_type))?; } + if let ::std::option::Option::Some(ref v) = self.one_of_field_id { + match v { + &EditFieldPayload_oneof_one_of_field_id::field_id(ref v) => { + os.write_string(2, v)?; + }, + }; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -1827,10 +1867,10 @@ impl ::protobuf::Message for EditFieldPayload { |m: &EditFieldPayload| { &m.grid_id }, |m: &mut EditFieldPayload| { &mut m.grid_id }, )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( "field_id", - |m: &EditFieldPayload| { &m.field_id }, - |m: &mut EditFieldPayload| { &mut m.field_id }, + EditFieldPayload::has_field_id, + EditFieldPayload::get_field_id, )); fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum>( "field_type", @@ -1854,7 +1894,7 @@ impl ::protobuf::Message for EditFieldPayload { impl ::protobuf::Clear for EditFieldPayload { fn clear(&mut self) { self.grid_id.clear(); - self.field_id.clear(); + self.one_of_field_id = ::std::option::Option::None; self.field_type = FieldType::RichText; self.unknown_fields.clear(); } @@ -7928,78 +7968,79 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x05index\x18\x02\x20\x01(\x05R\x05index\"\x90\x01\n\x1aGetEditFieldCont\ extPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1b\n\ \x08field_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\n\nfield_type\x18\ - \x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field_id\"q\ - \n\x10EditFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridI\ - d\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12)\n\nfield_typ\ - e\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldType\"|\n\x10EditFieldContext\ - \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12%\n\ngrid_field\ - \x18\x02\x20\x01(\x0b2\x06.FieldR\tgridField\x12(\n\x10type_option_data\ - \x18\x03\x20\x01(\x0cR\x0etypeOptionData\"Z\n\x13FieldTypeOptionData\x12\ - \x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12(\n\x10type_option_\ - data\x18\x02\x20\x01(\x0cR\x0etypeOptionData\"-\n\rRepeatedField\x12\x1c\ - \n\x05items\x18\x01\x20\x03(\x0b2\x06.FieldR\x05items\"7\n\x12RepeatedFi\ - eldOrder\x12!\n\x05items\x18\x01\x20\x03(\x0b2\x0b.FieldOrderR\x05items\ - \"T\n\x08RowOrder\x12\x15\n\x06row_id\x18\x01\x20\x01(\tR\x05rowId\x12\ - \x19\n\x08block_id\x18\x02\x20\x01(\tR\x07blockId\x12\x16\n\x06height\ - \x18\x03\x20\x01(\x05R\x06height\"\xb8\x01\n\x03Row\x12\x0e\n\x02id\x18\ - \x01\x20\x01(\tR\x02id\x12@\n\x10cell_by_field_id\x18\x02\x20\x03(\x0b2\ - \x17.Row.CellByFieldIdEntryR\rcellByFieldId\x12\x16\n\x06height\x18\x03\ - \x20\x01(\x05R\x06height\x1aG\n\x12CellByFieldIdEntry\x12\x10\n\x03key\ - \x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05value\x18\x02\x20\x01(\x0b2\x05\ - .CellR\x05value:\x028\x01\")\n\x0bRepeatedRow\x12\x1a\n\x05items\x18\x01\ - \x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11RepeatedGridBlock\x12\x20\n\x05\ - items\x18\x01\x20\x03(\x0b2\n.GridBlockR\x05items\"U\n\x0eGridBlockOrder\ - \x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07blockId\x12(\n\nrow_orders\ - \x18\x02\x20\x03(\x0b2\t.RowOrderR\trowOrders\"_\n\rIndexRowOrder\x12&\n\ - \trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x05i\ - ndex\x18\x02\x20\x01(\x05H\0R\x05indexB\x0e\n\x0cone_of_index\"Q\n\x0fUp\ - datedRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.RowOrderR\x08row\ - Order\x12\x16\n\x03row\x18\x02\x20\x01(\x0b2\x04.RowR\x03row\"\xc6\x01\n\ - \x11GridRowsChangeset\x12\x19\n\x08block_id\x18\x01\x20\x01(\tR\x07block\ - Id\x123\n\rinserted_rows\x18\x02\x20\x03(\x0b2\x0e.IndexRowOrderR\x0cins\ - ertedRows\x12,\n\x0cdeleted_rows\x18\x03\x20\x03(\x0b2\t.RowOrderR\x0bde\ - letedRows\x123\n\x0cupdated_rows\x18\x04\x20\x03(\x0b2\x10.UpdatedRowOrd\ - erR\x0bupdatedRows\"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\"+\n\x0cRepeatedCell\x12\ - \x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\x11CreateG\ - ridPayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\x1e\n\x06Grid\ - Id\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\x0bGridBlockId\ - \x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10CreateRowPayloa\ - d\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\"\n\x0cstart_ro\ - w_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of_start_row_id\"\ - \xb6\x01\n\x12InsertFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\t\ - R\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\ - \x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\ - \n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15on\ - e_of_start_field_id\"d\n\x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\ - \x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\ - \x13.RepeatedFieldOrderR\x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\ - \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orde\ - rs\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\ - \x15FieldChangesetPayload\x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07f\ - ieldId\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04n\ - ame\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\ - \x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\ - \tfieldType\x12\x18\n\x06frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\ - \x20\n\nvisibility\x18\x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05w\ - idth\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10type_option_data\x18\ - \t\x20\x01(\x0cH\x06R\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_\ - of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_\ - of_visibilityB\x0e\n\x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\ - \x9c\x01\n\x0fMoveItemPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\ - \x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\ - \nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\ - \x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.Mo\ - veItemTypeR\x02ty\"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\ - \x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\ - \x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\ - \x18\x04\x20\x01(\tH\0R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\ - \x12\r\n\tMoveField\x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\ - \x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08Date\ - Time\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\ - \x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ + \x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fone_of_field_id\"\ + \x86\x01\n\x10EditFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\ + \x06gridId\x12\x1b\n\x08field_id\x18\x02\x20\x01(\tH\0R\x07fieldId\x12)\ + \n\nfield_type\x18\x03\x20\x01(\x0e2\n.FieldTypeR\tfieldTypeB\x11\n\x0fo\ + ne_of_field_id\"|\n\x10EditFieldContext\x12\x17\n\x07grid_id\x18\x01\x20\ + \x01(\tR\x06gridId\x12%\n\ngrid_field\x18\x02\x20\x01(\x0b2\x06.FieldR\t\ + gridField\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etypeOption\ + Data\"Z\n\x13FieldTypeOptionData\x12\x19\n\x08field_id\x18\x01\x20\x01(\ + \tR\x07fieldId\x12(\n\x10type_option_data\x18\x02\x20\x01(\x0cR\x0etypeO\ + ptionData\"-\n\rRepeatedField\x12\x1c\n\x05items\x18\x01\x20\x03(\x0b2\ + \x06.FieldR\x05items\"7\n\x12RepeatedFieldOrder\x12!\n\x05items\x18\x01\ + \x20\x03(\x0b2\x0b.FieldOrderR\x05items\"T\n\x08RowOrder\x12\x15\n\x06ro\ + w_id\x18\x01\x20\x01(\tR\x05rowId\x12\x19\n\x08block_id\x18\x02\x20\x01(\ + \tR\x07blockId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\"\xb8\ + \x01\n\x03Row\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\x02id\x12@\n\x10cell_b\ + y_field_id\x18\x02\x20\x03(\x0b2\x17.Row.CellByFieldIdEntryR\rcellByFiel\ + dId\x12\x16\n\x06height\x18\x03\x20\x01(\x05R\x06height\x1aG\n\x12CellBy\ + FieldIdEntry\x12\x10\n\x03key\x18\x01\x20\x01(\tR\x03key\x12\x1b\n\x05va\ + lue\x18\x02\x20\x01(\x0b2\x05.CellR\x05value:\x028\x01\")\n\x0bRepeatedR\ + ow\x12\x1a\n\x05items\x18\x01\x20\x03(\x0b2\x04.RowR\x05items\"5\n\x11Re\ + peatedGridBlock\x12\x20\n\x05items\x18\x01\x20\x03(\x0b2\n.GridBlockR\ + \x05items\"U\n\x0eGridBlockOrder\x12\x19\n\x08block_id\x18\x01\x20\x01(\ + \tR\x07blockId\x12(\n\nrow_orders\x18\x02\x20\x03(\x0b2\t.RowOrderR\trow\ + Orders\"_\n\rIndexRowOrder\x12&\n\trow_order\x18\x01\x20\x01(\x0b2\t.Row\ + OrderR\x08rowOrder\x12\x16\n\x05index\x18\x02\x20\x01(\x05H\0R\x05indexB\ + \x0e\n\x0cone_of_index\"Q\n\x0fUpdatedRowOrder\x12&\n\trow_order\x18\x01\ + \x20\x01(\x0b2\t.RowOrderR\x08rowOrder\x12\x16\n\x03row\x18\x02\x20\x01(\ + \x0b2\x04.RowR\x03row\"\xc6\x01\n\x11GridRowsChangeset\x12\x19\n\x08bloc\ + k_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\x123\n\x0cupdated_rows\x18\ + \x04\x20\x03(\x0b2\x10.UpdatedRowOrderR\x0bupdatedRows\"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\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b\ + 2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\n\x04name\x18\x01\ + \x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\x01\x20\ + \x01(\tR\x05value\"#\n\x0bGridBlockId\x12\x14\n\x05value\x18\x01\x20\x01\ + (\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\ + \x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0R\nstart\ + RowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12InsertFieldPayload\ + \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\ + \x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\x12(\n\x10type_option_data\ + \x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\n\x0estart_field_id\x18\ + \x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_field_id\"d\n\ + \x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\ + \x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\ + \x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\ + \x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\ + \x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\x15FieldChangesetPayload\ + \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\ + id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0\ + R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfie\ + ld_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\x06\ + frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\x18\ + \x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\x01(\ + \x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\x06R\ + \x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one\ + _of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\ + \x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0fMoveIt\ + emPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x17\n\ + \x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\x18\x03\ + \x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\x05R\ + \x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\x02ty\ + \"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06grid\ + Id\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_i\ + d\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\x20\x01(\tH\0\ + R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\x12\r\n\tMoveField\x10\ + \0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\ + \0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0c\ + SingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Check\ + box\x10\x05b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto index ccfd8e58bb..3fb7740fe7 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto +++ b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto @@ -35,7 +35,7 @@ message GetEditFieldContextPayload { } message EditFieldPayload { string grid_id = 1; - string field_id = 2; + oneof one_of_field_id { string field_id = 2; }; FieldType field_type = 3; } message EditFieldContext { From f617a0490021a40ecf5a4ef68d7aac0c2fbb41b1 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 9 May 2022 16:08:27 +0800 Subject: [PATCH 03/14] refactor: cell with origin data --- .../application/grid/cell/date_cal_bloc.dart | 33 ++++- .../application/grid/field/field_service.dart | 1 + .../flowy-grid-data-model/grid.pb.dart | 14 ++ .../flowy-grid-data-model/grid.pbjson.dart | 3 +- .../rust-lib/flowy-grid/src/event_handler.rs | 2 +- .../type_options/checkbox_type_option.rs | 10 +- .../field/type_options/date_type_option.rs | 19 +-- .../field/type_options/number_type_option.rs | 28 ++-- .../type_options/selection_type_option.rs | 33 ++--- .../field/type_options/text_type_option.rs | 13 +- .../src/services/row/cell_data_operation.rs | 48 ++++--- .../flowy-grid/src/services/row/row_loader.rs | 8 +- .../flowy-grid/tests/grid/grid_test.rs | 5 +- .../src/entities/grid.rs | 14 +- .../src/protobuf/model/grid.rs | 120 ++++++++++++------ .../src/protobuf/proto/grid.proto | 1 + 16 files changed, 240 insertions(+), 112 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 2214ddb875..f3ce3d5faa 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -1,3 +1,4 @@ +import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -6,6 +7,7 @@ import 'package:table_calendar/table_calendar.dart'; import 'dart:async'; import 'cell_service.dart'; import 'package:dartz/dartz.dart'; +import 'package:fixnum/fixnum.dart' as $fixnum; part 'date_cal_bloc.freezed.dart'; class DateCalBloc extends Bloc { @@ -15,9 +17,10 @@ class DateCalBloc extends Bloc { DateCalBloc({required this.cellContext}) : super(DateCalState.initial(cellContext)) { on( (event, emit) async { - event.map( - initial: (_Initial value) { + await event.map( + initial: (_Initial value) async { _startListening(); + await _loadDateTypeOption(emit); }, selectDay: (_SelectDay value) { if (!isSameDay(state.selectedDay, value.day)) { @@ -60,6 +63,30 @@ class DateCalBloc extends Bloc { ); } + Future _loadDateTypeOption(Emitter emit) async { + final result = await cellContext.getTypeOptionData(); + result.fold( + (data) { + final typeOptionData = DateTypeOption.fromBuffer(data); + + DateTime? selectedDay; + final cellData = cellContext.getCellData()?.data; + + if (cellData != null) { + final timestamp = $fixnum.Int64.parseInt(cellData).toInt(); + selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); + } + + emit(state.copyWith( + typeOptinoData: some(typeOptionData), + includeTime: typeOptionData.includeTime, + selectedDay: selectedDay, + )); + }, + (err) => Log.error(err), + ); + } + void _updateCellData(DateTime day) { final data = day.millisecondsSinceEpoch ~/ 1000; cellContext.saveCellData(data.toString()); @@ -83,6 +110,7 @@ class DateCalState with _$DateCalState { required Option typeOptinoData, required CalendarFormat format, required DateTime focusedDay, + required bool includeTime, DateTime? selectedDay, }) = _DateCalState; @@ -91,5 +119,6 @@ class DateCalState with _$DateCalState { typeOptinoData: none(), format: CalendarFormat.month, focusedDay: DateTime.now(), + includeTime: false, ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index 7ee2863ef0..ef198d5c3a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -119,6 +119,7 @@ class FieldService { required FieldType fieldType, }) { final payload = EditFieldPayload.create() + ..gridId = gridId ..fieldId = fieldId ..fieldType = fieldType; return GridEventGetFieldTypeOption(payload).send().then((result) { diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart index f88989a841..968044a972 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart @@ -1350,6 +1350,7 @@ class Cell extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'Cell', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'content') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data') ..hasRequiredFields = false ; @@ -1357,6 +1358,7 @@ class Cell extends $pb.GeneratedMessage { factory Cell({ $core.String? fieldId, $core.String? content, + $core.String? data, }) { final _result = create(); if (fieldId != null) { @@ -1365,6 +1367,9 @@ class Cell extends $pb.GeneratedMessage { if (content != null) { _result.content = content; } + if (data != null) { + _result.data = data; + } return _result; } factory Cell.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -1405,6 +1410,15 @@ class Cell extends $pb.GeneratedMessage { $core.bool hasContent() => $_has(1); @$pb.TagNumber(2) void clearContent() => clearField(2); + + @$pb.TagNumber(3) + $core.String get data => $_getSZ(2); + @$pb.TagNumber(3) + set data($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasData() => $_has(2); + @$pb.TagNumber(3) + void clearData() => clearField(3); } class RepeatedCell extends $pb.GeneratedMessage { diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart index d59dd68b25..29dcde046c 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart @@ -291,11 +291,12 @@ const Cell$json = const { '2': const [ const {'1': 'field_id', '3': 1, '4': 1, '5': 9, '10': 'fieldId'}, const {'1': 'content', '3': 2, '4': 1, '5': 9, '10': 'content'}, + const {'1': 'data', '3': 3, '4': 1, '5': 9, '10': 'data'}, ], }; /// Descriptor for `Cell`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQ='); +final $typed_data.Uint8List cellDescriptor = $convert.base64Decode('CgRDZWxsEhkKCGZpZWxkX2lkGAEgASgJUgdmaWVsZElkEhgKB2NvbnRlbnQYAiABKAlSB2NvbnRlbnQSEgoEZGF0YRgDIAEoCVIEZGF0YQ=='); @$core.Deprecated('Use repeatedCellDescriptor instead') const RepeatedCell$json = const { '1': 'RepeatedCell', diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 43bed6b053..fd7b838b82 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -245,7 +245,7 @@ pub(crate) async fn get_cell_handler( let params: CellIdentifier = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_cell(¶ms).await { - None => data_result(Cell::new(¶ms.field_id, "".to_owned())), + None => data_result(Cell::empty(¶ms.field_id)), Some(cell) => data_result(cell), } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs index 994e82829a..ff1f2d3d78 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs @@ -1,6 +1,6 @@ use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use crate::services::row::{CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::FlowyError; @@ -44,18 +44,18 @@ const YES: &str = "Yes"; const NO: &str = "No"; impl CellDataOperation for CheckboxTypeOption { - fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if !type_option_cell_data.is_checkbox() { - return String::new(); + return DecodedCellData::default(); } let cell_data = type_option_cell_data.data; if cell_data == YES || cell_data == NO { - return cell_data; + return DecodedCellData::from_content(cell_data); } } - String::new() + DecodedCellData::default() } fn apply_changeset>( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 81e77f2645..42912b932f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -1,8 +1,8 @@ use crate::impl_type_option; -use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use crate::services::row::{CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use chrono::format::strftime::StrftimeItems; -use chrono::NaiveDateTime; +use chrono::{NaiveDateTime, ParseResult}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::FlowyError; use flowy_grid_data_model::entities::{ @@ -53,24 +53,25 @@ impl DateTypeOption { } impl CellDataOperation for DateTypeOption { - fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if !type_option_cell_data.is_date() { - return String::new(); + return DecodedCellData::default(); } let cell_data = type_option_cell_data.data; if let Ok(timestamp) = cell_data.parse::() { let native = NaiveDateTime::from_timestamp(timestamp, 0); - return self.today_from_native(native); + return DecodedCellData::new(format!("{}", timestamp), self.today_from_native(native)); } - if NaiveDateTime::parse_from_str(&cell_data, &self.fmt_str()).is_ok() { - return cell_data; - } + return match NaiveDateTime::parse_from_str(&cell_data, &self.fmt_str()) { + Ok(date_time) => DecodedCellData::new(format!("{}", date_time.timestamp()), cell_data), + Err(_) => DecodedCellData::default(), + }; } - String::new() + DecodedCellData::default() } fn apply_changeset>( diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs index 2d03a0ab33..36c05410da 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs @@ -1,6 +1,6 @@ use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use crate::services::row::{CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::FlowyError; @@ -77,30 +77,36 @@ pub struct NumberTypeOption { impl_type_option!(NumberTypeOption, FieldType::Number); impl CellDataOperation for NumberTypeOption { - fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if type_option_cell_data.is_date() { - return String::new(); + return DecodedCellData::default(); } let cell_data = type_option_cell_data.data; - match self.format { + return match self.format { NumberFormat::Number => { if let Ok(v) = cell_data.parse::() { - return v.to_string(); + return DecodedCellData::from_content(v.to_string()); } if let Ok(v) = cell_data.parse::() { - return v.to_string(); + return DecodedCellData::from_content(v.to_string()); } - return String::new(); + DecodedCellData::default() } - NumberFormat::Percent => cell_data.parse::().map_or(String::new(), |v| v.to_string()), - _ => self.money_from_str(&cell_data), - } + NumberFormat::Percent => { + let content = cell_data.parse::().map_or(String::new(), |v| v.to_string()); + DecodedCellData::from_content(content) + } + _ => { + let content = self.money_from_str(&cell_data); + DecodedCellData::from_content(content) + } + }; } else { - String::new() + DecodedCellData::default() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs index ecaf2344b8..7b049a7385 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs @@ -1,7 +1,7 @@ use crate::impl_type_option; use crate::services::entities::{CellIdentifier, CellIdentifierPayload}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use crate::services::row::{CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; @@ -95,22 +95,21 @@ impl SelectOptionOperation for SingleSelectTypeOption { } impl CellDataOperation for SingleSelectTypeOption { - fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if !type_option_cell_data.is_single_select() { - return String::new(); + return DecodedCellData::default(); } - match select_option_ids(type_option_cell_data.data).first() { - None => String::new(), - Some(option_id) => match self.options.iter().find(|option| &option.id == option_id) { - None => String::new(), - Some(option) => option.name.clone(), - }, + if let Some(option_id) = select_option_ids(type_option_cell_data.data).first() { + return match self.options.iter().find(|option| &option.id == option_id) { + None => DecodedCellData::default(), + Some(option) => DecodedCellData::from_content(option.name.clone()), + }; } - } else { - String::new() } + + DecodedCellData::default() } fn apply_changeset>( @@ -194,20 +193,22 @@ impl SelectOptionOperation for MultiSelectTypeOption { } impl CellDataOperation for MultiSelectTypeOption { - fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> String { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if !type_option_cell_data.is_multi_select() { - return String::new(); + return DecodedCellData::default(); } let option_ids = select_option_ids(type_option_cell_data.data); - self.options + let content = self + .options .iter() .filter(|option| option_ids.contains(&option.id)) .map(|option| option.name.clone()) .collect::>() - .join(SELECTION_IDS_SEPARATOR) + .join(SELECTION_IDS_SEPARATOR); + DecodedCellData::from_content(content) } else { - String::new() + DecodedCellData::default() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs index 08e61a57e9..d605a719bf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -1,6 +1,8 @@ use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{decode_cell_data, CellDataChangeset, CellDataOperation, TypeOptionCellData}; +use crate::services::row::{ + decode_cell_data, CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData, +}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::FlowyError; @@ -33,19 +35,20 @@ pub struct RichTextTypeOption { impl_type_option!(RichTextTypeOption, FieldType::RichText); impl CellDataOperation for RichTextTypeOption { - fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> String { + fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if type_option_cell_data.is_date() || type_option_cell_data.is_single_select() || type_option_cell_data.is_multi_select() || type_option_cell_data.is_number() { - decode_cell_data(data, field_meta, &type_option_cell_data.field_type).unwrap_or_else(|| "".to_owned()) + decode_cell_data(data, field_meta, &type_option_cell_data.field_type) + .unwrap_or_else(|| DecodedCellData::default()) } else { - type_option_cell_data.data + DecodedCellData::from_content(type_option_cell_data.data) } } else { - String::new() + DecodedCellData::default() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs index 9d92de574e..99ff127b32 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs @@ -1,12 +1,14 @@ use crate::services::field::*; +use std::borrow::Cow; use std::fmt::Formatter; +use std::sync::Arc; use flowy_error::FlowyError; use flowy_grid_data_model::entities::{CellMeta, FieldMeta, FieldType}; use serde::{Deserialize, Serialize}; pub trait CellDataOperation { - fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> String; + fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData; fn apply_changeset>( &self, changeset: T, @@ -106,22 +108,31 @@ pub fn apply_cell_data_changeset>( FieldType::Checkbox => CheckboxTypeOption::from(field_meta).apply_changeset(changeset, cell_meta), } } -// -// #[tracing::instrument(level = "trace", skip(field_meta, data), fields(content), err)] -// pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &FieldType) -> Result { -// let s = match field_meta.field_type { -// FieldType::RichText => RichTextTypeOption::from(field_meta).decode_cell_data(data, field_meta), -// FieldType::Number => NumberTypeOption::from(field_meta).decode_cell_data(data, field_meta), -// FieldType::DateTime => DateTypeOption::from(field_meta).decode_cell_data(data, field_meta), -// FieldType::SingleSelect => SingleSelectTypeOption::from(field_meta).decode_cell_data(data, field_meta), -// FieldType::MultiSelect => MultiSelectTypeOption::from(field_meta).decode_cell_data(data, field_meta), -// FieldType::Checkbox => CheckboxTypeOption::from(field_meta).decode_cell_data(data, field_meta), -// }; -// tracing::Span::current().record("content", &format!("{:?}: {}", field_meta.field_type, s).as_str()); -// Ok(s) -// } -pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &FieldType) -> Option { +#[derive(Default)] +pub struct DecodedCellData { + raw: String, + content: String, +} + +impl DecodedCellData { + pub fn from_content(content: String) -> Self { + Self { + raw: content.clone(), + content, + } + } + + pub fn new(raw: String, content: String) -> Self { + Self { raw, content } + } + + pub fn split(self) -> (String, String) { + (self.raw, self.content) + } +} + +pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &FieldType) -> Option { let s = match field_type { FieldType::RichText => field_meta .get_type_option_entry::(field_type)? @@ -142,6 +153,9 @@ pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &Field .get_type_option_entry::(field_type)? .decode_cell_data(data, field_meta), }; - tracing::Span::current().record("content", &format!("{:?}: {}", field_meta.field_type, s).as_str()); + tracing::Span::current().record( + "content", + &format!("{:?}: {}", field_meta.field_type, s.content).as_str(), + ); Some(s) } diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs index b4cb0476ef..543e743a51 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs @@ -31,15 +31,15 @@ pub fn make_cell_by_field_id( cell_meta: CellMeta, ) -> Option<(String, Cell)> { let field_meta = field_map.get(&field_id)?; - let content = decode_cell_data(cell_meta.data, field_meta, &field_meta.field_type)?; - let cell = Cell::new(&field_id, content); + let (raw, content) = decode_cell_data(cell_meta.data.clone(), field_meta, &field_meta.field_type)?.split(); + let cell = Cell::new(&field_id, content, raw); Some((field_id, cell)) } pub fn make_cell(field_id: &str, field_meta: &FieldMeta, row_meta: &RowMeta) -> Option { let cell_meta = row_meta.cells.get(field_id)?.clone(); - let content = decode_cell_data(cell_meta.data, field_meta, &field_meta.field_type)?; - Some(Cell::new(field_id, content)) + let (raw, content) = decode_cell_data(cell_meta.data.clone(), field_meta, &field_meta.field_type)?.split(); + Some(Cell::new(field_id, content, raw)) } pub(crate) fn make_row_orders_from_row_metas(row_metas: &[Arc]) -> Vec { diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs index 3c66f2355e..9ac18aed7f 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs @@ -287,7 +287,10 @@ async fn grid_row_add_date_cell_test() { let date_field = date_field.unwrap(); let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone(); assert_eq!( - decode_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type).unwrap(), + decode_cell_data(cell_data.data.clone(), &date_field, &date_field.field_type) + .unwrap() + .split() + .1, "2022/03/16", ); let scripts = vec![CreateRow { context }]; diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs index 2a287c941a..09f6f8f40c 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -461,13 +461,25 @@ pub struct Cell { #[pb(index = 2)] pub content: String, + + #[pb(index = 3)] + pub data: String, } impl Cell { - pub fn new(field_id: &str, content: String) -> Self { + pub fn new(field_id: &str, content: String, data: String) -> Self { Self { field_id: field_id.to_owned(), content, + data, + } + } + + pub fn empty(field_id: &str) -> Self { + Self { + field_id: field_id.to_owned(), + content: "".to_string(), + data: "".to_string(), } } } diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs index 072c4a4e49..5d3d3df43a 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs @@ -4692,6 +4692,7 @@ pub struct Cell { // message fields pub field_id: ::std::string::String, pub content: ::std::string::String, + pub data: ::std::string::String, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -4759,6 +4760,32 @@ impl Cell { pub fn take_content(&mut self) -> ::std::string::String { ::std::mem::replace(&mut self.content, ::std::string::String::new()) } + + // string data = 3; + + + pub fn get_data(&self) -> &str { + &self.data + } + pub fn clear_data(&mut self) { + self.data.clear(); + } + + // Param is passed by value, moved + pub fn set_data(&mut self, v: ::std::string::String) { + self.data = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_data(&mut self) -> &mut ::std::string::String { + &mut self.data + } + + // Take field + pub fn take_data(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.data, ::std::string::String::new()) + } } impl ::protobuf::Message for Cell { @@ -4776,6 +4803,9 @@ impl ::protobuf::Message for Cell { 2 => { ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.content)?; }, + 3 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.data)?; + }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, @@ -4794,6 +4824,9 @@ impl ::protobuf::Message for Cell { if !self.content.is_empty() { my_size += ::protobuf::rt::string_size(2, &self.content); } + if !self.data.is_empty() { + my_size += ::protobuf::rt::string_size(3, &self.data); + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size @@ -4806,6 +4839,9 @@ impl ::protobuf::Message for Cell { if !self.content.is_empty() { os.write_string(2, &self.content)?; } + if !self.data.is_empty() { + os.write_string(3, &self.data)?; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -4854,6 +4890,11 @@ impl ::protobuf::Message for Cell { |m: &Cell| { &m.content }, |m: &mut Cell| { &mut m.content }, )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "data", + |m: &Cell| { &m.data }, + |m: &mut Cell| { &mut m.data }, + )); ::protobuf::reflect::MessageDescriptor::new_pb_name::( "Cell", fields, @@ -4872,6 +4913,7 @@ impl ::protobuf::Clear for Cell { fn clear(&mut self) { self.field_id.clear(); self.content.clear(); + self.data.clear(); self.unknown_fields.clear(); } } @@ -8001,46 +8043,46 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x03\x20\x03(\x0b2\t.RowOrderR\x0bdeletedRows\x123\n\x0cupdated_rows\x18\ \x04\x20\x03(\x0b2\x10.UpdatedRowOrderR\x0bupdatedRows\"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\ + \x20\x03(\x0b2\t.RowOrderR\trowOrders\"O\n\x04Cell\x12\x19\n\x08field_id\ \x18\x01\x20\x01(\tR\x07fieldId\x12\x18\n\x07content\x18\x02\x20\x01(\tR\ - \x07content\"+\n\x0cRepeatedCell\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b\ - 2\x05.CellR\x05items\"'\n\x11CreateGridPayload\x12\x12\n\x04name\x18\x01\ - \x20\x01(\tR\x04name\"\x1e\n\x06GridId\x12\x14\n\x05value\x18\x01\x20\ - \x01(\tR\x05value\"#\n\x0bGridBlockId\x12\x14\n\x05value\x18\x01\x20\x01\ - (\tR\x05value\"f\n\x10CreateRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\ - \x01(\tR\x06gridId\x12\"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0R\nstart\ - RowIdB\x15\n\x13one_of_start_row_id\"\xb6\x01\n\x12InsertFieldPayload\ - \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\ - \x18\x02\x20\x01(\x0b2\x06.FieldR\x05field\x12(\n\x10type_option_data\ - \x18\x03\x20\x01(\x0cR\x0etypeOptionData\x12&\n\x0estart_field_id\x18\ - \x04\x20\x01(\tH\0R\x0cstartFieldIdB\x17\n\x15one_of_start_field_id\"d\n\ - \x11QueryFieldPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\ - \x126\n\x0cfield_orders\x18\x02\x20\x01(\x0b2\x13.RepeatedFieldOrderR\ - \x0bfieldOrders\"e\n\x16QueryGridBlocksPayload\x12\x17\n\x07grid_id\x18\ - \x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\ - \x0f.GridBlockOrderR\x0bblockOrders\"\xa8\x03\n\x15FieldChangesetPayload\ - \x12\x19\n\x08field_id\x18\x01\x20\x01(\tR\x07fieldId\x12\x17\n\x07grid_\ - id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\n\x04name\x18\x03\x20\x01(\tH\0\ - R\x04name\x12\x14\n\x04desc\x18\x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfie\ - ld_type\x18\x05\x20\x01(\x0e2\n.FieldTypeH\x02R\tfieldType\x12\x18\n\x06\ - frozen\x18\x06\x20\x01(\x08H\x03R\x06frozen\x12\x20\n\nvisibility\x18\ - \x07\x20\x01(\x08H\x04R\nvisibility\x12\x16\n\x05width\x18\x08\x20\x01(\ - \x05H\x05R\x05width\x12*\n\x10type_option_data\x18\t\x20\x01(\x0cH\x06R\ - \x0etypeOptionDataB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x13\n\x11one\ - _of_field_typeB\x0f\n\rone_of_frozenB\x13\n\x11one_of_visibilityB\x0e\n\ - \x0cone_of_widthB\x19\n\x17one_of_type_option_data\"\x9c\x01\n\x0fMoveIt\ - emPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x17\n\ - \x07item_id\x18\x02\x20\x01(\tR\x06itemId\x12\x1d\n\nfrom_index\x18\x03\ - \x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_index\x18\x04\x20\x01(\x05R\ - \x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\x0e2\r.MoveItemTypeR\x02ty\ - \"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06grid\ - Id\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_i\ - d\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\x04data\x18\x04\x20\x01(\tH\0\ - R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveItemType\x12\r\n\tMoveField\x10\ - \0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\ - \0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0c\ - SingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Check\ - box\x10\x05b\x06proto3\ + \x07content\x12\x12\n\x04data\x18\x03\x20\x01(\tR\x04data\"+\n\x0cRepeat\ + edCell\x12\x1b\n\x05items\x18\x01\x20\x03(\x0b2\x05.CellR\x05items\"'\n\ + \x11CreateGridPayload\x12\x12\n\x04name\x18\x01\x20\x01(\tR\x04name\"\ + \x1e\n\x06GridId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"#\n\ + \x0bGridBlockId\x12\x14\n\x05value\x18\x01\x20\x01(\tR\x05value\"f\n\x10\ + CreateRowPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\ + \"\n\x0cstart_row_id\x18\x02\x20\x01(\tH\0R\nstartRowIdB\x15\n\x13one_of\ + _start_row_id\"\xb6\x01\n\x12InsertFieldPayload\x12\x17\n\x07grid_id\x18\ + \x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.\ + FieldR\x05field\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etype\ + OptionData\x12&\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartField\ + IdB\x17\n\x15one_of_start_field_id\"d\n\x11QueryFieldPayload\x12\x17\n\ + \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orders\x18\x02\ + \x20\x01(\x0b2\x13.RepeatedFieldOrderR\x0bfieldOrders\"e\n\x16QueryGridB\ + locksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\ + \x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrder\ + s\"\xa8\x03\n\x15FieldChangesetPayload\x12\x19\n\x08field_id\x18\x01\x20\ + \x01(\tR\x07fieldId\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\ + \x12\x14\n\x04name\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\ + \x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\x0e2\n\ + .FieldTypeH\x02R\tfieldType\x12\x18\n\x06frozen\x18\x06\x20\x01(\x08H\ + \x03R\x06frozen\x12\x20\n\nvisibility\x18\x07\x20\x01(\x08H\x04R\nvisibi\ + lity\x12\x16\n\x05width\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10ty\ + pe_option_data\x18\t\x20\x01(\x0cH\x06R\x0etypeOptionDataB\r\n\x0bone_of\ + _nameB\r\n\x0bone_of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_fro\ + zenB\x13\n\x11one_of_visibilityB\x0e\n\x0cone_of_widthB\x19\n\x17one_of_\ + type_option_data\"\x9c\x01\n\x0fMoveItemPayload\x12\x17\n\x07grid_id\x18\ + \x01\x20\x01(\tR\x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06i\ + temId\x12\x1d\n\nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\ + \x08to_index\x18\x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\ + \x20\x01(\x0e2\r.MoveItemTypeR\x02ty\"\x7f\n\rCellChangeset\x12\x17\n\ + \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\ + \x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07field\ + Id\x12\x14\n\x04data\x18\x04\x20\x01(\tH\0R\x04dataB\r\n\x0bone_of_data*\ + *\n\x0cMoveItemType\x12\r\n\tMoveField\x10\0\x12\x0b\n\x07MoveRow\x10\ + \x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\ + \x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\ + \x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto index 3fb7740fe7..77c6943c04 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto +++ b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto @@ -94,6 +94,7 @@ message GridBlock { message Cell { string field_id = 1; string content = 2; + string data = 3; } message RepeatedCell { repeated Cell items = 1; From d3841154a578d6730d18085b05b3582bc5695481 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 9 May 2022 21:32:58 +0800 Subject: [PATCH 04/14] chore: config caladen ui --- .../clock_alarm.svg => grid/clock.svg} | 0 .../application/grid/cell/date_cal_bloc.dart | 14 +- .../src/widgets/cell/date_cell/calendar.dart | 220 ++++++++++++++---- .../grid/src/widgets/header/field_cell.dart | 2 +- .../widgets/header/field_editor_pannel.dart | 2 +- .../src/widgets/header/type_option/date.dart | 70 ++++-- .../widgets/header/type_option/number.dart | 2 +- .../lib/style_widget/button.dart | 6 +- 8 files changed, 246 insertions(+), 70 deletions(-) rename frontend/app_flowy/assets/images/{editor/clock_alarm.svg => grid/clock.svg} (100%) diff --git a/frontend/app_flowy/assets/images/editor/clock_alarm.svg b/frontend/app_flowy/assets/images/grid/clock.svg similarity index 100% rename from frontend/app_flowy/assets/images/editor/clock_alarm.svg rename to frontend/app_flowy/assets/images/grid/clock.svg diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index f3ce3d5faa..c33666669d 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -28,7 +28,7 @@ class DateCalBloc extends Bloc { emit(state.copyWith(selectedDay: value.day)); } }, - setFormat: (_CalendarFormat value) { + setCalFormat: (_CalendarFormat value) { emit(state.copyWith(format: value.format)); }, setFocusedDay: (_FocusedDay value) { @@ -38,6 +38,11 @@ class DateCalBloc extends Bloc { didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { emit(state.copyWith(field: value.field)); }, + setIncludeTime: (_IncludeTime value) { + emit(state.copyWith(includeTime: value.includeTime)); + }, + setDateFormat: (_DateFormat value) {}, + setTimeFormat: (_TimeFormat value) {}, ); }, ); @@ -97,8 +102,11 @@ class DateCalBloc extends Bloc { class DateCalEvent with _$DateCalEvent { const factory DateCalEvent.initial() = _Initial; const factory DateCalEvent.selectDay(DateTime day) = _SelectDay; - const factory DateCalEvent.setFormat(CalendarFormat format) = _CalendarFormat; + const factory DateCalEvent.setCalFormat(CalendarFormat format) = _CalendarFormat; const factory DateCalEvent.setFocusedDay(DateTime day) = _FocusedDay; + const factory DateCalEvent.setTimeFormat(TimeFormat value) = _TimeFormat; + const factory DateCalEvent.setDateFormat(DateFormat value) = _DateFormat; + const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime; const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; const factory DateCalEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; } @@ -111,6 +119,7 @@ class DateCalState with _$DateCalState { required CalendarFormat format, required DateTime focusedDay, required bool includeTime, + required Option time, DateTime? selectedDay, }) = _DateCalState; @@ -120,5 +129,6 @@ class DateCalState with _$DateCalState { format: CalendarFormat.month, focusedDay: DateTime.now(), includeTime: false, + time: none(), ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 7b052078d0..311f091e9b 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -1,6 +1,15 @@ +import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/workspace/application/grid/cell/date_cal_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart'; +import 'package:easy_localization/easy_localization.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/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:table_calendar/table_calendar.dart'; @@ -9,6 +18,7 @@ import 'package:app_flowy/workspace/application/grid/prelude.dart'; final kToday = DateTime.now(); final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); +const kMargin = EdgeInsets.symmetric(horizontal: 6, vertical: 10); class CellCalendar with FlowyOverlayDelegate { final VoidCallback onDismissed; @@ -47,7 +57,7 @@ class CellCalendar with FlowyOverlayDelegate { FlowyOverlay.of(context).insertWithAnchor( widget: OverlayContainer( child: calendar, - constraints: BoxConstraints.tight(const Size(320, 320)), + constraints: BoxConstraints.tight(const Size(320, 500)), ), identifier: CellCalendar.identifier(), anchorContext: context, @@ -67,6 +77,9 @@ class CellCalendar with FlowyOverlayDelegate { @override void didRemove() => onDismissed(); + + @override + bool asBarrier() => true; } class _CellCalendarWidget extends StatelessWidget { @@ -94,46 +107,175 @@ class _CellCalendarWidget extends StatelessWidget { }, listenWhen: (p, c) => p.selectedDay != c.selectedDay, builder: (context, state) { - return TableCalendar( - firstDay: kFirstDay, - lastDay: kLastDay, - focusedDay: state.focusedDay, - rowHeight: 40, - calendarFormat: state.format, - headerStyle: const HeaderStyle(formatButtonVisible: false), - calendarStyle: CalendarStyle( - selectedDecoration: BoxDecoration( - color: theme.main1, - shape: BoxShape.circle, - ), - todayDecoration: BoxDecoration( - color: theme.shader4, - shape: BoxShape.circle, - ), - selectedTextStyle: TextStyle( - color: theme.surface, - fontSize: 14.0, - ), - todayTextStyle: TextStyle( - color: theme.surface, - fontSize: 14.0, - ), - ), - selectedDayPredicate: (day) { - return isSameDay(state.selectedDay, day); - }, - onDaySelected: (selectedDay, focusedDay) { - context.read().add(DateCalEvent.selectDay(selectedDay)); - }, - onFormatChanged: (format) { - context.read().add(DateCalEvent.setFormat(format)); - }, - onPageChanged: (focusedDay) { - context.read().add(DateCalEvent.setFocusedDay(focusedDay)); - }, - ); + List children = []; + + children.addAll([ + _buildCalendar(state, theme, context), + const VSpace(10), + ]); + + if (state.includeTime) { + children.addAll([ + const _TimeTextField(), + const VSpace(10), + ]); + } + + children.addAll([ + Divider(height: 1, color: theme.shader5), + const _IncludeTimeButton(), + ]); + + state.typeOptinoData.fold(() => null, (dateTypeOption) { + children.add(_DateTypeOptionButton(dateTypeOption: dateTypeOption)); + }); + + return Column(children: children); }, ), ); } + + TableCalendar _buildCalendar(DateCalState state, AppTheme theme, BuildContext context) { + return TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: state.focusedDay, + rowHeight: 40, + calendarFormat: state.format, + headerStyle: HeaderStyle( + formatButtonVisible: false, + titleCentered: true, + leftChevronMargin: EdgeInsets.zero, + leftChevronPadding: EdgeInsets.zero, + leftChevronIcon: svgWidget("home/arrow_left"), + rightChevronPadding: EdgeInsets.zero, + rightChevronMargin: EdgeInsets.zero, + rightChevronIcon: svgWidget("home/arrow_right"), + ), + calendarStyle: CalendarStyle( + selectedDecoration: BoxDecoration( + color: theme.main1, + shape: BoxShape.circle, + ), + todayDecoration: BoxDecoration( + color: theme.shader4, + shape: BoxShape.circle, + ), + selectedTextStyle: TextStyle( + color: theme.surface, + fontSize: 14.0, + ), + todayTextStyle: TextStyle( + color: theme.surface, + fontSize: 14.0, + ), + ), + selectedDayPredicate: (day) { + return isSameDay(state.selectedDay, day); + }, + onDaySelected: (selectedDay, focusedDay) { + context.read().add(DateCalEvent.selectDay(selectedDay)); + }, + onFormatChanged: (format) { + context.read().add(DateCalEvent.setCalFormat(format)); + }, + onPageChanged: (focusedDay) { + context.read().add(DateCalEvent.setFocusedDay(focusedDay)); + }, + ); + } +} + +class _IncludeTimeButton extends StatelessWidget { + const _IncludeTimeButton({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return BlocSelector( + selector: (state) => state.includeTime, + builder: (context, includeTime) { + return SizedBox( + height: 50, + child: Padding( + padding: kMargin, + child: Row( + children: [ + svgWidget("grid/clock", color: theme.iconColor), + const HSpace(4), + FlowyText.medium(LocaleKeys.grid_field_includeTime.tr(), fontSize: 14), + const Spacer(), + Switch( + value: includeTime, + onChanged: (newValue) => context.read().add(DateCalEvent.setIncludeTime(newValue)), + ), + ], + ), + ), + ); + }, + ); + } +} + +class _TimeTextField extends StatelessWidget { + const _TimeTextField({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container(); + } +} + +class _DateTypeOptionButton extends StatelessWidget { + final DateTypeOption dateTypeOption; + const _DateTypeOptionButton({required this.dateTypeOption, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + final title = LocaleKeys.grid_field_dateFormat.tr() + " &" + LocaleKeys.grid_field_timeFormat.tr(); + return FlowyButton( + text: FlowyText.medium(title, fontSize: 12), + hoverColor: theme.hover, + margin: kMargin, + onTap: () { + final setting = _CalDateTimeSetting(dateTypeOption: dateTypeOption); + setting.show(context); + }, + rightIcon: svgWidget("grid/more", color: theme.iconColor), + ); + } +} + +class _CalDateTimeSetting extends StatelessWidget { + final DateTypeOption dateTypeOption; + const _CalDateTimeSetting({required this.dateTypeOption, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column(children: [ + DateFormatButton(onTap: () { + final list = DateFormatList( + selectedFormat: dateTypeOption.dateFormat, + onSelected: (format) { + context.read().add(DateTypeOptionEvent.didSelectDateFormat(format)); + }, + ); + }), + TimeFormatButton( + timeFormat: dateTypeOption.timeFormat, + onTap: () { + final list = TimeFormatList( + selectedFormat: dateTypeOption.timeFormat, + onSelected: (format) { + context.read().add(DateTypeOptionEvent.didSelectTimeFormat(format)); + }); + }, + ), + ]); + } + + void show(BuildContext context) {} } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart index aa45487fe2..eb264e6664 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -150,7 +150,7 @@ class FieldCellButton extends StatelessWidget { onTap: onTap, leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), text: FlowyText.medium(field.name, fontSize: 12), - padding: GridSize.cellContentInsets, + margin: GridSize.cellContentInsets, ); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart index fe00fe45a6..b64cd4ad50 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart @@ -80,7 +80,7 @@ class _FieldEditorPannelState extends State { height: GridSize.typeOptionItemHeight, child: FlowyButton( text: FlowyText.medium(field.fieldType.title(), fontSize: 12), - padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + margin: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), hoverColor: theme.hover, onTap: () { final list = FieldTypeList(onSelectField: (newFieldType) { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart index 2d920cbbf2..677e043703 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart @@ -50,8 +50,8 @@ class DateTypeOptionWidget extends TypeOptionWidget { listener: (context, state) => dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()), builder: (context, state) { return Column(children: [ - _dateFormatButton(context, state.typeOption.dateFormat), - _timeFormatButton(context, state.typeOption.timeFormat), + _renderDateFormatButton(context, state.typeOption.dateFormat), + _renderTimeFormatButton(context, state.typeOption.timeFormat), const _IncludeTimeButton(), ]); }, @@ -59,44 +59,68 @@ class DateTypeOptionWidget extends TypeOptionWidget { ); } - Widget _dateFormatButton(BuildContext context, DateFormat dataFormat) { + Widget _renderDateFormatButton(BuildContext context, DateFormat dataFormat) { + return DateFormatButton(onTap: () { + final list = DateFormatList( + selectedFormat: dataFormat, + onSelected: (format) { + context.read().add(DateTypeOptionEvent.didSelectDateFormat(format)); + }, + ); + overlayDelegate.showOverlay(context, list); + }); + } + + Widget _renderTimeFormatButton(BuildContext context, TimeFormat timeFormat) { + return TimeFormatButton( + timeFormat: timeFormat, + onTap: () { + final list = TimeFormatList( + selectedFormat: timeFormat, + onSelected: (format) { + context.read().add(DateTypeOptionEvent.didSelectTimeFormat(format)); + }); + overlayDelegate.showOverlay(context, list); + }, + ); + } +} + +class DateFormatButton extends StatelessWidget { + final VoidCallback onTap; + const DateFormatButton({required this.onTap, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { final theme = context.watch(); return SizedBox( height: GridSize.typeOptionItemHeight, child: FlowyButton( text: FlowyText.medium(LocaleKeys.grid_field_dateFormat.tr(), fontSize: 12), - padding: GridSize.typeOptionContentInsets, + margin: GridSize.typeOptionContentInsets, hoverColor: theme.hover, - onTap: () { - final list = DateFormatList( - selectedFormat: dataFormat, - onSelected: (format) { - context.read().add(DateTypeOptionEvent.didSelectDateFormat(format)); - }, - ); - overlayDelegate.showOverlay(context, list); - }, + onTap: onTap, rightIcon: svgWidget("grid/more", color: theme.iconColor), ), ); } +} - Widget _timeFormatButton(BuildContext context, TimeFormat timeFormat) { +class TimeFormatButton extends StatelessWidget { + final TimeFormat timeFormat; + final VoidCallback onTap; + const TimeFormatButton({required this.timeFormat, required this.onTap, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { final theme = context.watch(); return SizedBox( height: GridSize.typeOptionItemHeight, child: FlowyButton( text: FlowyText.medium(LocaleKeys.grid_field_timeFormat.tr(), fontSize: 12), - padding: GridSize.typeOptionContentInsets, + margin: GridSize.typeOptionContentInsets, hoverColor: theme.hover, - onTap: () { - final list = TimeFormatList( - selectedFormat: timeFormat, - onSelected: (format) { - context.read().add(DateTypeOptionEvent.didSelectTimeFormat(format)); - }); - overlayDelegate.showOverlay(context, list); - }, + onTap: onTap, rightIcon: svgWidget("grid/more", color: theme.iconColor), ), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart index b887fd53a9..9e3ced1c43 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/number.dart @@ -60,7 +60,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget { FlowyText.regular(state.typeOption.format.title(), fontSize: 12), ], ), - padding: GridSize.typeOptionContentInsets, + margin: GridSize.typeOptionContentInsets, hoverColor: theme.hover, onTap: () { final list = NumberFormatList( diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart index 8249bc115b..9a7407f9bb 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/button.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; class FlowyButton extends StatelessWidget { final Widget text; final VoidCallback? onTap; - final EdgeInsets padding; + final EdgeInsets margin; final Widget? leftIcon; final Widget? rightIcon; final Color hoverColor; @@ -16,7 +16,7 @@ class FlowyButton extends StatelessWidget { Key? key, required this.text, this.onTap, - this.padding = const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + this.margin = const EdgeInsets.symmetric(horizontal: 6, vertical: 2), this.leftIcon, this.rightIcon, this.hoverColor = Colors.transparent, @@ -50,7 +50,7 @@ class FlowyButton extends StatelessWidget { } return Padding( - padding: padding, + padding: margin, child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, From 81d75147d5323bbb6e5c3d15587fa569711f598a Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 10 May 2022 09:33:34 +0800 Subject: [PATCH 05/14] chore: update typeOption data --- .../application/grid/cell/date_cal_bloc.dart | 70 ++-- .../application/grid/field/field_service.dart | 13 + .../src/widgets/cell/date_cell/calendar.dart | 171 ++++++---- .../dart_event/flowy-grid/dart_event.dart | 17 + .../flowy-grid-data-model/grid.pb.dart | 75 +++++ .../flowy-grid-data-model/grid.pbjson.dart | 12 + .../protobuf/flowy-grid/event_map.pbenum.dart | 16 +- .../protobuf/flowy-grid/event_map.pbjson.dart | 17 +- .../rust-lib/flowy-grid/src/event_handler.rs | 13 + frontend/rust-lib/flowy-grid/src/event_map.rs | 18 +- .../src/protobuf/model/event_map.rs | 51 +-- .../src/protobuf/proto/event_map.proto | 15 +- .../flowy-grid/src/services/grid_editor.rs | 28 ++ .../src/entities/grid.rs | 34 ++ .../src/protobuf/model/grid.rs | 300 ++++++++++++++++-- .../src/protobuf/proto/grid.proto | 5 + 16 files changed, 701 insertions(+), 154 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index c33666669d..da1238e758 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -1,5 +1,6 @@ +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -8,6 +9,7 @@ import 'dart:async'; import 'cell_service.dart'; import 'package:dartz/dartz.dart'; import 'package:fixnum/fixnum.dart' as $fixnum; +import 'package:protobuf/protobuf.dart'; part 'date_cal_bloc.freezed.dart'; class DateCalBloc extends Bloc { @@ -35,14 +37,15 @@ class DateCalBloc extends Bloc { emit(state.copyWith(focusedDay: value.day)); }, didReceiveCellUpdate: (_DidReceiveCellUpdate value) {}, - didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - emit(state.copyWith(field: value.field)); + setIncludeTime: (_IncludeTime value) async { + await _updateTypeOption(emit, includeTime: value.includeTime); }, - setIncludeTime: (_IncludeTime value) { - emit(state.copyWith(includeTime: value.includeTime)); + setDateFormat: (_DateFormat value) async { + await _updateTypeOption(emit, dateFormat: value.dateFormat); + }, + setTimeFormat: (_TimeFormat value) async { + await _updateTypeOption(emit, timeFormat: value.timeFormat); }, - setDateFormat: (_DateFormat value) {}, - setTimeFormat: (_TimeFormat value) {}, ); }, ); @@ -83,8 +86,7 @@ class DateCalBloc extends Bloc { } emit(state.copyWith( - typeOptinoData: some(typeOptionData), - includeTime: typeOptionData.includeTime, + dateTypeOption: some(typeOptionData), selectedDay: selectedDay, )); }, @@ -96,6 +98,43 @@ class DateCalBloc extends Bloc { final data = day.millisecondsSinceEpoch ~/ 1000; cellContext.saveCellData(data.toString()); } + + Future? _updateTypeOption( + Emitter emit, { + DateFormat? dateFormat, + TimeFormat? timeFormat, + bool? includeTime, + }) async { + final newDateTypeOption = state.dateTypeOption.fold(() => null, (dateTypeOption) { + dateTypeOption.freeze(); + return dateTypeOption.rebuild((typeOption) { + if (dateFormat != null) { + typeOption.dateFormat = dateFormat; + } + + if (timeFormat != null) { + typeOption.timeFormat = timeFormat; + } + + if (includeTime != null) { + typeOption.includeTime = includeTime; + } + }); + }); + + if (newDateTypeOption != null) { + final result = await FieldService.updateFieldTypeOption( + gridId: cellContext.gridId, + fieldId: cellContext.field.id, + typeOptionData: newDateTypeOption.writeToBuffer(), + ); + + result.fold( + (l) => emit(state.copyWith(dateTypeOption: Some(newDateTypeOption))), + (err) => Log.error(err), + ); + } + } } @freezed @@ -104,31 +143,26 @@ class DateCalEvent with _$DateCalEvent { const factory DateCalEvent.selectDay(DateTime day) = _SelectDay; const factory DateCalEvent.setCalFormat(CalendarFormat format) = _CalendarFormat; const factory DateCalEvent.setFocusedDay(DateTime day) = _FocusedDay; - const factory DateCalEvent.setTimeFormat(TimeFormat value) = _TimeFormat; - const factory DateCalEvent.setDateFormat(DateFormat value) = _DateFormat; + const factory DateCalEvent.setTimeFormat(TimeFormat timeFormat) = _TimeFormat; + const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat; const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime; const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; - const factory DateCalEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; } @freezed class DateCalState with _$DateCalState { const factory DateCalState({ - required Field field, - required Option typeOptinoData, + required Option dateTypeOption, required CalendarFormat format, required DateTime focusedDay, - required bool includeTime, required Option time, DateTime? selectedDay, }) = _DateCalState; factory DateCalState.initial(GridCellContext context) => DateCalState( - field: context.field, - typeOptinoData: none(), + dateTypeOption: none(), format: CalendarFormat.month, focusedDay: DateTime.now(), - includeTime: false, time: none(), ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index ef198d5c3a..70c6caf9f8 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -99,6 +99,19 @@ class FieldService { return GridEventInsertField(payload).send(); } + static Future> updateFieldTypeOption({ + required String gridId, + required String fieldId, + required List typeOptionData, + }) { + var payload = UpdateFieldTypeOptionPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..typeOptionData = typeOptionData; + + return GridEventUpdateFieldTypeOption(payload).send(); + } + Future> deleteField() { final payload = FieldIdentifierPayload.create() ..gridId = gridId diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 311f091e9b..68875d4ce3 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/workspace/application/grid/cell/date_cal_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/image.dart'; @@ -10,10 +11,10 @@ import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:dartz/dartz.dart' show Option; final kToday = DateTime.now(); final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); @@ -39,25 +40,11 @@ class CellCalendar with FlowyOverlayDelegate { includeTime: false, cellContext: cellContext, ); - // const size = Size(460, 400); - // final window = await getWindowInfo(); - // FlowyOverlay.of(context).insertWithRect( - // widget: OverlayContainer( - // child: calendar, - // constraints: BoxConstraints.loose(const Size(460, 400)), - // ), - // identifier: _CellCalendar.identifier(), - // anchorPosition: Offset(-size.width / 2.0, -size.height / 2.0), - // anchorSize: window.frame.size, - // anchorDirection: AnchorDirection.center, - // style: FlowyOverlayStyle(blur: false), - // delegate: calendar, - // ); FlowyOverlay.of(context).insertWithAnchor( widget: OverlayContainer( child: calendar, - constraints: BoxConstraints.tight(const Size(320, 500)), + constraints: BoxConstraints.loose(const Size(320, 500)), ), identifier: CellCalendar.identifier(), anchorContext: context, @@ -114,23 +101,31 @@ class _CellCalendarWidget extends StatelessWidget { const VSpace(10), ]); - if (state.includeTime) { + state.dateTypeOption.foldRight(null, (dateTypeOption, _) { children.addAll([ const _TimeTextField(), const VSpace(10), ]); - } + }); children.addAll([ Divider(height: 1, color: theme.shader5), const _IncludeTimeButton(), ]); - state.typeOptinoData.fold(() => null, (dateTypeOption) { - children.add(_DateTypeOptionButton(dateTypeOption: dateTypeOption)); - }); + children.add(const _DateTypeOptionButton()); - return Column(children: children); + return ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: children.length, + itemBuilder: (BuildContext context, int index) { + return children[index]; + }, + ); }, ), ); @@ -194,7 +189,7 @@ class _IncludeTimeButton extends StatelessWidget { Widget build(BuildContext context) { final theme = context.watch(); return BlocSelector( - selector: (state) => state.includeTime, + selector: (state) => state.dateTypeOption.foldRight(false, (option, _) => option.includeTime), builder: (context, includeTime) { return SizedBox( height: 50, @@ -229,53 +224,117 @@ class _TimeTextField extends StatelessWidget { } class _DateTypeOptionButton extends StatelessWidget { - final DateTypeOption dateTypeOption; - const _DateTypeOptionButton({required this.dateTypeOption, Key? key}) : super(key: key); + const _DateTypeOptionButton({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final theme = context.watch(); final title = LocaleKeys.grid_field_dateFormat.tr() + " &" + LocaleKeys.grid_field_timeFormat.tr(); - return FlowyButton( - text: FlowyText.medium(title, fontSize: 12), - hoverColor: theme.hover, - margin: kMargin, - onTap: () { - final setting = _CalDateTimeSetting(dateTypeOption: dateTypeOption); - setting.show(context); + return BlocSelector>( + selector: (state) => state.dateTypeOption, + builder: (context, dateTypeOption) { + return FlowyButton( + text: FlowyText.medium(title, fontSize: 12), + hoverColor: theme.hover, + margin: kMargin, + onTap: () { + dateTypeOption.fold(() => null, (dateTypeOption) { + final setting = _CalDateTimeSetting(dateTypeOption: dateTypeOption); + setting.show(context); + }); + }, + rightIcon: svgWidget("grid/more", color: theme.iconColor), + ); }, - rightIcon: svgWidget("grid/more", color: theme.iconColor), ); } } -class _CalDateTimeSetting extends StatelessWidget { +class _CalDateTimeSetting extends StatefulWidget { final DateTypeOption dateTypeOption; const _CalDateTimeSetting({required this.dateTypeOption, Key? key}) : super(key: key); @override - Widget build(BuildContext context) { - return Column(children: [ - DateFormatButton(onTap: () { - final list = DateFormatList( - selectedFormat: dateTypeOption.dateFormat, - onSelected: (format) { - context.read().add(DateTypeOptionEvent.didSelectDateFormat(format)); - }, - ); - }), - TimeFormatButton( - timeFormat: dateTypeOption.timeFormat, - onTap: () { - final list = TimeFormatList( - selectedFormat: dateTypeOption.timeFormat, - onSelected: (format) { - context.read().add(DateTypeOptionEvent.didSelectTimeFormat(format)); - }); - }, - ), - ]); + State<_CalDateTimeSetting> createState() => _CalDateTimeSettingState(); + + static String identifier() { + return (_CalDateTimeSetting).toString(); } - void show(BuildContext context) {} + void show(BuildContext context) { + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: this, + constraints: BoxConstraints.loose(const Size(140, 100)), + ), + identifier: _CalDateTimeSetting.identifier(), + anchorContext: context, + anchorDirection: AnchorDirection.rightWithCenterAligned, + ); + } +} + +class _CalDateTimeSettingState extends State<_CalDateTimeSetting> { + String? overlayIdentifier; + + @override + Widget build(BuildContext context) { + List children = [ + DateFormatButton(onTap: () { + final list = DateFormatList( + selectedFormat: widget.dateTypeOption.dateFormat, + onSelected: (format) { + context.read().add(DateCalEvent.setDateFormat(format)); + }, + ); + _showOverlay(context, list); + }), + TimeFormatButton( + timeFormat: widget.dateTypeOption.timeFormat, + onTap: () { + final list = TimeFormatList( + selectedFormat: widget.dateTypeOption.timeFormat, + onSelected: (format) { + context.read().add(DateCalEvent.setTimeFormat(format)); + }, + ); + _showOverlay(context, list); + }, + ), + ]; + + return SizedBox( + width: 180, + child: ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: children.length, + itemBuilder: (BuildContext context, int index) { + return children[index]; + }, + ), + ); + } + + void _showOverlay(BuildContext context, Widget child) { + if (overlayIdentifier != null) { + FlowyOverlay.of(context).remove(overlayIdentifier!); + } + + overlayIdentifier = child.toString(); + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: child, + constraints: BoxConstraints.loose(const Size(460, 440)), + ), + identifier: overlayIdentifier!, + anchorContext: context, + anchorDirection: AnchorDirection.rightWithCenterAligned, + style: FlowyOverlayStyle(blur: false), + anchorOffset: const Offset(-20, 0), + ); + } } diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart index 339f2b451c..ddc642d913 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart @@ -69,6 +69,23 @@ class GridEventUpdateField { } } +class GridEventUpdateFieldTypeOption { + UpdateFieldTypeOptionPayload request; + GridEventUpdateFieldTypeOption(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.UpdateFieldTypeOption.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + class GridEventInsertField { InsertFieldPayload request; GridEventInsertField(this.request); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart index 968044a972..5cf3a2a83b 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart @@ -1781,6 +1781,81 @@ class InsertFieldPayload extends $pb.GeneratedMessage { void clearStartFieldId() => clearField(4); } +class UpdateFieldTypeOptionPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'UpdateFieldTypeOptionPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') + ..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'typeOptionData', $pb.PbFieldType.OY) + ..hasRequiredFields = false + ; + + UpdateFieldTypeOptionPayload._() : super(); + factory UpdateFieldTypeOptionPayload({ + $core.String? gridId, + $core.String? fieldId, + $core.List<$core.int>? typeOptionData, + }) { + final _result = create(); + if (gridId != null) { + _result.gridId = gridId; + } + if (fieldId != null) { + _result.fieldId = fieldId; + } + if (typeOptionData != null) { + _result.typeOptionData = typeOptionData; + } + return _result; + } + factory UpdateFieldTypeOptionPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory UpdateFieldTypeOptionPayload.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') + UpdateFieldTypeOptionPayload clone() => UpdateFieldTypeOptionPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + UpdateFieldTypeOptionPayload copyWith(void Function(UpdateFieldTypeOptionPayload) updates) => super.copyWith((message) => updates(message as UpdateFieldTypeOptionPayload)) as UpdateFieldTypeOptionPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static UpdateFieldTypeOptionPayload create() => UpdateFieldTypeOptionPayload._(); + UpdateFieldTypeOptionPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static UpdateFieldTypeOptionPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static UpdateFieldTypeOptionPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get gridId => $_getSZ(0); + @$pb.TagNumber(1) + set gridId($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasGridId() => $_has(0); + @$pb.TagNumber(1) + void clearGridId() => clearField(1); + + @$pb.TagNumber(2) + $core.String get fieldId => $_getSZ(1); + @$pb.TagNumber(2) + set fieldId($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasFieldId() => $_has(1); + @$pb.TagNumber(2) + void clearFieldId() => clearField(2); + + @$pb.TagNumber(3) + $core.List<$core.int> get typeOptionData => $_getN(2); + @$pb.TagNumber(3) + set typeOptionData($core.List<$core.int> v) { $_setBytes(2, v); } + @$pb.TagNumber(3) + $core.bool hasTypeOptionData() => $_has(2); + @$pb.TagNumber(3) + void clearTypeOptionData() => clearField(3); +} + class QueryFieldPayload extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryFieldPayload', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart index 29dcde046c..9043564b43 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart @@ -367,6 +367,18 @@ const InsertFieldPayload$json = const { /// Descriptor for `InsertFieldPayload`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List insertFieldPayloadDescriptor = $convert.base64Decode('ChJJbnNlcnRGaWVsZFBheWxvYWQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEhwKBWZpZWxkGAIgASgLMgYuRmllbGRSBWZpZWxkEigKEHR5cGVfb3B0aW9uX2RhdGEYAyABKAxSDnR5cGVPcHRpb25EYXRhEiYKDnN0YXJ0X2ZpZWxkX2lkGAQgASgJSABSDHN0YXJ0RmllbGRJZEIXChVvbmVfb2Zfc3RhcnRfZmllbGRfaWQ='); +@$core.Deprecated('Use updateFieldTypeOptionPayloadDescriptor instead') +const UpdateFieldTypeOptionPayload$json = const { + '1': 'UpdateFieldTypeOptionPayload', + '2': const [ + const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, + const {'1': 'field_id', '3': 2, '4': 1, '5': 9, '10': 'fieldId'}, + const {'1': 'type_option_data', '3': 3, '4': 1, '5': 12, '10': 'typeOptionData'}, + ], +}; + +/// Descriptor for `UpdateFieldTypeOptionPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List updateFieldTypeOptionPayloadDescriptor = $convert.base64Decode('ChxVcGRhdGVGaWVsZFR5cGVPcHRpb25QYXlsb2FkEhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIZCghmaWVsZF9pZBgCIAEoCVIHZmllbGRJZBIoChB0eXBlX29wdGlvbl9kYXRhGAMgASgMUg50eXBlT3B0aW9uRGF0YQ=='); @$core.Deprecated('Use queryFieldPayloadDescriptor instead') const QueryFieldPayload$json = const { '1': 'QueryFieldPayload', diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart index b907873844..4e0db67667 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart @@ -14,13 +14,14 @@ class GridEvent extends $pb.ProtobufEnum { static const GridEvent GetGridBlocks = GridEvent._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetGridBlocks'); static const GridEvent GetFields = GridEvent._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFields'); static const GridEvent UpdateField = GridEvent._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateField'); - static const GridEvent InsertField = GridEvent._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InsertField'); - static const GridEvent DeleteField = GridEvent._(13, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteField'); - static const GridEvent SwitchToField = GridEvent._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SwitchToField'); - static const GridEvent DuplicateField = GridEvent._(15, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField'); - static const GridEvent GetEditFieldContext = GridEvent._(16, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetEditFieldContext'); - static const GridEvent MoveItem = GridEvent._(17, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem'); - static const GridEvent GetFieldTypeOption = GridEvent._(18, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFieldTypeOption'); + static const GridEvent UpdateFieldTypeOption = GridEvent._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateFieldTypeOption'); + static const GridEvent InsertField = GridEvent._(13, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InsertField'); + static const GridEvent DeleteField = GridEvent._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteField'); + static const GridEvent SwitchToField = GridEvent._(20, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SwitchToField'); + static const GridEvent DuplicateField = GridEvent._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField'); + static const GridEvent GetEditFieldContext = GridEvent._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetEditFieldContext'); + static const GridEvent MoveItem = GridEvent._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem'); + static const GridEvent GetFieldTypeOption = GridEvent._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFieldTypeOption'); static const GridEvent NewSelectOption = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewSelectOption'); static const GridEvent GetSelectOptionContext = GridEvent._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetSelectOptionContext'); static const GridEvent UpdateSelectOption = GridEvent._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOption'); @@ -37,6 +38,7 @@ class GridEvent extends $pb.ProtobufEnum { GetGridBlocks, GetFields, UpdateField, + UpdateFieldTypeOption, InsertField, DeleteField, SwitchToField, diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart index 9d63053af5..6c3f668b74 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart @@ -16,13 +16,14 @@ const GridEvent$json = const { const {'1': 'GetGridBlocks', '2': 1}, const {'1': 'GetFields', '2': 10}, const {'1': 'UpdateField', '2': 11}, - const {'1': 'InsertField', '2': 12}, - const {'1': 'DeleteField', '2': 13}, - const {'1': 'SwitchToField', '2': 14}, - const {'1': 'DuplicateField', '2': 15}, - const {'1': 'GetEditFieldContext', '2': 16}, - const {'1': 'MoveItem', '2': 17}, - const {'1': 'GetFieldTypeOption', '2': 18}, + const {'1': 'UpdateFieldTypeOption', '2': 12}, + const {'1': 'InsertField', '2': 13}, + const {'1': 'DeleteField', '2': 14}, + const {'1': 'SwitchToField', '2': 20}, + const {'1': 'DuplicateField', '2': 21}, + const {'1': 'GetEditFieldContext', '2': 22}, + const {'1': 'MoveItem', '2': 23}, + const {'1': 'GetFieldTypeOption', '2': 24}, const {'1': 'NewSelectOption', '2': 30}, const {'1': 'GetSelectOptionContext', '2': 31}, const {'1': 'UpdateSelectOption', '2': 32}, @@ -37,4 +38,4 @@ const GridEvent$json = const { }; /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtJbnNlcnRGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEQoNU3dpdGNoVG9GaWVsZBAOEhIKDkR1cGxpY2F0ZUZpZWxkEA8SFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAQEgwKCE1vdmVJdGVtEBESFgoSR2V0RmllbGRUeXBlT3B0aW9uEBISEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlQ2VsbFNlbGVjdE9wdGlvbhBI'); +final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAWEgwKCE1vdmVJdGVtEBcSFgoSR2V0RmllbGRUeXBlT3B0aW9uEBgSEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlQ2VsbFNlbGVjdE9wdGlvbhBI'); diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index fd7b838b82..f60f31e87a 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -70,6 +70,19 @@ pub(crate) async fn insert_field_handler( Ok(()) } +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn update_field_type_option_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: UpdateFieldTypeOptionParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + let _ = editor + .update_field_type_option(¶ms.grid_id, ¶ms.field_id, params.type_option_data) + .await?; + Ok(()) +} + #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn delete_field_handler( data: Data, diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index a90c90ebe2..dab3cefd78 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -14,6 +14,7 @@ pub fn create(grid_manager: Arc) -> Module { .event(GridEvent::GetFields, get_fields_handler) .event(GridEvent::UpdateField, update_field_handler) .event(GridEvent::InsertField, insert_field_handler) + .event(GridEvent::UpdateFieldTypeOption, update_field_type_option_handler) .event(GridEvent::DeleteField, delete_field_handler) .event(GridEvent::SwitchToField, switch_to_field_handler) .event(GridEvent::DuplicateField, duplicate_field_handler) @@ -52,26 +53,29 @@ pub enum GridEvent { #[event(input = "FieldChangesetPayload")] UpdateField = 11, + #[event(input = "UpdateFieldTypeOptionPayload")] + UpdateFieldTypeOption = 12, + #[event(input = "InsertFieldPayload")] - InsertField = 12, + InsertField = 13, #[event(input = "FieldIdentifierPayload")] - DeleteField = 13, + DeleteField = 14, #[event(input = "EditFieldPayload", output = "EditFieldContext")] - SwitchToField = 14, + SwitchToField = 20, #[event(input = "FieldIdentifierPayload")] - DuplicateField = 15, + DuplicateField = 21, #[event(input = "EditFieldPayload", output = "EditFieldContext")] - GetEditFieldContext = 16, + GetEditFieldContext = 22, #[event(input = "MoveItemPayload")] - MoveItem = 17, + MoveItem = 23, #[event(input = "EditFieldPayload", output = "FieldTypeOptionData")] - GetFieldTypeOption = 18, + GetFieldTypeOption = 24, #[event(input = "CreateSelectOptionPayload", output = "SelectOption")] NewSelectOption = 30, diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs index 739f8d9767..bf1cb2c71a 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs @@ -29,13 +29,14 @@ pub enum GridEvent { GetGridBlocks = 1, GetFields = 10, UpdateField = 11, - InsertField = 12, - DeleteField = 13, - SwitchToField = 14, - DuplicateField = 15, - GetEditFieldContext = 16, - MoveItem = 17, - GetFieldTypeOption = 18, + UpdateFieldTypeOption = 12, + InsertField = 13, + DeleteField = 14, + SwitchToField = 20, + DuplicateField = 21, + GetEditFieldContext = 22, + MoveItem = 23, + GetFieldTypeOption = 24, NewSelectOption = 30, GetSelectOptionContext = 31, UpdateSelectOption = 32, @@ -59,13 +60,14 @@ impl ::protobuf::ProtobufEnum for GridEvent { 1 => ::std::option::Option::Some(GridEvent::GetGridBlocks), 10 => ::std::option::Option::Some(GridEvent::GetFields), 11 => ::std::option::Option::Some(GridEvent::UpdateField), - 12 => ::std::option::Option::Some(GridEvent::InsertField), - 13 => ::std::option::Option::Some(GridEvent::DeleteField), - 14 => ::std::option::Option::Some(GridEvent::SwitchToField), - 15 => ::std::option::Option::Some(GridEvent::DuplicateField), - 16 => ::std::option::Option::Some(GridEvent::GetEditFieldContext), - 17 => ::std::option::Option::Some(GridEvent::MoveItem), - 18 => ::std::option::Option::Some(GridEvent::GetFieldTypeOption), + 12 => ::std::option::Option::Some(GridEvent::UpdateFieldTypeOption), + 13 => ::std::option::Option::Some(GridEvent::InsertField), + 14 => ::std::option::Option::Some(GridEvent::DeleteField), + 20 => ::std::option::Option::Some(GridEvent::SwitchToField), + 21 => ::std::option::Option::Some(GridEvent::DuplicateField), + 22 => ::std::option::Option::Some(GridEvent::GetEditFieldContext), + 23 => ::std::option::Option::Some(GridEvent::MoveItem), + 24 => ::std::option::Option::Some(GridEvent::GetFieldTypeOption), 30 => ::std::option::Option::Some(GridEvent::NewSelectOption), 31 => ::std::option::Option::Some(GridEvent::GetSelectOptionContext), 32 => ::std::option::Option::Some(GridEvent::UpdateSelectOption), @@ -86,6 +88,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { GridEvent::GetGridBlocks, GridEvent::GetFields, GridEvent::UpdateField, + GridEvent::UpdateFieldTypeOption, GridEvent::InsertField, GridEvent::DeleteField, GridEvent::SwitchToField, @@ -131,17 +134,17 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\x95\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ + \n\x0fevent_map.proto*\xb0\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\ - \x0bUpdateField\x10\x0b\x12\x0f\n\x0bInsertField\x10\x0c\x12\x0f\n\x0bDe\ - leteField\x10\r\x12\x11\n\rSwitchToField\x10\x0e\x12\x12\n\x0eDuplicateF\ - ield\x10\x0f\x12\x17\n\x13GetEditFieldContext\x10\x10\x12\x0c\n\x08MoveI\ - tem\x10\x11\x12\x16\n\x12GetFieldTypeOption\x10\x12\x12\x13\n\x0fNewSele\ - ctOption\x10\x1e\x12\x1a\n\x16GetSelectOptionContext\x10\x1f\x12\x16\n\ - \x12UpdateSelectOption\x10\x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\ - \x103\x12\r\n\tDeleteRow\x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\ - \x07GetCell\x10F\x12\x0e\n\nUpdateCell\x10G\x12\x1a\n\x16UpdateCellSelec\ - tOption\x10Hb\x06proto3\ + \x0bUpdateField\x10\x0b\x12\x19\n\x15UpdateFieldTypeOption\x10\x0c\x12\ + \x0f\n\x0bInsertField\x10\r\x12\x0f\n\x0bDeleteField\x10\x0e\x12\x11\n\r\ + SwitchToField\x10\x14\x12\x12\n\x0eDuplicateField\x10\x15\x12\x17\n\x13G\ + etEditFieldContext\x10\x16\x12\x0c\n\x08MoveItem\x10\x17\x12\x16\n\x12Ge\ + tFieldTypeOption\x10\x18\x12\x13\n\x0fNewSelectOption\x10\x1e\x12\x1a\n\ + \x16GetSelectOptionContext\x10\x1f\x12\x16\n\x12UpdateSelectOption\x10\ + \x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteRow\ + \x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\ + \nUpdateCell\x10G\x12\x1a\n\x16UpdateCellSelectOption\x10Hb\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto index 233de825a2..ab804c2b82 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto @@ -5,13 +5,14 @@ enum GridEvent { GetGridBlocks = 1; GetFields = 10; UpdateField = 11; - InsertField = 12; - DeleteField = 13; - SwitchToField = 14; - DuplicateField = 15; - GetEditFieldContext = 16; - MoveItem = 17; - GetFieldTypeOption = 18; + UpdateFieldTypeOption = 12; + InsertField = 13; + DeleteField = 14; + SwitchToField = 20; + DuplicateField = 21; + GetEditFieldContext = 22; + MoveItem = 23; + GetFieldTypeOption = 24; NewSelectOption = 30; GetSelectOptionContext = 31; UpdateSelectOption = 32; diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 5962386352..ab41542174 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -93,6 +93,34 @@ impl ClientGridEditor { Ok(()) } + pub async fn update_field_type_option( + &self, + grid_id: &str, + field_id: &str, + type_option_data: Vec, + ) -> FlowyResult<()> { + let result = self.get_field_meta(field_id).await; + if result.is_none() { + tracing::warn!("Can't find the field with id: {}", field_id); + return Ok(()); + } + let field_meta = result.unwrap(); + let _ = self + .modify(|grid| { + let deserializer = TypeOptionJsonDeserializer(field_meta.field_type.clone()); + let changeset = FieldChangesetParams { + field_id: field_id.to_owned(), + grid_id: grid_id.to_owned(), + type_option_data: Some(type_option_data), + ..Default::default() + }; + Ok(grid.update_field_meta(changeset, deserializer)?) + }) + .await?; + let _ = self.notify_did_update_grid_field(&field_id).await?; + Ok(()) + } + pub async fn create_next_field_meta(&self, field_type: &FieldType) -> FlowyResult { let name = format!("Property {}", self.grid_pad.read().await.fields().len() + 1); let field_meta = FieldBuilder::from_field_type(field_type).name(&name).build(); diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs index 09f6f8f40c..42c280aec5 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -616,6 +616,40 @@ impl TryInto for InsertFieldPayload { } } +#[derive(ProtoBuf, Default)] +pub struct UpdateFieldTypeOptionPayload { + #[pb(index = 1)] + pub grid_id: String, + + #[pb(index = 2)] + pub field_id: String, + + #[pb(index = 3)] + pub type_option_data: Vec, +} + +#[derive(Clone)] +pub struct UpdateFieldTypeOptionParams { + pub grid_id: String, + pub field_id: String, + pub type_option_data: Vec, +} + +impl TryInto for UpdateFieldTypeOptionPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; + let _ = NotEmptyStr::parse(self.field_id.clone()).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + + Ok(UpdateFieldTypeOptionParams { + grid_id: grid_id.0, + field_id: self.field_id, + type_option_data: self.type_option_data, + }) + } +} + #[derive(ProtoBuf, Default)] pub struct QueryFieldPayload { #[pb(index = 1)] diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs index 5d3d3df43a..8391c13453 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs @@ -6154,6 +6154,249 @@ impl ::protobuf::reflect::ProtobufValue for InsertFieldPayload { } } +#[derive(PartialEq,Clone,Default)] +pub struct UpdateFieldTypeOptionPayload { + // message fields + pub grid_id: ::std::string::String, + pub field_id: ::std::string::String, + pub type_option_data: ::std::vec::Vec, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a UpdateFieldTypeOptionPayload { + fn default() -> &'a UpdateFieldTypeOptionPayload { + ::default_instance() + } +} + +impl UpdateFieldTypeOptionPayload { + pub fn new() -> UpdateFieldTypeOptionPayload { + ::std::default::Default::default() + } + + // string grid_id = 1; + + + pub fn get_grid_id(&self) -> &str { + &self.grid_id + } + pub fn clear_grid_id(&mut self) { + self.grid_id.clear(); + } + + // Param is passed by value, moved + pub fn set_grid_id(&mut self, v: ::std::string::String) { + self.grid_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { + &mut self.grid_id + } + + // Take field + pub fn take_grid_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + } + + // string field_id = 2; + + + pub fn get_field_id(&self) -> &str { + &self.field_id + } + pub fn clear_field_id(&mut self) { + self.field_id.clear(); + } + + // Param is passed by value, moved + pub fn set_field_id(&mut self, v: ::std::string::String) { + self.field_id = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_field_id(&mut self) -> &mut ::std::string::String { + &mut self.field_id + } + + // Take field + pub fn take_field_id(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) + } + + // bytes type_option_data = 3; + + + pub fn get_type_option_data(&self) -> &[u8] { + &self.type_option_data + } + pub fn clear_type_option_data(&mut self) { + self.type_option_data.clear(); + } + + // Param is passed by value, moved + pub fn set_type_option_data(&mut self, v: ::std::vec::Vec) { + self.type_option_data = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_type_option_data(&mut self) -> &mut ::std::vec::Vec { + &mut self.type_option_data + } + + // Take field + pub fn take_type_option_data(&mut self) -> ::std::vec::Vec { + ::std::mem::replace(&mut self.type_option_data, ::std::vec::Vec::new()) + } +} + +impl ::protobuf::Message for UpdateFieldTypeOptionPayload { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; + }, + 3 => { + ::protobuf::rt::read_singular_proto3_bytes_into(wire_type, is, &mut self.type_option_data)?; + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if !self.grid_id.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.grid_id); + } + if !self.field_id.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.field_id); + } + if !self.type_option_data.is_empty() { + my_size += ::protobuf::rt::bytes_size(3, &self.type_option_data); + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if !self.grid_id.is_empty() { + os.write_string(1, &self.grid_id)?; + } + if !self.field_id.is_empty() { + os.write_string(2, &self.field_id)?; + } + if !self.type_option_data.is_empty() { + os.write_bytes(3, &self.type_option_data)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> UpdateFieldTypeOptionPayload { + UpdateFieldTypeOptionPayload::new() + } + + fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; + descriptor.get(|| { + let mut fields = ::std::vec::Vec::new(); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "grid_id", + |m: &UpdateFieldTypeOptionPayload| { &m.grid_id }, + |m: &mut UpdateFieldTypeOptionPayload| { &mut m.grid_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "field_id", + |m: &UpdateFieldTypeOptionPayload| { &m.field_id }, + |m: &mut UpdateFieldTypeOptionPayload| { &mut m.field_id }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBytes>( + "type_option_data", + |m: &UpdateFieldTypeOptionPayload| { &m.type_option_data }, + |m: &mut UpdateFieldTypeOptionPayload| { &mut m.type_option_data }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "UpdateFieldTypeOptionPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static UpdateFieldTypeOptionPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(UpdateFieldTypeOptionPayload::new) + } +} + +impl ::protobuf::Clear for UpdateFieldTypeOptionPayload { + fn clear(&mut self) { + self.grid_id.clear(); + self.field_id.clear(); + self.type_option_data.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for UpdateFieldTypeOptionPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for UpdateFieldTypeOptionPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct QueryFieldPayload { // message fields @@ -8056,33 +8299,36 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x01\x20\x01(\tR\x06gridId\x12\x1c\n\x05field\x18\x02\x20\x01(\x0b2\x06.\ FieldR\x05field\x12(\n\x10type_option_data\x18\x03\x20\x01(\x0cR\x0etype\ OptionData\x12&\n\x0estart_field_id\x18\x04\x20\x01(\tH\0R\x0cstartField\ - IdB\x17\n\x15one_of_start_field_id\"d\n\x11QueryFieldPayload\x12\x17\n\ - \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x126\n\x0cfield_orders\x18\x02\ - \x20\x01(\x0b2\x13.RepeatedFieldOrderR\x0bfieldOrders\"e\n\x16QueryGridB\ - locksPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\ - \x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrder\ - s\"\xa8\x03\n\x15FieldChangesetPayload\x12\x19\n\x08field_id\x18\x01\x20\ - \x01(\tR\x07fieldId\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\ - \x12\x14\n\x04name\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\ - \x04\x20\x01(\tH\x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\x0e2\n\ - .FieldTypeH\x02R\tfieldType\x12\x18\n\x06frozen\x18\x06\x20\x01(\x08H\ - \x03R\x06frozen\x12\x20\n\nvisibility\x18\x07\x20\x01(\x08H\x04R\nvisibi\ - lity\x12\x16\n\x05width\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10ty\ - pe_option_data\x18\t\x20\x01(\x0cH\x06R\x0etypeOptionDataB\r\n\x0bone_of\ - _nameB\r\n\x0bone_of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_fro\ - zenB\x13\n\x11one_of_visibilityB\x0e\n\x0cone_of_widthB\x19\n\x17one_of_\ - type_option_data\"\x9c\x01\n\x0fMoveItemPayload\x12\x17\n\x07grid_id\x18\ - \x01\x20\x01(\tR\x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06i\ - temId\x12\x1d\n\nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\ - \x08to_index\x18\x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\ - \x20\x01(\x0e2\r.MoveItemTypeR\x02ty\"\x7f\n\rCellChangeset\x12\x17\n\ - \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\ - \x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07field\ - Id\x12\x14\n\x04data\x18\x04\x20\x01(\tH\0R\x04dataB\r\n\x0bone_of_data*\ - *\n\x0cMoveItemType\x12\r\n\tMoveField\x10\0\x12\x0b\n\x07MoveRow\x10\ - \x01*d\n\tFieldType\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\ - \x01\x12\x0c\n\x08DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\ - \x0f\n\x0bMultiSelect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ + IdB\x17\n\x15one_of_start_field_id\"|\n\x1cUpdateFieldTypeOptionPayload\ + \x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_i\ + d\x18\x02\x20\x01(\tR\x07fieldId\x12(\n\x10type_option_data\x18\x03\x20\ + \x01(\x0cR\x0etypeOptionData\"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\x16QueryGridBlocksPay\ + load\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x122\n\x0cblock_\ + orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\x0bblockOrders\"\xa8\ + \x03\n\x15FieldChangesetPayload\x12\x19\n\x08field_id\x18\x01\x20\x01(\t\ + R\x07fieldId\x12\x17\n\x07grid_id\x18\x02\x20\x01(\tR\x06gridId\x12\x14\ + \n\x04name\x18\x03\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x04\x20\ + \x01(\tH\x01R\x04desc\x12+\n\nfield_type\x18\x05\x20\x01(\x0e2\n.FieldTy\ + peH\x02R\tfieldType\x12\x18\n\x06frozen\x18\x06\x20\x01(\x08H\x03R\x06fr\ + ozen\x12\x20\n\nvisibility\x18\x07\x20\x01(\x08H\x04R\nvisibility\x12\ + \x16\n\x05width\x18\x08\x20\x01(\x05H\x05R\x05width\x12*\n\x10type_optio\ + n_data\x18\t\x20\x01(\x0cH\x06R\x0etypeOptionDataB\r\n\x0bone_of_nameB\r\ + \n\x0bone_of_descB\x13\n\x11one_of_field_typeB\x0f\n\rone_of_frozenB\x13\ + \n\x11one_of_visibilityB\x0e\n\x0cone_of_widthB\x19\n\x17one_of_type_opt\ + ion_data\"\x9c\x01\n\x0fMoveItemPayload\x12\x17\n\x07grid_id\x18\x01\x20\ + \x01(\tR\x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06itemId\ + \x12\x1d\n\nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_\ + index\x18\x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\ + \x0e2\r.MoveItemTypeR\x02ty\"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\ + \x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\ + \x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\ + \x04data\x18\x04\x20\x01(\tH\0R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveI\ + temType\x12\r\n\tMoveField\x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tField\ + Type\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08\ + DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSel\ + ect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto index 77c6943c04..4295dee2bb 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto +++ b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto @@ -118,6 +118,11 @@ message InsertFieldPayload { bytes type_option_data = 3; oneof one_of_start_field_id { string start_field_id = 4; }; } +message UpdateFieldTypeOptionPayload { + string grid_id = 1; + string field_id = 2; + bytes type_option_data = 3; +} message QueryFieldPayload { string grid_id = 1; RepeatedFieldOrder field_orders = 2; From a2dfc8bc0378b03a8f7ae22312df6d9a937e853e Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 10 May 2022 10:26:40 +0800 Subject: [PATCH 06/14] chore: set time --- .../application/grid/cell/date_cal_bloc.dart | 76 ++++++------ .../src/widgets/cell/date_cell/calendar.dart | 111 ++++++++++++------ .../grid/src/widgets/common/text_field.dart | 2 +- .../lib/widget/rounded_input_field.dart | 8 +- 4 files changed, 123 insertions(+), 74 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index da1238e758..91e8559a6f 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -16,13 +17,17 @@ class DateCalBloc extends Bloc { final GridDefaultCellContext cellContext; void Function()? _onCellChangedFn; - DateCalBloc({required this.cellContext}) : super(DateCalState.initial(cellContext)) { + DateCalBloc({ + required DateTypeOption dateTypeOption, + required DateTime? selectedDay, + required this.cellContext, + }) : super(DateCalState.initial(dateTypeOption, selectedDay)) { on( (event, emit) async { await event.map( initial: (_Initial value) async { _startListening(); - await _loadDateTypeOption(emit); + // await _loadDateTypeOption(emit); }, selectDay: (_SelectDay value) { if (!isSameDay(state.selectedDay, value.day)) { @@ -46,6 +51,7 @@ class DateCalBloc extends Bloc { setTimeFormat: (_TimeFormat value) async { await _updateTypeOption(emit, timeFormat: value.timeFormat); }, + setTime: (_Time value) {}, ); }, ); @@ -71,12 +77,12 @@ class DateCalBloc extends Bloc { ); } + // ignore: unused_element Future _loadDateTypeOption(Emitter emit) async { final result = await cellContext.getTypeOptionData(); result.fold( (data) { final typeOptionData = DateTypeOption.fromBuffer(data); - DateTime? selectedDay; final cellData = cellContext.getCellData()?.data; @@ -86,7 +92,7 @@ class DateCalBloc extends Bloc { } emit(state.copyWith( - dateTypeOption: some(typeOptionData), + dateTypeOption: typeOptionData, selectedDay: selectedDay, )); }, @@ -105,35 +111,31 @@ class DateCalBloc extends Bloc { TimeFormat? timeFormat, bool? includeTime, }) async { - final newDateTypeOption = state.dateTypeOption.fold(() => null, (dateTypeOption) { - dateTypeOption.freeze(); - return dateTypeOption.rebuild((typeOption) { - if (dateFormat != null) { - typeOption.dateFormat = dateFormat; - } + state.dateTypeOption.freeze(); + final newDateTypeOption = state.dateTypeOption.rebuild((typeOption) { + if (dateFormat != null) { + typeOption.dateFormat = dateFormat; + } - if (timeFormat != null) { - typeOption.timeFormat = timeFormat; - } + if (timeFormat != null) { + typeOption.timeFormat = timeFormat; + } - if (includeTime != null) { - typeOption.includeTime = includeTime; - } - }); + if (includeTime != null) { + typeOption.includeTime = includeTime; + } }); - if (newDateTypeOption != null) { - final result = await FieldService.updateFieldTypeOption( - gridId: cellContext.gridId, - fieldId: cellContext.field.id, - typeOptionData: newDateTypeOption.writeToBuffer(), - ); + final result = await FieldService.updateFieldTypeOption( + gridId: cellContext.gridId, + fieldId: cellContext.field.id, + typeOptionData: newDateTypeOption.writeToBuffer(), + ); - result.fold( - (l) => emit(state.copyWith(dateTypeOption: Some(newDateTypeOption))), - (err) => Log.error(err), - ); - } + result.fold( + (l) => emit(state.copyWith(dateTypeOption: newDateTypeOption)), + (err) => Log.error(err), + ); } } @@ -146,23 +148,31 @@ class DateCalEvent with _$DateCalEvent { const factory DateCalEvent.setTimeFormat(TimeFormat timeFormat) = _TimeFormat; const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat; const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime; + const factory DateCalEvent.setTime(String time) = _Time; const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; } @freezed class DateCalState with _$DateCalState { const factory DateCalState({ - required Option dateTypeOption, + required DateTypeOption dateTypeOption, required CalendarFormat format, required DateTime focusedDay, - required Option time, + required String time, + required Option inputTimeError, DateTime? selectedDay, }) = _DateCalState; - factory DateCalState.initial(GridCellContext context) => DateCalState( - dateTypeOption: none(), + factory DateCalState.initial( + DateTypeOption dateTypeOption, + DateTime? selectedDay, + ) => + DateCalState( + dateTypeOption: dateTypeOption, format: CalendarFormat.month, focusedDay: DateTime.now(), - time: none(), + selectedDay: selectedDay, + time: "", + inputTimeError: none(), ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 68875d4ce3..d30be1887a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -8,13 +8,15 @@ 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/text.dart'; +import 'package:flowy_infra_ui/widget/rounded_input_field.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; -import 'package:dartz/dartz.dart' show Option; +import 'package:fixnum/fixnum.dart' as $fixnum; final kToday = DateTime.now(); final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); @@ -35,22 +37,38 @@ class CellCalendar with FlowyOverlayDelegate { }) async { CellCalendar.remove(context); - final calendar = _CellCalendarWidget( - onSelected: onSelected, - includeTime: false, - cellContext: cellContext, - ); + final result = await cellContext.getTypeOptionData(); + result.fold( + (data) { + final typeOptionData = DateTypeOption.fromBuffer(data); + DateTime? selectedDay; + final cellData = cellContext.getCellData()?.data; - FlowyOverlay.of(context).insertWithAnchor( - widget: OverlayContainer( - child: calendar, - constraints: BoxConstraints.loose(const Size(320, 500)), - ), - identifier: CellCalendar.identifier(), - anchorContext: context, - anchorDirection: AnchorDirection.leftWithCenterAligned, - style: FlowyOverlayStyle(blur: false), - delegate: this, + if (cellData != null) { + final timestamp = $fixnum.Int64.parseInt(cellData).toInt(); + selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); + } + + final calendar = _CellCalendarWidget( + onSelected: onSelected, + cellContext: cellContext, + dateTypeOption: typeOptionData, + selectedDay: selectedDay, + ); + + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: calendar, + constraints: BoxConstraints.loose(const Size(320, 500)), + ), + identifier: CellCalendar.identifier(), + anchorContext: context, + anchorDirection: AnchorDirection.leftWithCenterAligned, + style: FlowyOverlayStyle(blur: false), + delegate: this, + ); + }, + (err) => Log.error(err), ); } @@ -70,14 +88,16 @@ class CellCalendar with FlowyOverlayDelegate { } class _CellCalendarWidget extends StatelessWidget { - final bool includeTime; final GridDefaultCellContext cellContext; + final DateTypeOption dateTypeOption; + final DateTime? selectedDay; final void Function(DateTime) onSelected; const _CellCalendarWidget({ required this.onSelected, - required this.includeTime, required this.cellContext, + required this.dateTypeOption, + this.selectedDay, Key? key, }) : super(key: key); @@ -85,7 +105,11 @@ class _CellCalendarWidget extends StatelessWidget { Widget build(BuildContext context) { final theme = context.watch(); return BlocProvider( - create: (context) => DateCalBloc(cellContext: cellContext)..add(const DateCalEvent.initial()), + create: (context) => DateCalBloc( + dateTypeOption: dateTypeOption, + selectedDay: selectedDay, + cellContext: cellContext, + )..add(const DateCalEvent.initial()), child: BlocConsumer( listener: (context, state) { if (state.selectedDay != null) { @@ -101,12 +125,11 @@ class _CellCalendarWidget extends StatelessWidget { const VSpace(10), ]); - state.dateTypeOption.foldRight(null, (dateTypeOption, _) { + if (state.dateTypeOption.includeTime) { children.addAll([ const _TimeTextField(), - const VSpace(10), ]); - }); + } children.addAll([ Divider(height: 1, color: theme.shader5), @@ -189,7 +212,7 @@ class _IncludeTimeButton extends StatelessWidget { Widget build(BuildContext context) { final theme = context.watch(); return BlocSelector( - selector: (state) => state.dateTypeOption.foldRight(false, (option, _) => option.includeTime), + selector: (state) => state.dateTypeOption.includeTime, builder: (context, includeTime) { return SizedBox( height: 50, @@ -219,7 +242,19 @@ class _TimeTextField extends StatelessWidget { @override Widget build(BuildContext context) { - return Container(); + final theme = context.watch(); + return Padding( + padding: kMargin, + child: RoundedInputField( + height: 40, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + normalBorderColor: theme.shader4, + errorBorderColor: theme.red, + cursorColor: theme.main1, + errorText: context.read().state.inputTimeError.fold(() => "", (error) => error.toString()), + onEditingComplete: (value) => context.read().add(DateCalEvent.setTime(value)), + ), + ); } } @@ -230,29 +265,33 @@ class _DateTypeOptionButton extends StatelessWidget { Widget build(BuildContext context) { final theme = context.watch(); final title = LocaleKeys.grid_field_dateFormat.tr() + " &" + LocaleKeys.grid_field_timeFormat.tr(); - return BlocSelector>( + return BlocSelector( selector: (state) => state.dateTypeOption, builder: (context, dateTypeOption) { return FlowyButton( text: FlowyText.medium(title, fontSize: 12), hoverColor: theme.hover, margin: kMargin, - onTap: () { - dateTypeOption.fold(() => null, (dateTypeOption) { - final setting = _CalDateTimeSetting(dateTypeOption: dateTypeOption); - setting.show(context); - }); - }, + onTap: () => _showTimeSetting(dateTypeOption, context), rightIcon: svgWidget("grid/more", color: theme.iconColor), ); }, ); } + + void _showTimeSetting(DateTypeOption dateTypeOption, BuildContext context) { + final setting = _CalDateTimeSetting( + dateTypeOption: dateTypeOption, + onEvent: (event) => context.read().add(event), + ); + setting.show(context); + } } class _CalDateTimeSetting extends StatefulWidget { final DateTypeOption dateTypeOption; - const _CalDateTimeSetting({required this.dateTypeOption, Key? key}) : super(key: key); + final Function(DateCalEvent) onEvent; + const _CalDateTimeSetting({required this.dateTypeOption, required this.onEvent, Key? key}) : super(key: key); @override State<_CalDateTimeSetting> createState() => _CalDateTimeSettingState(); @@ -283,9 +322,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> { DateFormatButton(onTap: () { final list = DateFormatList( selectedFormat: widget.dateTypeOption.dateFormat, - onSelected: (format) { - context.read().add(DateCalEvent.setDateFormat(format)); - }, + onSelected: (format) => widget.onEvent(DateCalEvent.setDateFormat(format)), ); _showOverlay(context, list); }), @@ -294,9 +331,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> { onTap: () { final list = TimeFormatList( selectedFormat: widget.dateTypeOption.timeFormat, - onSelected: (format) { - context.read().add(DateCalEvent.setTimeFormat(format)); - }, + onSelected: (format) => widget.onEvent(DateCalEvent.setTimeFormat(format)), ); _showOverlay(context, list); }, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart index 5a06dbfd46..b5860b1fbb 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart @@ -53,7 +53,7 @@ class _InputTextFieldState extends State { widget.onChanged!(text); } }, - onEditingComplete: () { + onEditingComplete: (_) { if (widget.onDone != null) { widget.onDone!(_controller.text); } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart index 19b3accc59..66e40a380b 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart @@ -15,7 +15,7 @@ class RoundedInputField extends StatefulWidget { final String errorText; final TextStyle style; final ValueChanged? onChanged; - final VoidCallback? onEditingComplete; + final Function(String)? onEditingComplete; final String? initialValue; final EdgeInsets margin; final EdgeInsets padding; @@ -90,7 +90,11 @@ class _RoundedInputFieldState extends State { } setState(() {}); }, - onEditingComplete: widget.onEditingComplete, + onEditingComplete: () { + if (widget.onEditingComplete != null) { + widget.onEditingComplete!(inputText); + } + }, cursorColor: widget.cursorColor, obscureText: obscuteText, style: widget.style, From 19da42f2104d617112bbe6ad67b87a17ff9902c2 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 11 May 2022 11:34:13 +0800 Subject: [PATCH 07/14] chore: add date cell handler --- .../application/grid/cell/cell_service.dart | 2 +- .../application/grid/cell/date_cal_bloc.dart | 4 +- .../grid/cell/select_option_service.dart | 30 +- .../src/widgets/cell/date_cell/calendar.dart | 3 +- .../dart_event/flowy-grid/dart_event.dart | 23 +- .../flowy-grid-data-model/grid.pb.dart | 30 +- .../flowy-grid-data-model/grid.pbjson.dart | 6 +- .../flowy-grid/date_type_option.pb.dart | 105 ++++++ .../flowy-grid/date_type_option.pbjson.dart | 16 + .../protobuf/flowy-grid/event_map.pbenum.dart | 6 +- .../protobuf/flowy-grid/event_map.pbjson.dart | 5 +- .../flowy-grid/selection_type_option.pb.dart | 74 ++-- .../selection_type_option.pbjson.dart | 10 +- .../rust-lib/flowy-grid/src/event_handler.rs | 30 +- frontend/rust-lib/flowy-grid/src/event_map.rs | 9 +- .../src/protobuf/model/date_type_option.rs | 355 +++++++++++++++++- .../src/protobuf/model/event_map.rs | 14 +- .../protobuf/model/selection_type_option.rs | 182 +++------ .../src/protobuf/proto/date_type_option.proto | 6 + .../src/protobuf/proto/event_map.proto | 3 +- .../proto/selection_type_option.proto | 8 +- .../type_options/checkbox_type_option.rs | 18 +- .../field/type_options/date_type_option.rs | 89 ++++- .../src/services/field/type_options/mod.rs | 2 +- .../field/type_options/number_type_option.rs | 61 +-- .../type_options/selection_type_option.rs | 161 ++++---- .../field/type_options/text_type_option.rs | 21 +- .../field/type_options/type_option_data.rs | 1 - .../src/services/field/type_options/util.rs | 10 + .../flowy-grid/src/services/grid_editor.rs | 43 ++- .../src/services/row/cell_data_operation.rs | 65 ++-- .../src/services/row/row_builder.rs | 4 +- .../flowy-grid/src/services/row/row_loader.rs | 4 +- .../flowy-grid/tests/grid/grid_test.rs | 15 +- .../src/entities/grid.rs | 4 +- .../src/protobuf/model/grid.rs | 81 ++-- .../src/protobuf/proto/grid.proto | 2 +- .../src/parser/user_email.rs | 1 + 38 files changed, 995 insertions(+), 508 deletions(-) delete mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_data.rs create mode 100644 frontend/rust-lib/flowy-grid/src/services/field/type_options/util.rs diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart index 06cfa8c0e9..fc8bb001e4 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart @@ -344,7 +344,7 @@ class CellService { ..gridId = gridId ..fieldId = fieldId ..rowId = rowId - ..data = data; + ..cellContentChangeset = data; return GridEventUpdateCell(payload).send(); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 91e8559a6f..7f7d64cd26 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -51,7 +51,9 @@ class DateCalBloc extends Bloc { setTimeFormat: (_TimeFormat value) async { await _updateTypeOption(emit, timeFormat: value.timeFormat); }, - setTime: (_Time value) {}, + setTime: (_Time value) { + // + }, ); }, ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart index 8a10a211d5..f8795c4510 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -60,27 +60,18 @@ class SelectOptionService { Future> update({ required SelectOption option, }) { - final cellIdentifier = CellIdentifierPayload.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId; final payload = SelectOptionChangesetPayload.create() ..updateOption = option - ..cellIdentifier = cellIdentifier; + ..cellIdentifier = _cellIdentifier(); return GridEventUpdateSelectOption(payload).send(); } Future> delete({ required SelectOption option, }) { - final cellIdentifier = CellIdentifierPayload.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId; - final payload = SelectOptionChangesetPayload.create() ..deleteOption = option - ..cellIdentifier = cellIdentifier; + ..cellIdentifier = _cellIdentifier(); return GridEventUpdateSelectOption(payload).send(); } @@ -96,19 +87,22 @@ class SelectOptionService { Future> select({required String optionId}) { final payload = SelectOptionCellChangesetPayload.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId + ..cellIdentifier = _cellIdentifier() ..insertOptionId = optionId; - return GridEventUpdateCellSelectOption(payload).send(); + return GridEventUpdateSelectOptionCell(payload).send(); } Future> unSelect({required String optionId}) { final payload = SelectOptionCellChangesetPayload.create() + ..cellIdentifier = _cellIdentifier() + ..deleteOptionId = optionId; + return GridEventUpdateSelectOptionCell(payload).send(); + } + + CellIdentifierPayload _cellIdentifier() { + return CellIdentifierPayload.create() ..gridId = gridId ..fieldId = fieldId - ..rowId = rowId - ..deleteOptionId = optionId; - return GridEventUpdateCellSelectOption(payload).send(); + ..rowId = rowId; } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index d30be1887a..0efe2d4c7e 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -309,6 +309,7 @@ class _CalDateTimeSetting extends StatefulWidget { identifier: _CalDateTimeSetting.identifier(), anchorContext: context, anchorDirection: AnchorDirection.rightWithCenterAligned, + anchorOffset: const Offset(20, 0), ); } } @@ -369,7 +370,7 @@ class _CalDateTimeSettingState extends State<_CalDateTimeSetting> { anchorContext: context, anchorDirection: AnchorDirection.rightWithCenterAligned, style: FlowyOverlayStyle(blur: false), - anchorOffset: const Offset(-20, 0), + anchorOffset: const Offset(20, 0), ); } } diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart index ddc642d913..ea1c73ec35 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart @@ -358,13 +358,30 @@ class GridEventUpdateCell { } } -class GridEventUpdateCellSelectOption { +class GridEventUpdateSelectOptionCell { SelectOptionCellChangesetPayload request; - GridEventUpdateCellSelectOption(this.request); + GridEventUpdateSelectOptionCell(this.request); Future> send() { final request = FFIRequest.create() - ..event = GridEvent.UpdateCellSelectOption.toString() + ..event = GridEvent.UpdateSelectOptionCell.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (bytes) => left(unit), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + +class GridEventUpdateDateCell { + DateChangesetPayload request; + GridEventUpdateDateCell(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.UpdateDateCell.toString() ..payload = requestToBytes(this.request); return Dispatch.asyncRequest(request) diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart index 5cf3a2a83b..4c18294dae 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pb.dart @@ -2327,22 +2327,22 @@ class MoveItemPayload extends $pb.GeneratedMessage { void clearTy() => clearField(5); } -enum CellChangeset_OneOfData { - data, +enum CellChangeset_OneOfCellContentChangeset { + cellContentChangeset, notSet } class CellChangeset extends $pb.GeneratedMessage { - static const $core.Map<$core.int, CellChangeset_OneOfData> _CellChangeset_OneOfDataByTag = { - 4 : CellChangeset_OneOfData.data, - 0 : CellChangeset_OneOfData.notSet + static const $core.Map<$core.int, CellChangeset_OneOfCellContentChangeset> _CellChangeset_OneOfCellContentChangesetByTag = { + 4 : CellChangeset_OneOfCellContentChangeset.cellContentChangeset, + 0 : CellChangeset_OneOfCellContentChangeset.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CellChangeset', createEmptyInstance: create) ..oo(0, [4]) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') - ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'data') + ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'cellContentChangeset') ..hasRequiredFields = false ; @@ -2351,7 +2351,7 @@ class CellChangeset extends $pb.GeneratedMessage { $core.String? gridId, $core.String? rowId, $core.String? fieldId, - $core.String? data, + $core.String? cellContentChangeset, }) { final _result = create(); if (gridId != null) { @@ -2363,8 +2363,8 @@ class CellChangeset extends $pb.GeneratedMessage { if (fieldId != null) { _result.fieldId = fieldId; } - if (data != null) { - _result.data = data; + if (cellContentChangeset != null) { + _result.cellContentChangeset = cellContentChangeset; } return _result; } @@ -2389,8 +2389,8 @@ class CellChangeset extends $pb.GeneratedMessage { static CellChangeset getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static CellChangeset? _defaultInstance; - CellChangeset_OneOfData whichOneOfData() => _CellChangeset_OneOfDataByTag[$_whichOneof(0)]!; - void clearOneOfData() => clearField($_whichOneof(0)); + CellChangeset_OneOfCellContentChangeset whichOneOfCellContentChangeset() => _CellChangeset_OneOfCellContentChangesetByTag[$_whichOneof(0)]!; + void clearOneOfCellContentChangeset() => clearField($_whichOneof(0)); @$pb.TagNumber(1) $core.String get gridId => $_getSZ(0); @@ -2420,12 +2420,12 @@ class CellChangeset extends $pb.GeneratedMessage { void clearFieldId() => clearField(3); @$pb.TagNumber(4) - $core.String get data => $_getSZ(3); + $core.String get cellContentChangeset => $_getSZ(3); @$pb.TagNumber(4) - set data($core.String v) { $_setString(3, v); } + set cellContentChangeset($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) - $core.bool hasData() => $_has(3); + $core.bool hasCellContentChangeset() => $_has(3); @$pb.TagNumber(4) - void clearData() => clearField(4); + void clearCellContentChangeset() => clearField(4); } diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart index 9043564b43..3155b79a2e 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid-data-model/grid.pbjson.dart @@ -449,12 +449,12 @@ const CellChangeset$json = const { const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, const {'1': 'row_id', '3': 2, '4': 1, '5': 9, '10': 'rowId'}, const {'1': 'field_id', '3': 3, '4': 1, '5': 9, '10': 'fieldId'}, - const {'1': 'data', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'data'}, + const {'1': 'cell_content_changeset', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'cellContentChangeset'}, ], '8': const [ - const {'1': 'one_of_data'}, + const {'1': 'one_of_cell_content_changeset'}, ], }; /// Descriptor for `CellChangeset`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List cellChangesetDescriptor = $convert.base64Decode('Cg1DZWxsQ2hhbmdlc2V0EhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIVCgZyb3dfaWQYAiABKAlSBXJvd0lkEhkKCGZpZWxkX2lkGAMgASgJUgdmaWVsZElkEhQKBGRhdGEYBCABKAlIAFIEZGF0YUINCgtvbmVfb2ZfZGF0YQ=='); +final $typed_data.Uint8List cellChangesetDescriptor = $convert.base64Decode('Cg1DZWxsQ2hhbmdlc2V0EhcKB2dyaWRfaWQYASABKAlSBmdyaWRJZBIVCgZyb3dfaWQYAiABKAlSBXJvd0lkEhkKCGZpZWxkX2lkGAMgASgJUgdmaWVsZElkEjYKFmNlbGxfY29udGVudF9jaGFuZ2VzZXQYBCABKAlIAFIUY2VsbENvbnRlbnRDaGFuZ2VzZXRCHwodb25lX29mX2NlbGxfY29udGVudF9jaGFuZ2VzZXQ='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart index db19e676d1..1f77ca10fb 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart @@ -9,6 +9,8 @@ import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; +import 'cell_entities.pb.dart' as $0; + import 'date_type_option.pbenum.dart'; export 'date_type_option.pbenum.dart'; @@ -88,3 +90,106 @@ class DateTypeOption extends $pb.GeneratedMessage { void clearIncludeTime() => clearField(3); } +enum DateChangesetPayload_OneOfDate { + date, + notSet +} + +enum DateChangesetPayload_OneOfTime { + time, + notSet +} + +class DateChangesetPayload extends $pb.GeneratedMessage { + static const $core.Map<$core.int, DateChangesetPayload_OneOfDate> _DateChangesetPayload_OneOfDateByTag = { + 2 : DateChangesetPayload_OneOfDate.date, + 0 : DateChangesetPayload_OneOfDate.notSet + }; + static const $core.Map<$core.int, DateChangesetPayload_OneOfTime> _DateChangesetPayload_OneOfTimeByTag = { + 3 : DateChangesetPayload_OneOfTime.time, + 0 : DateChangesetPayload_OneOfTime.notSet + }; + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DateChangesetPayload', createEmptyInstance: create) + ..oo(0, [2]) + ..oo(1, [3]) + ..aOM<$0.CellIdentifierPayload>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'cellIdentifier', subBuilder: $0.CellIdentifierPayload.create) + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'date') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'time') + ..hasRequiredFields = false + ; + + DateChangesetPayload._() : super(); + factory DateChangesetPayload({ + $0.CellIdentifierPayload? cellIdentifier, + $core.String? date, + $core.String? time, + }) { + final _result = create(); + if (cellIdentifier != null) { + _result.cellIdentifier = cellIdentifier; + } + if (date != null) { + _result.date = date; + } + if (time != null) { + _result.time = time; + } + return _result; + } + factory DateChangesetPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory DateChangesetPayload.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') + DateChangesetPayload clone() => DateChangesetPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + DateChangesetPayload copyWith(void Function(DateChangesetPayload) updates) => super.copyWith((message) => updates(message as DateChangesetPayload)) as DateChangesetPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static DateChangesetPayload create() => DateChangesetPayload._(); + DateChangesetPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static DateChangesetPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static DateChangesetPayload? _defaultInstance; + + DateChangesetPayload_OneOfDate whichOneOfDate() => _DateChangesetPayload_OneOfDateByTag[$_whichOneof(0)]!; + void clearOneOfDate() => clearField($_whichOneof(0)); + + DateChangesetPayload_OneOfTime whichOneOfTime() => _DateChangesetPayload_OneOfTimeByTag[$_whichOneof(1)]!; + void clearOneOfTime() => clearField($_whichOneof(1)); + + @$pb.TagNumber(1) + $0.CellIdentifierPayload get cellIdentifier => $_getN(0); + @$pb.TagNumber(1) + set cellIdentifier($0.CellIdentifierPayload v) { setField(1, v); } + @$pb.TagNumber(1) + $core.bool hasCellIdentifier() => $_has(0); + @$pb.TagNumber(1) + void clearCellIdentifier() => clearField(1); + @$pb.TagNumber(1) + $0.CellIdentifierPayload ensureCellIdentifier() => $_ensure(0); + + @$pb.TagNumber(2) + $core.String get date => $_getSZ(1); + @$pb.TagNumber(2) + set date($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasDate() => $_has(1); + @$pb.TagNumber(2) + void clearDate() => clearField(2); + + @$pb.TagNumber(3) + $core.String get time => $_getSZ(2); + @$pb.TagNumber(3) + set time($core.String v) { $_setString(2, v); } + @$pb.TagNumber(3) + $core.bool hasTime() => $_has(2); + @$pb.TagNumber(3) + void clearTime() => clearField(3); +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart index f419cc0e95..58f9ed5c31 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart @@ -44,3 +44,19 @@ const DateTypeOption$json = const { /// Descriptor for `DateTypeOption`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List dateTypeOptionDescriptor = $convert.base64Decode('Cg5EYXRlVHlwZU9wdGlvbhIsCgtkYXRlX2Zvcm1hdBgBIAEoDjILLkRhdGVGb3JtYXRSCmRhdGVGb3JtYXQSLAoLdGltZV9mb3JtYXQYAiABKA4yCy5UaW1lRm9ybWF0Ugp0aW1lRm9ybWF0EiEKDGluY2x1ZGVfdGltZRgDIAEoCFILaW5jbHVkZVRpbWU='); +@$core.Deprecated('Use dateChangesetPayloadDescriptor instead') +const DateChangesetPayload$json = const { + '1': 'DateChangesetPayload', + '2': const [ + const {'1': 'cell_identifier', '3': 1, '4': 1, '5': 11, '6': '.CellIdentifierPayload', '10': 'cellIdentifier'}, + const {'1': 'date', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'date'}, + const {'1': 'time', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'time'}, + ], + '8': const [ + const {'1': 'one_of_date'}, + const {'1': 'one_of_time'}, + ], +}; + +/// Descriptor for `DateChangesetPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List dateChangesetPayloadDescriptor = $convert.base64Decode('ChREYXRlQ2hhbmdlc2V0UGF5bG9hZBI/Cg9jZWxsX2lkZW50aWZpZXIYASABKAsyFi5DZWxsSWRlbnRpZmllclBheWxvYWRSDmNlbGxJZGVudGlmaWVyEhQKBGRhdGUYAiABKAlIAFIEZGF0ZRIUCgR0aW1lGAMgASgJSAFSBHRpbWVCDQoLb25lX29mX2RhdGVCDQoLb25lX29mX3RpbWU='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart index 4e0db67667..42f454d42c 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart @@ -31,7 +31,8 @@ class GridEvent extends $pb.ProtobufEnum { 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 UpdateCellSelectOption = GridEvent._(72, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCellSelectOption'); + static const GridEvent UpdateSelectOptionCell = GridEvent._(72, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOptionCell'); + static const GridEvent UpdateDateCell = GridEvent._(80, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateDateCell'); static const $core.List values = [ GetGridData, @@ -55,7 +56,8 @@ class GridEvent extends $pb.ProtobufEnum { DuplicateRow, GetCell, UpdateCell, - UpdateCellSelectOption, + UpdateSelectOptionCell, + UpdateDateCell, ]; static final $core.Map<$core.int, GridEvent> _byValue = $pb.ProtobufEnum.initByValue(values); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart index 6c3f668b74..54b39477ba 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart @@ -33,9 +33,10 @@ const GridEvent$json = const { const {'1': 'DuplicateRow', '2': 53}, const {'1': 'GetCell', '2': 70}, const {'1': 'UpdateCell', '2': 71}, - const {'1': 'UpdateCellSelectOption', '2': 72}, + const {'1': 'UpdateSelectOptionCell', '2': 72}, + const {'1': 'UpdateDateCell', '2': 80}, ], }; /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAWEgwKCE1vdmVJdGVtEBcSFgoSR2V0RmllbGRUeXBlT3B0aW9uEBgSEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlQ2VsbFNlbGVjdE9wdGlvbhBI'); +final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAWEgwKCE1vdmVJdGVtEBcSFgoSR2V0RmllbGRUeXBlT3B0aW9uEBgSEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlU2VsZWN0T3B0aW9uQ2VsbBBIEhIKDlVwZGF0ZURhdGVDZWxsEFA='); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart index d6e0bbcdaf..53d5c5069e 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart @@ -348,41 +348,31 @@ enum SelectOptionCellChangesetPayload_OneOfDeleteOptionId { class SelectOptionCellChangesetPayload extends $pb.GeneratedMessage { static const $core.Map<$core.int, SelectOptionCellChangesetPayload_OneOfInsertOptionId> _SelectOptionCellChangesetPayload_OneOfInsertOptionIdByTag = { - 4 : SelectOptionCellChangesetPayload_OneOfInsertOptionId.insertOptionId, + 2 : SelectOptionCellChangesetPayload_OneOfInsertOptionId.insertOptionId, 0 : SelectOptionCellChangesetPayload_OneOfInsertOptionId.notSet }; static const $core.Map<$core.int, SelectOptionCellChangesetPayload_OneOfDeleteOptionId> _SelectOptionCellChangesetPayload_OneOfDeleteOptionIdByTag = { - 5 : SelectOptionCellChangesetPayload_OneOfDeleteOptionId.deleteOptionId, + 3 : SelectOptionCellChangesetPayload_OneOfDeleteOptionId.deleteOptionId, 0 : SelectOptionCellChangesetPayload_OneOfDeleteOptionId.notSet }; static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SelectOptionCellChangesetPayload', createEmptyInstance: create) - ..oo(0, [4]) - ..oo(1, [5]) - ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'gridId') - ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'rowId') - ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldId') - ..aOS(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertOptionId') - ..aOS(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deleteOptionId') + ..oo(0, [2]) + ..oo(1, [3]) + ..aOM<$0.CellIdentifierPayload>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'cellIdentifier', subBuilder: $0.CellIdentifierPayload.create) + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'insertOptionId') + ..aOS(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'deleteOptionId') ..hasRequiredFields = false ; SelectOptionCellChangesetPayload._() : super(); factory SelectOptionCellChangesetPayload({ - $core.String? gridId, - $core.String? rowId, - $core.String? fieldId, + $0.CellIdentifierPayload? cellIdentifier, $core.String? insertOptionId, $core.String? deleteOptionId, }) { final _result = create(); - if (gridId != null) { - _result.gridId = gridId; - } - if (rowId != null) { - _result.rowId = rowId; - } - if (fieldId != null) { - _result.fieldId = fieldId; + if (cellIdentifier != null) { + _result.cellIdentifier = cellIdentifier; } if (insertOptionId != null) { _result.insertOptionId = insertOptionId; @@ -420,49 +410,33 @@ class SelectOptionCellChangesetPayload extends $pb.GeneratedMessage { void clearOneOfDeleteOptionId() => clearField($_whichOneof(1)); @$pb.TagNumber(1) - $core.String get gridId => $_getSZ(0); + $0.CellIdentifierPayload get cellIdentifier => $_getN(0); @$pb.TagNumber(1) - set gridId($core.String v) { $_setString(0, v); } + set cellIdentifier($0.CellIdentifierPayload v) { setField(1, v); } @$pb.TagNumber(1) - $core.bool hasGridId() => $_has(0); + $core.bool hasCellIdentifier() => $_has(0); @$pb.TagNumber(1) - void clearGridId() => clearField(1); + void clearCellIdentifier() => clearField(1); + @$pb.TagNumber(1) + $0.CellIdentifierPayload ensureCellIdentifier() => $_ensure(0); @$pb.TagNumber(2) - $core.String get rowId => $_getSZ(1); + $core.String get insertOptionId => $_getSZ(1); @$pb.TagNumber(2) - set rowId($core.String v) { $_setString(1, v); } + set insertOptionId($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) - $core.bool hasRowId() => $_has(1); + $core.bool hasInsertOptionId() => $_has(1); @$pb.TagNumber(2) - void clearRowId() => clearField(2); + void clearInsertOptionId() => clearField(2); @$pb.TagNumber(3) - $core.String get fieldId => $_getSZ(2); + $core.String get deleteOptionId => $_getSZ(2); @$pb.TagNumber(3) - set fieldId($core.String v) { $_setString(2, v); } + set deleteOptionId($core.String v) { $_setString(2, v); } @$pb.TagNumber(3) - $core.bool hasFieldId() => $_has(2); + $core.bool hasDeleteOptionId() => $_has(2); @$pb.TagNumber(3) - void clearFieldId() => clearField(3); - - @$pb.TagNumber(4) - $core.String get insertOptionId => $_getSZ(3); - @$pb.TagNumber(4) - set insertOptionId($core.String v) { $_setString(3, v); } - @$pb.TagNumber(4) - $core.bool hasInsertOptionId() => $_has(3); - @$pb.TagNumber(4) - void clearInsertOptionId() => clearField(4); - - @$pb.TagNumber(5) - $core.String get deleteOptionId => $_getSZ(4); - @$pb.TagNumber(5) - set deleteOptionId($core.String v) { $_setString(4, v); } - @$pb.TagNumber(5) - $core.bool hasDeleteOptionId() => $_has(4); - @$pb.TagNumber(5) - void clearDeleteOptionId() => clearField(5); + void clearDeleteOptionId() => clearField(3); } class SelectOptionContext extends $pb.GeneratedMessage { diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart index 9613b926bd..2166a01087 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart @@ -82,11 +82,9 @@ final $typed_data.Uint8List selectOptionChangesetPayloadDescriptor = $convert.ba const SelectOptionCellChangesetPayload$json = const { '1': 'SelectOptionCellChangesetPayload', '2': const [ - const {'1': 'grid_id', '3': 1, '4': 1, '5': 9, '10': 'gridId'}, - const {'1': 'row_id', '3': 2, '4': 1, '5': 9, '10': 'rowId'}, - const {'1': 'field_id', '3': 3, '4': 1, '5': 9, '10': 'fieldId'}, - const {'1': 'insert_option_id', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'insertOptionId'}, - const {'1': 'delete_option_id', '3': 5, '4': 1, '5': 9, '9': 1, '10': 'deleteOptionId'}, + const {'1': 'cell_identifier', '3': 1, '4': 1, '5': 11, '6': '.CellIdentifierPayload', '10': 'cellIdentifier'}, + const {'1': 'insert_option_id', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'insertOptionId'}, + const {'1': 'delete_option_id', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'deleteOptionId'}, ], '8': const [ const {'1': 'one_of_insert_option_id'}, @@ -95,7 +93,7 @@ const SelectOptionCellChangesetPayload$json = const { }; /// Descriptor for `SelectOptionCellChangesetPayload`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List selectOptionCellChangesetPayloadDescriptor = $convert.base64Decode('CiBTZWxlY3RPcHRpb25DZWxsQ2hhbmdlc2V0UGF5bG9hZBIXCgdncmlkX2lkGAEgASgJUgZncmlkSWQSFQoGcm93X2lkGAIgASgJUgVyb3dJZBIZCghmaWVsZF9pZBgDIAEoCVIHZmllbGRJZBIqChBpbnNlcnRfb3B0aW9uX2lkGAQgASgJSABSDmluc2VydE9wdGlvbklkEioKEGRlbGV0ZV9vcHRpb25faWQYBSABKAlIAVIOZGVsZXRlT3B0aW9uSWRCGQoXb25lX29mX2luc2VydF9vcHRpb25faWRCGQoXb25lX29mX2RlbGV0ZV9vcHRpb25faWQ='); +final $typed_data.Uint8List selectOptionCellChangesetPayloadDescriptor = $convert.base64Decode('CiBTZWxlY3RPcHRpb25DZWxsQ2hhbmdlc2V0UGF5bG9hZBI/Cg9jZWxsX2lkZW50aWZpZXIYASABKAsyFi5DZWxsSWRlbnRpZmllclBheWxvYWRSDmNlbGxJZGVudGlmaWVyEioKEGluc2VydF9vcHRpb25faWQYAiABKAlIAFIOaW5zZXJ0T3B0aW9uSWQSKgoQZGVsZXRlX29wdGlvbl9pZBgDIAEoCUgBUg5kZWxldGVPcHRpb25JZEIZChdvbmVfb2ZfaW5zZXJ0X29wdGlvbl9pZEIZChdvbmVfb2ZfZGVsZXRlX29wdGlvbl9pZA=='); @$core.Deprecated('Use selectOptionContextDescriptor instead') const SelectOptionContext$json = const { '1': 'SelectOptionContext', diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index f60f31e87a..c87c94de7c 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -182,8 +182,8 @@ async fn make_edit_field_context( async fn get_type_option_data(field_meta: &FieldMeta, field_type: &FieldType) -> FlowyResult> { let s = field_meta - .get_type_option_str(&field_type) - .unwrap_or_else(|| default_type_option_builder_from_type(&field_type).entry().json_str()); + .get_type_option_str(field_type) + .unwrap_or_else(|| default_type_option_builder_from_type(field_type).entry().json_str()); let builder = type_option_builder_from_json_str(&s, &field_meta.field_type); let type_option_data = builder.entry().protobuf_bytes().to_vec(); @@ -301,10 +301,10 @@ pub(crate) async fn update_select_option_handler( if let Some(mut field_meta) = editor.get_field_meta(&changeset.cell_identifier.field_id).await { let mut type_option = select_option_operation(&field_meta)?; - let mut cell_data = None; + let mut cell_content_changeset = None; if let Some(option) = changeset.insert_option { - cell_data = Some(SelectOptionCellChangeset::from_insert(&option.id).cell_data()); + cell_content_changeset = Some(SelectOptionCellContentChangeset::from_insert(&option.id).to_str()); type_option.insert_option(option); } @@ -313,7 +313,7 @@ pub(crate) async fn update_select_option_handler( } if let Some(option) = changeset.delete_option { - cell_data = Some(SelectOptionCellChangeset::from_delete(&option.id).cell_data()); + cell_content_changeset = Some(SelectOptionCellContentChangeset::from_delete(&option.id).to_str()); type_option.delete_option(option); } @@ -324,7 +324,7 @@ pub(crate) async fn update_select_option_handler( grid_id: changeset.cell_identifier.grid_id, row_id: changeset.cell_identifier.row_id, field_id: changeset.cell_identifier.field_id, - data: cell_data, + cell_content_changeset, }; let _ = editor.update_cell(changeset).await?; } @@ -365,13 +365,23 @@ pub(crate) async fn get_select_option_handler( } #[tracing::instrument(level = "debug", skip_all, err)] -pub(crate) async fn update_cell_select_option_handler( +pub(crate) async fn update_select_option_cell_handler( data: Data, manager: AppData>, ) -> Result<(), FlowyError> { let params: SelectOptionCellChangesetParams = data.into_inner().try_into()?; - let editor = manager.get_grid_editor(¶ms.grid_id)?; - let changeset: CellChangeset = params.into(); - let _ = editor.update_cell(changeset).await?; + let editor = manager.get_grid_editor(¶ms.cell_identifier.grid_id)?; + let _ = editor.update_cell(params.into()).await?; + Ok(()) +} + +#[tracing::instrument(level = "debug", skip_all, err)] +pub(crate) async fn update_date_cell_handler( + data: Data, + manager: AppData>, +) -> Result<(), FlowyError> { + let params: DateChangesetParams = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.cell_identifier.grid_id)?; + let _ = editor.update_cell(params.into()).await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index dab3cefd78..ccd437c0a0 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -33,7 +33,9 @@ pub fn create(grid_manager: Arc) -> Module { .event(GridEvent::NewSelectOption, new_select_option_handler) .event(GridEvent::UpdateSelectOption, update_select_option_handler) .event(GridEvent::GetSelectOptionContext, get_select_option_handler) - .event(GridEvent::UpdateCellSelectOption, update_cell_select_option_handler); + .event(GridEvent::UpdateSelectOptionCell, update_select_option_cell_handler) + // Date + .event(GridEvent::UpdateDateCell, update_date_cell_handler); module } @@ -105,5 +107,8 @@ pub enum GridEvent { UpdateCell = 71, #[event(input = "SelectOptionCellChangesetPayload")] - UpdateCellSelectOption = 72, + UpdateSelectOptionCell = 72, + + #[event(input = "DateChangesetPayload")] + UpdateDateCell = 80, } diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs index 223d6f322c..0d84c294ac 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs @@ -237,6 +237,343 @@ impl ::protobuf::reflect::ProtobufValue for DateTypeOption { } } +#[derive(PartialEq,Clone,Default)] +pub struct DateChangesetPayload { + // message fields + pub cell_identifier: ::protobuf::SingularPtrField, + // message oneof groups + pub one_of_date: ::std::option::Option, + pub one_of_time: ::std::option::Option, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a DateChangesetPayload { + fn default() -> &'a DateChangesetPayload { + ::default_instance() + } +} + +#[derive(Clone,PartialEq,Debug)] +pub enum DateChangesetPayload_oneof_one_of_date { + date(::std::string::String), +} + +#[derive(Clone,PartialEq,Debug)] +pub enum DateChangesetPayload_oneof_one_of_time { + time(::std::string::String), +} + +impl DateChangesetPayload { + pub fn new() -> DateChangesetPayload { + ::std::default::Default::default() + } + + // .CellIdentifierPayload cell_identifier = 1; + + + pub fn get_cell_identifier(&self) -> &super::cell_entities::CellIdentifierPayload { + self.cell_identifier.as_ref().unwrap_or_else(|| ::default_instance()) + } + pub fn clear_cell_identifier(&mut self) { + self.cell_identifier.clear(); + } + + pub fn has_cell_identifier(&self) -> bool { + self.cell_identifier.is_some() + } + + // Param is passed by value, moved + pub fn set_cell_identifier(&mut self, v: super::cell_entities::CellIdentifierPayload) { + self.cell_identifier = ::protobuf::SingularPtrField::some(v); + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_cell_identifier(&mut self) -> &mut super::cell_entities::CellIdentifierPayload { + if self.cell_identifier.is_none() { + self.cell_identifier.set_default(); + } + self.cell_identifier.as_mut().unwrap() + } + + // Take field + pub fn take_cell_identifier(&mut self) -> super::cell_entities::CellIdentifierPayload { + self.cell_identifier.take().unwrap_or_else(|| super::cell_entities::CellIdentifierPayload::new()) + } + + // string date = 2; + + + pub fn get_date(&self) -> &str { + match self.one_of_date { + ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_date::date(ref v)) => v, + _ => "", + } + } + pub fn clear_date(&mut self) { + self.one_of_date = ::std::option::Option::None; + } + + pub fn has_date(&self) -> bool { + match self.one_of_date { + ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_date::date(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_date(&mut self, v: ::std::string::String) { + self.one_of_date = ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_date::date(v)) + } + + // Mutable pointer to the field. + pub fn mut_date(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_date::date(_)) = self.one_of_date { + } else { + self.one_of_date = ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_date::date(::std::string::String::new())); + } + match self.one_of_date { + ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_date::date(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_date(&mut self) -> ::std::string::String { + if self.has_date() { + match self.one_of_date.take() { + ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_date::date(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } + + // string time = 3; + + + pub fn get_time(&self) -> &str { + match self.one_of_time { + ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_time::time(ref v)) => v, + _ => "", + } + } + pub fn clear_time(&mut self) { + self.one_of_time = ::std::option::Option::None; + } + + pub fn has_time(&self) -> bool { + match self.one_of_time { + ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_time::time(..)) => true, + _ => false, + } + } + + // Param is passed by value, moved + pub fn set_time(&mut self, v: ::std::string::String) { + self.one_of_time = ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_time::time(v)) + } + + // Mutable pointer to the field. + pub fn mut_time(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_time::time(_)) = self.one_of_time { + } else { + self.one_of_time = ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_time::time(::std::string::String::new())); + } + match self.one_of_time { + ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_time::time(ref mut v)) => v, + _ => panic!(), + } + } + + // Take field + pub fn take_time(&mut self) -> ::std::string::String { + if self.has_time() { + match self.one_of_time.take() { + ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_time::time(v)) => v, + _ => panic!(), + } + } else { + ::std::string::String::new() + } + } +} + +impl ::protobuf::Message for DateChangesetPayload { + fn is_initialized(&self) -> bool { + for v in &self.cell_identifier { + 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.cell_identifier)?; + }, + 2 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_date = ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_date::date(is.read_string()?)); + }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + self.one_of_time = ::std::option::Option::Some(DateChangesetPayload_oneof_one_of_time::time(is.read_string()?)); + }, + _ => { + ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u32 { + let mut my_size = 0; + if let Some(ref v) = self.cell_identifier.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_date { + match v { + &DateChangesetPayload_oneof_one_of_date::date(ref v) => { + my_size += ::protobuf::rt::string_size(2, &v); + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_time { + match v { + &DateChangesetPayload_oneof_one_of_time::time(ref v) => { + my_size += ::protobuf::rt::string_size(3, &v); + }, + }; + } + my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); + self.cached_size.set(my_size); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { + if let Some(ref v) = self.cell_identifier.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_date { + match v { + &DateChangesetPayload_oneof_one_of_date::date(ref v) => { + os.write_string(2, v)?; + }, + }; + } + if let ::std::option::Option::Some(ref v) = self.one_of_time { + match v { + &DateChangesetPayload_oneof_one_of_time::time(ref v) => { + os.write_string(3, v)?; + }, + }; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> DateChangesetPayload { + DateChangesetPayload::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>( + "cell_identifier", + |m: &DateChangesetPayload| { &m.cell_identifier }, + |m: &mut DateChangesetPayload| { &mut m.cell_identifier }, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "date", + DateChangesetPayload::has_date, + DateChangesetPayload::get_date, + )); + fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( + "time", + DateChangesetPayload::has_time, + DateChangesetPayload::get_time, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "DateChangesetPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static DateChangesetPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(DateChangesetPayload::new) + } +} + +impl ::protobuf::Clear for DateChangesetPayload { + fn clear(&mut self) { + self.cell_identifier.clear(); + self.one_of_date = ::std::option::Option::None; + self.one_of_time = ::std::option::Option::None; + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for DateChangesetPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for DateChangesetPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(Clone,PartialEq,Eq,Debug,Hash)] pub enum DateFormat { Local = 0, @@ -344,13 +681,17 @@ impl ::protobuf::reflect::ProtobufValue for TimeFormat { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x16date_type_option.proto\"\x8f\x01\n\x0eDateTypeOption\x12,\n\x0bdat\ - e_format\x18\x01\x20\x01(\x0e2\x0b.DateFormatR\ndateFormat\x12,\n\x0btim\ - e_format\x18\x02\x20\x01(\x0e2\x0b.TimeFormatR\ntimeFormat\x12!\n\x0cinc\ - lude_time\x18\x03\x20\x01(\x08R\x0bincludeTime*6\n\nDateFormat\x12\t\n\ - \x05Local\x10\0\x12\x06\n\x02US\x10\x01\x12\x07\n\x03ISO\x10\x02\x12\x0c\ - \n\x08Friendly\x10\x03*0\n\nTimeFormat\x12\x0e\n\nTwelveHour\x10\0\x12\ - \x12\n\x0eTwentyFourHour\x10\x01b\x06proto3\ + \n\x16date_type_option.proto\x1a\x13cell_entities.proto\"\x8f\x01\n\x0eD\ + ateTypeOption\x12,\n\x0bdate_format\x18\x01\x20\x01(\x0e2\x0b.DateFormat\ + R\ndateFormat\x12,\n\x0btime_format\x18\x02\x20\x01(\x0e2\x0b.TimeFormat\ + R\ntimeFormat\x12!\n\x0cinclude_time\x18\x03\x20\x01(\x08R\x0bincludeTim\ + e\"\xa1\x01\n\x14DateChangesetPayload\x12?\n\x0fcell_identifier\x18\x01\ + \x20\x01(\x0b2\x16.CellIdentifierPayloadR\x0ecellIdentifier\x12\x14\n\ + \x04date\x18\x02\x20\x01(\tH\0R\x04date\x12\x14\n\x04time\x18\x03\x20\ + \x01(\tH\x01R\x04timeB\r\n\x0bone_of_dateB\r\n\x0bone_of_time*6\n\nDateF\ + ormat\x12\t\n\x05Local\x10\0\x12\x06\n\x02US\x10\x01\x12\x07\n\x03ISO\ + \x10\x02\x12\x0c\n\x08Friendly\x10\x03*0\n\nTimeFormat\x12\x0e\n\nTwelve\ + Hour\x10\0\x12\x12\n\x0eTwentyFourHour\x10\x01b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs index bf1cb2c71a..0b2648208c 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs @@ -46,7 +46,8 @@ pub enum GridEvent { DuplicateRow = 53, GetCell = 70, UpdateCell = 71, - UpdateCellSelectOption = 72, + UpdateSelectOptionCell = 72, + UpdateDateCell = 80, } impl ::protobuf::ProtobufEnum for GridEvent { @@ -77,7 +78,8 @@ impl ::protobuf::ProtobufEnum for GridEvent { 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::UpdateCellSelectOption), + 72 => ::std::option::Option::Some(GridEvent::UpdateSelectOptionCell), + 80 => ::std::option::Option::Some(GridEvent::UpdateDateCell), _ => ::std::option::Option::None } } @@ -105,7 +107,8 @@ impl ::protobuf::ProtobufEnum for GridEvent { GridEvent::DuplicateRow, GridEvent::GetCell, GridEvent::UpdateCell, - GridEvent::UpdateCellSelectOption, + GridEvent::UpdateSelectOptionCell, + GridEvent::UpdateDateCell, ]; values } @@ -134,7 +137,7 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\xb0\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ + \n\x0fevent_map.proto*\xc4\x03\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\x19\n\x15UpdateFieldTypeOption\x10\x0c\x12\ \x0f\n\x0bInsertField\x10\r\x12\x0f\n\x0bDeleteField\x10\x0e\x12\x11\n\r\ @@ -144,7 +147,8 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x16GetSelectOptionContext\x10\x1f\x12\x16\n\x12UpdateSelectOption\x10\ \x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteRow\ \x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\ - \nUpdateCell\x10G\x12\x1a\n\x16UpdateCellSelectOption\x10Hb\x06proto3\ + \nUpdateCell\x10G\x12\x1a\n\x16UpdateSelectOptionCell\x10H\x12\x12\n\x0e\ + UpdateDateCell\x10Pb\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs index fb945be12b..d81b9ce6cb 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs @@ -1102,9 +1102,7 @@ impl ::protobuf::reflect::ProtobufValue for SelectOptionChangesetPayload { #[derive(PartialEq,Clone,Default)] pub struct SelectOptionCellChangesetPayload { // message fields - pub grid_id: ::std::string::String, - pub row_id: ::std::string::String, - pub field_id: ::std::string::String, + pub cell_identifier: ::protobuf::SingularPtrField, // message oneof groups pub one_of_insert_option_id: ::std::option::Option, pub one_of_delete_option_id: ::std::option::Option, @@ -1134,85 +1132,40 @@ impl SelectOptionCellChangesetPayload { ::std::default::Default::default() } - // string grid_id = 1; + // .CellIdentifierPayload cell_identifier = 1; - pub fn get_grid_id(&self) -> &str { - &self.grid_id + pub fn get_cell_identifier(&self) -> &super::cell_entities::CellIdentifierPayload { + self.cell_identifier.as_ref().unwrap_or_else(|| ::default_instance()) } - pub fn clear_grid_id(&mut self) { - self.grid_id.clear(); + pub fn clear_cell_identifier(&mut self) { + self.cell_identifier.clear(); + } + + pub fn has_cell_identifier(&self) -> bool { + self.cell_identifier.is_some() } // Param is passed by value, moved - pub fn set_grid_id(&mut self, v: ::std::string::String) { - self.grid_id = v; + pub fn set_cell_identifier(&mut self, v: super::cell_entities::CellIdentifierPayload) { + self.cell_identifier = ::protobuf::SingularPtrField::some(v); } // Mutable pointer to the field. // If field is not initialized, it is initialized with default value first. - pub fn mut_grid_id(&mut self) -> &mut ::std::string::String { - &mut self.grid_id + pub fn mut_cell_identifier(&mut self) -> &mut super::cell_entities::CellIdentifierPayload { + if self.cell_identifier.is_none() { + self.cell_identifier.set_default(); + } + self.cell_identifier.as_mut().unwrap() } // Take field - pub fn take_grid_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.grid_id, ::std::string::String::new()) + pub fn take_cell_identifier(&mut self) -> super::cell_entities::CellIdentifierPayload { + self.cell_identifier.take().unwrap_or_else(|| super::cell_entities::CellIdentifierPayload::new()) } - // string row_id = 2; - - - pub fn get_row_id(&self) -> &str { - &self.row_id - } - pub fn clear_row_id(&mut self) { - self.row_id.clear(); - } - - // Param is passed by value, moved - pub fn set_row_id(&mut self, v: ::std::string::String) { - self.row_id = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_row_id(&mut self) -> &mut ::std::string::String { - &mut self.row_id - } - - // Take field - pub fn take_row_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.row_id, ::std::string::String::new()) - } - - // string field_id = 3; - - - pub fn get_field_id(&self) -> &str { - &self.field_id - } - pub fn clear_field_id(&mut self) { - self.field_id.clear(); - } - - // Param is passed by value, moved - pub fn set_field_id(&mut self, v: ::std::string::String) { - self.field_id = v; - } - - // Mutable pointer to the field. - // If field is not initialized, it is initialized with default value first. - pub fn mut_field_id(&mut self) -> &mut ::std::string::String { - &mut self.field_id - } - - // Take field - pub fn take_field_id(&mut self) -> ::std::string::String { - ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) - } - - // string insert_option_id = 4; + // string insert_option_id = 2; pub fn get_insert_option_id(&self) -> &str { @@ -1261,7 +1214,7 @@ impl SelectOptionCellChangesetPayload { } } - // string delete_option_id = 5; + // string delete_option_id = 3; pub fn get_delete_option_id(&self) -> &str { @@ -1313,6 +1266,11 @@ impl SelectOptionCellChangesetPayload { impl ::protobuf::Message for SelectOptionCellChangesetPayload { fn is_initialized(&self) -> bool { + for v in &self.cell_identifier { + if !v.is_initialized() { + return false; + } + }; true } @@ -1321,21 +1279,15 @@ impl ::protobuf::Message for SelectOptionCellChangesetPayload { let (field_number, wire_type) = is.read_tag_unpack()?; match field_number { 1 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.grid_id)?; + ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.cell_identifier)?; }, 2 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.row_id)?; - }, - 3 => { - ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.field_id)?; - }, - 4 => { if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } self.one_of_insert_option_id = ::std::option::Option::Some(SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(is.read_string()?)); }, - 5 => { + 3 => { if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } @@ -1353,26 +1305,21 @@ impl ::protobuf::Message for SelectOptionCellChangesetPayload { #[allow(unused_variables)] fn compute_size(&self) -> u32 { let mut my_size = 0; - if !self.grid_id.is_empty() { - my_size += ::protobuf::rt::string_size(1, &self.grid_id); - } - if !self.row_id.is_empty() { - my_size += ::protobuf::rt::string_size(2, &self.row_id); - } - if !self.field_id.is_empty() { - my_size += ::protobuf::rt::string_size(3, &self.field_id); + if let Some(ref v) = self.cell_identifier.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_insert_option_id { match v { &SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(ref v) => { - my_size += ::protobuf::rt::string_size(4, &v); + my_size += ::protobuf::rt::string_size(2, &v); }, }; } if let ::std::option::Option::Some(ref v) = self.one_of_delete_option_id { match v { &SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(ref v) => { - my_size += ::protobuf::rt::string_size(5, &v); + my_size += ::protobuf::rt::string_size(3, &v); }, }; } @@ -1382,26 +1329,22 @@ impl ::protobuf::Message for SelectOptionCellChangesetPayload { } fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { - if !self.grid_id.is_empty() { - os.write_string(1, &self.grid_id)?; - } - if !self.row_id.is_empty() { - os.write_string(2, &self.row_id)?; - } - if !self.field_id.is_empty() { - os.write_string(3, &self.field_id)?; + if let Some(ref v) = self.cell_identifier.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_insert_option_id { match v { &SelectOptionCellChangesetPayload_oneof_one_of_insert_option_id::insert_option_id(ref v) => { - os.write_string(4, v)?; + os.write_string(2, v)?; }, }; } if let ::std::option::Option::Some(ref v) = self.one_of_delete_option_id { match v { &SelectOptionCellChangesetPayload_oneof_one_of_delete_option_id::delete_option_id(ref v) => { - os.write_string(5, v)?; + os.write_string(3, v)?; }, }; } @@ -1443,20 +1386,10 @@ impl ::protobuf::Message for SelectOptionCellChangesetPayload { static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; descriptor.get(|| { let mut fields = ::std::vec::Vec::new(); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "grid_id", - |m: &SelectOptionCellChangesetPayload| { &m.grid_id }, - |m: &mut SelectOptionCellChangesetPayload| { &mut m.grid_id }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "row_id", - |m: &SelectOptionCellChangesetPayload| { &m.row_id }, - |m: &mut SelectOptionCellChangesetPayload| { &mut m.row_id }, - )); - fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( - "field_id", - |m: &SelectOptionCellChangesetPayload| { &m.field_id }, - |m: &mut SelectOptionCellChangesetPayload| { &mut m.field_id }, + fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( + "cell_identifier", + |m: &SelectOptionCellChangesetPayload| { &m.cell_identifier }, + |m: &mut SelectOptionCellChangesetPayload| { &mut m.cell_identifier }, )); fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( "insert_option_id", @@ -1484,9 +1417,7 @@ impl ::protobuf::Message for SelectOptionCellChangesetPayload { impl ::protobuf::Clear for SelectOptionCellChangesetPayload { fn clear(&mut self) { - self.grid_id.clear(); - self.row_id.clear(); - self.field_id.clear(); + self.cell_identifier.clear(); self.one_of_insert_option_id = ::std::option::Option::None; self.one_of_delete_option_id = ::std::option::Option::None; self.unknown_fields.clear(); @@ -1806,19 +1737,18 @@ static file_descriptor_proto_data: &'static [u8] = b"\ _option\x18\x03\x20\x01(\x0b2\r.SelectOptionH\x01R\x0cupdateOption\x124\ \n\rdelete_option\x18\x04\x20\x01(\x0b2\r.SelectOptionH\x02R\x0cdeleteOp\ tionB\x16\n\x14one_of_insert_optionB\x16\n\x14one_of_update_optionB\x16\ - \n\x14one_of_delete_option\"\xfb\x01\n\x20SelectOptionCellChangesetPaylo\ - ad\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_i\ - d\x18\x02\x20\x01(\tR\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\ - \x07fieldId\x12*\n\x10insert_option_id\x18\x04\x20\x01(\tH\0R\x0einsertO\ - ptionId\x12*\n\x10delete_option_id\x18\x05\x20\x01(\tH\x01R\x0edeleteOpt\ - ionIdB\x19\n\x17one_of_insert_option_idB\x19\n\x17one_of_delete_option_i\ - d\"t\n\x13SelectOptionContext\x12'\n\x07options\x18\x01\x20\x03(\x0b2\r.\ - SelectOptionR\x07options\x124\n\x0eselect_options\x18\x02\x20\x03(\x0b2\ - \r.SelectOptionR\rselectOptions*y\n\x11SelectOptionColor\x12\n\n\x06Purp\ - le\x10\0\x12\x08\n\x04Pink\x10\x01\x12\r\n\tLightPink\x10\x02\x12\n\n\ - \x06Orange\x10\x03\x12\n\n\x06Yellow\x10\x04\x12\x08\n\x04Lime\x10\x05\ - \x12\t\n\x05Green\x10\x06\x12\x08\n\x04Aqua\x10\x07\x12\x08\n\x04Blue\ - \x10\x08b\x06proto3\ + \n\x14one_of_delete_option\"\xf1\x01\n\x20SelectOptionCellChangesetPaylo\ + ad\x12?\n\x0fcell_identifier\x18\x01\x20\x01(\x0b2\x16.CellIdentifierPay\ + loadR\x0ecellIdentifier\x12*\n\x10insert_option_id\x18\x02\x20\x01(\tH\0\ + R\x0einsertOptionId\x12*\n\x10delete_option_id\x18\x03\x20\x01(\tH\x01R\ + \x0edeleteOptionIdB\x19\n\x17one_of_insert_option_idB\x19\n\x17one_of_de\ + lete_option_id\"t\n\x13SelectOptionContext\x12'\n\x07options\x18\x01\x20\ + \x03(\x0b2\r.SelectOptionR\x07options\x124\n\x0eselect_options\x18\x02\ + \x20\x03(\x0b2\r.SelectOptionR\rselectOptions*y\n\x11SelectOptionColor\ + \x12\n\n\x06Purple\x10\0\x12\x08\n\x04Pink\x10\x01\x12\r\n\tLightPink\ + \x10\x02\x12\n\n\x06Orange\x10\x03\x12\n\n\x06Yellow\x10\x04\x12\x08\n\ + \x04Lime\x10\x05\x12\t\n\x05Green\x10\x06\x12\x08\n\x04Aqua\x10\x07\x12\ + \x08\n\x04Blue\x10\x08b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto index 6dbc5ae09b..602082e8a9 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto @@ -1,10 +1,16 @@ syntax = "proto3"; +import "cell_entities.proto"; message DateTypeOption { DateFormat date_format = 1; TimeFormat time_format = 2; bool include_time = 3; } +message DateChangesetPayload { + CellIdentifierPayload cell_identifier = 1; + oneof one_of_date { string date = 2; }; + oneof one_of_time { string time = 3; }; +} enum DateFormat { Local = 0; US = 1; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto index ab804c2b82..c98008d678 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto @@ -22,5 +22,6 @@ enum GridEvent { DuplicateRow = 53; GetCell = 70; UpdateCell = 71; - UpdateCellSelectOption = 72; + UpdateSelectOptionCell = 72; + UpdateDateCell = 80; } diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto index 9940c13e9c..822d0933cb 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto @@ -21,11 +21,9 @@ message SelectOptionChangesetPayload { oneof one_of_delete_option { SelectOption delete_option = 4; }; } message SelectOptionCellChangesetPayload { - string grid_id = 1; - string row_id = 2; - string field_id = 3; - oneof one_of_insert_option_id { string insert_option_id = 4; }; - oneof one_of_delete_option_id { string delete_option_id = 5; }; + CellIdentifierPayload cell_identifier = 1; + oneof one_of_insert_option_id { string insert_option_id = 2; }; + oneof one_of_delete_option_id { string delete_option_id = 3; }; } message SelectOptionContext { repeated SelectOption options = 1; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs index ff1f2d3d78..73c3f5f2d7 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/checkbox_type_option.rs @@ -1,6 +1,6 @@ use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; +use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use flowy_derive::ProtoBuf; use flowy_error::FlowyError; @@ -44,7 +44,7 @@ const YES: &str = "Yes"; const NO: &str = "No"; impl CellDataOperation for CheckboxTypeOption { - fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if !type_option_cell_data.is_checkbox() { return DecodedCellData::default(); @@ -58,7 +58,7 @@ impl CellDataOperation for CheckboxTypeOption { DecodedCellData::default() } - fn apply_changeset>( + fn apply_changeset>( &self, changeset: T, _cell_meta: Option, @@ -99,21 +99,21 @@ mod tests { let field_meta = FieldBuilder::from_field_type(&FieldType::DateTime).build(); let data = type_option.apply_changeset("true", None).unwrap(); - assert_eq!(type_option.decode_cell_data(data, &field_meta), YES); + assert_eq!(type_option.decode_cell_data(data, &field_meta).content, YES); let data = type_option.apply_changeset("1", None).unwrap(); - assert_eq!(type_option.decode_cell_data(data, &field_meta), YES); + assert_eq!(type_option.decode_cell_data(data, &field_meta).content, YES); let data = type_option.apply_changeset("yes", None).unwrap(); - assert_eq!(type_option.decode_cell_data(data, &field_meta), YES); + assert_eq!(type_option.decode_cell_data(data, &field_meta).content, YES); let data = type_option.apply_changeset("false", None).unwrap(); - assert_eq!(type_option.decode_cell_data(data, &field_meta), NO); + assert_eq!(type_option.decode_cell_data(data, &field_meta).content, NO); let data = type_option.apply_changeset("no", None).unwrap(); - assert_eq!(type_option.decode_cell_data(data, &field_meta), NO); + assert_eq!(type_option.decode_cell_data(data, &field_meta).content, NO); let data = type_option.apply_changeset("123", None).unwrap(); - assert_eq!(type_option.decode_cell_data(data, &field_meta), NO); + assert_eq!(type_option.decode_cell_data(data, &field_meta).content, NO); } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 42912b932f..844d7568db 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -1,17 +1,19 @@ use crate::impl_type_option; -use crate::services::row::{CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; +use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use chrono::format::strftime::StrftimeItems; -use chrono::{NaiveDateTime, ParseResult}; +use chrono::{Datelike, NaiveDateTime}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error::FlowyError; +use flowy_error::{ErrorCode, FlowyError}; use flowy_grid_data_model::entities::{ - CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, + CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, }; use serde::{Deserialize, Serialize}; use std::str::FromStr; +use crate::services::entities::{CellIdentifier, CellIdentifierPayload}; +use crate::services::field::type_options::util::get_cell_data; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use strum_macros::EnumIter; @@ -53,7 +55,7 @@ impl DateTypeOption { } impl CellDataOperation for DateTypeOption { - fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if !type_option_cell_data.is_date() { return DecodedCellData::default(); @@ -74,7 +76,7 @@ impl CellDataOperation for DateTypeOption { DecodedCellData::default() } - fn apply_changeset>( + fn apply_changeset>( &self, changeset: T, _cell_meta: Option, @@ -196,6 +198,59 @@ impl std::default::Default for TimeFormat { } } +#[derive(Clone, Debug, Default, ProtoBuf)] +pub struct DateChangesetPayload { + #[pb(index = 1)] + pub cell_identifier: CellIdentifierPayload, + + #[pb(index = 2, one_of)] + pub date: Option, + + #[pb(index = 3, one_of)] + pub time: Option, +} + +pub struct DateChangesetParams { + pub cell_identifier: CellIdentifier, + pub date: Option, + pub time: Option, +} + +impl TryInto for DateChangesetPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let cell_identifier: CellIdentifier = self.cell_identifier.try_into()?; + Ok(DateChangesetParams { + cell_identifier, + date: self.date, + time: self.time, + }) + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct DateCellContentChangeset { + pub date: Option, + pub time: Option, +} + +impl std::convert::From for CellChangeset { + fn from(params: DateChangesetParams) -> Self { + let changeset = DateCellContentChangeset { + date: params.date, + time: params.time, + }; + let s = serde_json::to_string(&changeset).unwrap(); + CellChangeset { + grid_id: params.cell_identifier.grid_id, + row_id: params.cell_identifier.row_id, + field_id: params.cell_identifier.field_id, + cell_content_changeset: Some(s), + } + } +} + #[cfg(test)] mod tests { use crate::services::field::FieldBuilder; @@ -210,7 +265,7 @@ mod tests { let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); assert_eq!( "".to_owned(), - type_option.decode_cell_data("1e".to_owned(), &field_meta) + type_option.decode_cell_data("1e".to_owned(), &field_meta).content ); } @@ -224,35 +279,39 @@ mod tests { DateFormat::Friendly => { assert_eq!( "Mar 14,2022".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta) + type_option.decode_cell_data(data("1647251762"), &field_meta).content ); assert_eq!( // "Mar 14,2022".to_owned(), "".to_owned(), - type_option.decode_cell_data(data("Mar 14,2022 17:56"), &field_meta) + type_option + .decode_cell_data(data("Mar 14,2022 17:56"), &field_meta) + .content ); } DateFormat::US => { assert_eq!( "2022/03/14".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta) + type_option.decode_cell_data(data("1647251762"), &field_meta).content ); assert_eq!( // "2022/03/14".to_owned(), "".to_owned(), - type_option.decode_cell_data(data("2022/03/14 17:56"), &field_meta) + type_option + .decode_cell_data(data("2022/03/14 17:56"), &field_meta) + .content ); } DateFormat::ISO => { assert_eq!( "2022-03-14".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta) + type_option.decode_cell_data(data("1647251762"), &field_meta).content ); } DateFormat::Local => { assert_eq!( "2022/03/14".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta) + type_option.decode_cell_data(data("1647251762"), &field_meta).content ); } } @@ -270,14 +329,14 @@ mod tests { assert_eq!("Mar 14,2022".to_owned(), type_option.today_from_timestamp(1647251762)); assert_eq!( "Mar 14,2022".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta) + type_option.decode_cell_data(data("1647251762"), &field_meta).content ); } TimeFormat::TwelveHour => { assert_eq!("Mar 14,2022".to_owned(), type_option.today_from_timestamp(1647251762)); assert_eq!( "Mar 14,2022".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta) + type_option.decode_cell_data(data("1647251762"), &field_meta).content ); } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs index b5cab79b97..2c74b2097b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/mod.rs @@ -3,7 +3,7 @@ mod date_type_option; mod number_type_option; mod selection_type_option; mod text_type_option; -mod type_option_data; +mod util; pub use checkbox_type_option::*; pub use date_type_option::*; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs index 36c05410da..a57b056f5d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/number_type_option.rs @@ -1,6 +1,6 @@ use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; +use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::FlowyError; @@ -77,14 +77,14 @@ pub struct NumberTypeOption { impl_type_option!(NumberTypeOption, FieldType::Number); impl CellDataOperation for NumberTypeOption { - fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData { + fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { if type_option_cell_data.is_date() { return DecodedCellData::default(); } let cell_data = type_option_cell_data.data; - return match self.format { + match self.format { NumberFormat::Number => { if let Ok(v) = cell_data.parse::() { return DecodedCellData::from_content(v.to_string()); @@ -104,13 +104,13 @@ impl CellDataOperation for NumberTypeOption { let content = self.money_from_str(&cell_data); DecodedCellData::from_content(content) } - }; + } } else { DecodedCellData::default() } } - fn apply_changeset>( + fn apply_changeset>( &self, changeset: T, _cell_meta: Option, @@ -562,7 +562,7 @@ define_currency_set!( impl NumberFormat { pub fn currency(&self) -> &'static number_currency::Currency { - let currency = match self { + match self { NumberFormat::Number => number_currency::NUMBER, NumberFormat::USD => number_currency::USD, NumberFormat::CanadianDollar => number_currency::CANADIAN_DOLLAR, @@ -599,8 +599,7 @@ impl NumberFormat { NumberFormat::ArgentinePeso => number_currency::ARS, NumberFormat::UruguayanPeso => number_currency::UYU, NumberFormat::Percent => number_currency::USD, - }; - currency + } } pub fn symbol(&self) -> String { @@ -628,8 +627,14 @@ mod tests { fn number_description_invalid_input_test() { let type_option = NumberTypeOption::default(); let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); - assert_eq!("".to_owned(), type_option.decode_cell_data(data(""), &field_meta)); - assert_eq!("".to_owned(), type_option.decode_cell_data(data("abc"), &field_meta)); + assert_eq!( + "".to_owned(), + type_option.decode_cell_data(data(""), &field_meta).content + ); + assert_eq!( + "".to_owned(), + type_option.decode_cell_data(data("abc"), &field_meta).content + ); } #[test] @@ -645,33 +650,39 @@ mod tests { match format { NumberFormat::Number => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "18443".to_owned() ); } NumberFormat::USD => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "$18,443".to_owned() ); - assert_eq!(type_option.decode_cell_data(data(""), &field_meta), "".to_owned()); - assert_eq!(type_option.decode_cell_data(data("abc"), &field_meta), "".to_owned()); + assert_eq!( + type_option.decode_cell_data(data(""), &field_meta).content, + "".to_owned() + ); + assert_eq!( + type_option.decode_cell_data(data("abc"), &field_meta).content, + "".to_owned() + ); } NumberFormat::Yen => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "Â¥18,443".to_owned() ); } NumberFormat::Yuan => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "CNÂ¥18,443".to_owned() ); } NumberFormat::EUR => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "€18.443".to_owned() ); } @@ -697,25 +708,25 @@ mod tests { match format { NumberFormat::Number => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "18443".to_owned() ); } NumberFormat::USD => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "$1,844.3".to_owned() ); } NumberFormat::Yen => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "Â¥1,844.3".to_owned() ); } NumberFormat::EUR => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "€1.844,3".to_owned() ); } @@ -737,25 +748,25 @@ mod tests { match format { NumberFormat::Number => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "18443".to_owned() ); } NumberFormat::USD => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "-$18,443".to_owned() ); } NumberFormat::Yen => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "-Â¥18,443".to_owned() ); } NumberFormat::EUR => { assert_eq!( - type_option.decode_cell_data(data("18443"), &field_meta), + type_option.decode_cell_data(data("18443"), &field_meta).content, "-€18.443".to_owned() ); } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs index 7b049a7385..e6a37d546e 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs @@ -1,7 +1,8 @@ use crate::impl_type_option; use crate::services::entities::{CellIdentifier, CellIdentifierPayload}; +use crate::services::field::type_options::util::get_cell_data; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; -use crate::services::row::{CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; +use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{ErrorCode, FlowyError, FlowyResult}; @@ -112,13 +113,13 @@ impl CellDataOperation for SingleSelectTypeOption { DecodedCellData::default() } - fn apply_changeset>( + fn apply_changeset>( &self, changeset: T, _cell_meta: Option, ) -> Result { let changeset = changeset.into(); - let select_option_changeset: SelectOptionCellChangeset = serde_json::from_str(&changeset)?; + let select_option_changeset: SelectOptionCellContentChangeset = serde_json::from_str(&changeset)?; let new_cell_data: String; if let Some(insert_option_id) = select_option_changeset.insert_option_id { tracing::trace!("Insert single select option: {}", &insert_option_id); @@ -165,15 +166,6 @@ pub struct MultiSelectTypeOption { } impl_type_option!(MultiSelectTypeOption, FieldType::MultiSelect); -impl MultiSelectTypeOption { - pub fn get_cell_data(&self, cell_meta: &CellMeta) -> String { - match TypeOptionCellData::from_str(&cell_meta.data) { - Ok(type_option) => type_option.data, - Err(_) => String::new(), - } - } -} - impl SelectOptionOperation for MultiSelectTypeOption { fn option_context(&self, cell_meta: &Option) -> SelectOptionContext { let select_options = make_select_context_from(cell_meta, &self.options); @@ -212,24 +204,21 @@ impl CellDataOperation for MultiSelectTypeOption { } } - fn apply_changeset>( + fn apply_changeset>( &self, changeset: T, cell_meta: Option, ) -> Result { - let changeset = changeset.into(); - let select_option_changeset: SelectOptionCellChangeset = serde_json::from_str(&changeset)?; + let content_changeset: SelectOptionCellContentChangeset = serde_json::from_str(&changeset.into())?; let new_cell_data: String; match cell_meta { None => { - new_cell_data = select_option_changeset - .insert_option_id - .unwrap_or_else(|| "".to_owned()); + new_cell_data = content_changeset.insert_option_id.unwrap_or_else(|| "".to_owned()); } Some(cell_meta) => { - let cell_data = self.get_cell_data(&cell_meta); + let cell_data = get_cell_data(&cell_meta); let mut selected_options = select_option_ids(cell_data); - if let Some(insert_option_id) = select_option_changeset.insert_option_id { + if let Some(insert_option_id) = content_changeset.insert_option_id { tracing::trace!("Insert multi select option: {}", &insert_option_id); if selected_options.contains(&insert_option_id) { selected_options.retain(|id| id != &insert_option_id); @@ -238,7 +227,7 @@ impl CellDataOperation for MultiSelectTypeOption { } } - if let Some(delete_option_id) = select_option_changeset.delete_option_id { + if let Some(delete_option_id) = content_changeset.delete_option_id { tracing::trace!("Delete multi select option: {}", &delete_option_id); selected_options.retain(|id| id != &delete_option_id); } @@ -348,68 +337,33 @@ impl TryInto for SelectOptionChangesetPayload { #[derive(Clone, Debug, Default, ProtoBuf)] pub struct SelectOptionCellChangesetPayload { #[pb(index = 1)] - pub grid_id: String, + pub cell_identifier: CellIdentifierPayload, - #[pb(index = 2)] - pub row_id: String, - - #[pb(index = 3)] - pub field_id: String, - - #[pb(index = 4, one_of)] + #[pb(index = 2, one_of)] pub insert_option_id: Option, - #[pb(index = 5, one_of)] + #[pb(index = 3, one_of)] pub delete_option_id: Option, } pub struct SelectOptionCellChangesetParams { - pub grid_id: String, - pub field_id: String, - pub row_id: String, - pub insert_option_id: Option, - - pub delete_option_id: Option, -} - -#[derive(Clone, Serialize, Deserialize)] -pub struct SelectOptionCellChangeset { + pub cell_identifier: CellIdentifier, pub insert_option_id: Option, pub delete_option_id: Option, } -impl SelectOptionCellChangeset { - pub fn from_insert(option_id: &str) -> Self { - SelectOptionCellChangeset { - insert_option_id: Some(option_id.to_string()), - delete_option_id: None, - } - } - - pub fn from_delete(option_id: &str) -> Self { - SelectOptionCellChangeset { - insert_option_id: None, - delete_option_id: Some(option_id.to_string()), - } - } - - pub fn cell_data(&self) -> String { - serde_json::to_string(self).unwrap() - } -} - impl std::convert::From for CellChangeset { fn from(params: SelectOptionCellChangesetParams) -> Self { - let changeset = SelectOptionCellChangeset { + let changeset = SelectOptionCellContentChangeset { insert_option_id: params.insert_option_id, delete_option_id: params.delete_option_id, }; let s = serde_json::to_string(&changeset).unwrap(); CellChangeset { - grid_id: params.grid_id, - row_id: params.row_id, - field_id: params.field_id, - data: Some(s), + grid_id: params.cell_identifier.grid_id, + row_id: params.cell_identifier.row_id, + field_id: params.cell_identifier.field_id, + cell_content_changeset: Some(s), } } } @@ -418,9 +372,7 @@ impl TryInto for SelectOptionCellChangesetPaylo type Error = ErrorCode; fn try_into(self) -> Result { - let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; - let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?; - let field_id = NotEmptyStr::parse(self.field_id).map_err(|_| ErrorCode::FieldIdIsEmpty)?; + let cell_identifier: CellIdentifier = self.cell_identifier.try_into()?; let insert_option_id = match self.insert_option_id { None => None, Some(insert_option_id) => Some( @@ -440,15 +392,39 @@ impl TryInto for SelectOptionCellChangesetPaylo }; Ok(SelectOptionCellChangesetParams { - grid_id: grid_id.0, - row_id: row_id.0, - field_id: field_id.0, + cell_identifier, insert_option_id, delete_option_id, }) } } +#[derive(Clone, Serialize, Deserialize)] +pub struct SelectOptionCellContentChangeset { + pub insert_option_id: Option, + pub delete_option_id: Option, +} + +impl SelectOptionCellContentChangeset { + pub fn from_insert(option_id: &str) -> Self { + SelectOptionCellContentChangeset { + insert_option_id: Some(option_id.to_string()), + delete_option_id: None, + } + } + + pub fn from_delete(option_id: &str) -> Self { + SelectOptionCellContentChangeset { + insert_option_id: None, + delete_option_id: Some(option_id.to_string()), + } + } + + pub fn to_str(&self) -> String { + serde_json::to_string(self).unwrap() + } +} + #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] pub struct SelectOptionContext { #[pb(index = 1)] @@ -513,7 +489,7 @@ fn make_select_context_from(cell_meta: &Option, options: &[SelectOptio mod tests { use crate::services::field::FieldBuilder; use crate::services::field::{ - MultiSelectTypeOption, MultiSelectTypeOptionBuilder, SelectOption, SelectOptionCellChangeset, + MultiSelectTypeOption, MultiSelectTypeOptionBuilder, SelectOption, SelectOptionCellContentChangeset, SingleSelectTypeOption, SingleSelectTypeOptionBuilder, SELECTION_IDS_SEPARATOR, }; use crate::services::row::CellDataOperation; @@ -536,25 +512,31 @@ mod tests { let type_option = SingleSelectTypeOption::from(&field_meta); 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 data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str(); let cell_data = type_option.apply_changeset(data, None).unwrap(); - assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), google_option.name,); + assert_eq!( + type_option.decode_cell_data(cell_data, &field_meta).content, + google_option.name, + ); - let data = SelectOptionCellChangeset::from_insert(&google_option.id).cell_data(); + let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str(); let cell_data = type_option.apply_changeset(data, None).unwrap(); - assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), google_option.name,); + assert_eq!( + type_option.decode_cell_data(cell_data, &field_meta).content, + google_option.name, + ); // Invalid option id let cell_data = type_option - .apply_changeset(SelectOptionCellChangeset::from_insert("").cell_data(), None) + .apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None) .unwrap(); - assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), "",); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta).content, "",); // Invalid option id let cell_data = type_option - .apply_changeset(SelectOptionCellChangeset::from_insert("123").cell_data(), None) + .apply_changeset(SelectOptionCellContentChangeset::from_insert("123").to_str(), None) .unwrap(); - assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), "",); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta).content, "",); // Invalid changeset assert!(type_option.apply_changeset("123", None).is_err()); @@ -578,28 +560,31 @@ mod tests { let type_option = MultiSelectTypeOption::from(&field_meta); let option_ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); - let data = SelectOptionCellChangeset::from_insert(&option_ids).cell_data(); + let data = SelectOptionCellContentChangeset::from_insert(&option_ids).to_str(); let cell_data = type_option.apply_changeset(data, None).unwrap(); assert_eq!( - type_option.decode_cell_data(cell_data, &field_meta), + type_option.decode_cell_data(cell_data, &field_meta).content, vec![google_option.name.clone(), facebook_option.name].join(SELECTION_IDS_SEPARATOR), ); - let data = SelectOptionCellChangeset::from_insert(&google_option.id).cell_data(); + let data = SelectOptionCellContentChangeset::from_insert(&google_option.id).to_str(); let cell_data = type_option.apply_changeset(data, None).unwrap(); - assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), google_option.name,); + assert_eq!( + type_option.decode_cell_data(cell_data, &field_meta).content, + google_option.name, + ); // Invalid option id let cell_data = type_option - .apply_changeset(SelectOptionCellChangeset::from_insert("").cell_data(), None) + .apply_changeset(SelectOptionCellContentChangeset::from_insert("").to_str(), None) .unwrap(); - assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), "",); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta).content, "",); // Invalid option id let cell_data = type_option - .apply_changeset(SelectOptionCellChangeset::from_insert("123,456").cell_data(), None) + .apply_changeset(SelectOptionCellContentChangeset::from_insert("123,456").to_str(), None) .unwrap(); - assert_eq!(type_option.decode_cell_data(cell_data, &field_meta), "",); + assert_eq!(type_option.decode_cell_data(cell_data, &field_meta).content, "",); // Invalid changeset assert!(type_option.apply_changeset("123", None).is_err()); diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs index d605a719bf..cf1ca7380f 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -1,7 +1,7 @@ use crate::impl_type_option; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{ - decode_cell_data, CellDataChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData, + decode_cell_data, CellContentChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData, }; use bytes::Bytes; use flowy_derive::ProtoBuf; @@ -42,8 +42,7 @@ impl CellDataOperation for RichTextTypeOption { || type_option_cell_data.is_multi_select() || type_option_cell_data.is_number() { - decode_cell_data(data, field_meta, &type_option_cell_data.field_type) - .unwrap_or_else(|| DecodedCellData::default()) + decode_cell_data(data, field_meta, &type_option_cell_data.field_type).unwrap_or_default() } else { DecodedCellData::from_content(type_option_cell_data.data) } @@ -52,7 +51,7 @@ impl CellDataOperation for RichTextTypeOption { } } - fn apply_changeset>( + fn apply_changeset>( &self, changeset: T, _cell_meta: Option, @@ -81,7 +80,7 @@ mod tests { let date_time_field_meta = FieldBuilder::from_field_type(&FieldType::DateTime).build(); let data = TypeOptionCellData::new("1647251762", FieldType::DateTime).json(); assert_eq!( - type_option.decode_cell_data(data, &date_time_field_meta), + type_option.decode_cell_data(data, &date_time_field_meta).content, "Mar 14,2022".to_owned() ); @@ -92,7 +91,9 @@ mod tests { let single_select_field_meta = FieldBuilder::new(single_select).build(); let cell_data = TypeOptionCellData::new(&done_option_id, FieldType::SingleSelect).json(); assert_eq!( - type_option.decode_cell_data(cell_data, &single_select_field_meta), + type_option + .decode_cell_data(cell_data, &single_select_field_meta) + .content, "Done".to_owned() ); @@ -100,7 +101,7 @@ mod tests { let google_option = SelectOption::new("Google"); let facebook_option = SelectOption::new("Facebook"); let ids = vec![google_option.id.clone(), facebook_option.id.clone()].join(SELECTION_IDS_SEPARATOR); - let cell_data_changeset = SelectOptionCellChangeset::from_insert(&ids).cell_data(); + let cell_data_changeset = SelectOptionCellContentChangeset::from_insert(&ids).to_str(); let multi_select = MultiSelectTypeOptionBuilder::default() .option(google_option) .option(facebook_option); @@ -108,7 +109,9 @@ mod tests { let multi_type_option = MultiSelectTypeOption::from(&multi_select_field_meta); let cell_data = multi_type_option.apply_changeset(cell_data_changeset, None).unwrap(); assert_eq!( - type_option.decode_cell_data(cell_data, &multi_select_field_meta), + type_option + .decode_cell_data(cell_data, &multi_select_field_meta) + .content, "Google,Facebook".to_owned() ); @@ -117,7 +120,7 @@ mod tests { let number_field_meta = FieldBuilder::new(number).build(); let data = TypeOptionCellData::new("18443", FieldType::Number).json(); assert_eq!( - type_option.decode_cell_data(data, &number_field_meta), + type_option.decode_cell_data(data, &number_field_meta).content, "$18,443".to_owned() ); } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_data.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_data.rs deleted file mode 100644 index 8b13789179..0000000000 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/type_option_data.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/util.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/util.rs new file mode 100644 index 0000000000..be141a41bf --- /dev/null +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/util.rs @@ -0,0 +1,10 @@ +use crate::services::row::TypeOptionCellData; +use flowy_grid_data_model::entities::CellMeta; +use std::str::FromStr; + +pub fn get_cell_data(cell_meta: &CellMeta) -> String { + match TypeOptionCellData::from_str(&cell_meta.data) { + Ok(type_option) => type_option.data, + Err(_) => String::new(), + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index ab41542174..c07b81ac58 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -117,7 +117,7 @@ impl ClientGridEditor { Ok(grid.update_field_meta(changeset, deserializer)?) }) .await?; - let _ = self.notify_did_update_grid_field(&field_id).await?; + let _ = self.notify_did_update_grid_field(field_id).await?; Ok(()) } @@ -337,30 +337,45 @@ impl ClientGridEditor { } #[tracing::instrument(level = "trace", skip_all, err)] - pub async fn update_cell(&self, mut changeset: CellChangeset) -> FlowyResult<()> { - if changeset.data.as_ref().is_none() { + pub async fn update_cell(&self, mut cell_changeset: CellChangeset) -> FlowyResult<()> { + if cell_changeset.cell_content_changeset.as_ref().is_none() { return Ok(()); } - let cell_data_changeset = changeset.data.unwrap(); - let cell_meta = self.get_cell_meta(&changeset.row_id, &changeset.field_id).await?; - tracing::trace!( - "field changeset: id:{} / value:{}", - &changeset.field_id, - cell_data_changeset - ); - match self.grid_pad.read().await.get_field_meta(&changeset.field_id) { + let CellChangeset { + grid_id, + row_id, + field_id, + mut cell_content_changeset, + } = cell_changeset; + + match self.grid_pad.read().await.get_field_meta(&field_id) { None => { - let msg = format!("Field not found with id: {}", &changeset.field_id); + let msg = format!("Field not found with id: {}", &field_id); Err(FlowyError::internal().context(msg)) } Some((_, field_meta)) => { + tracing::trace!("field changeset: id:{} / value:{:?}", &field_id, cell_content_changeset); + + let cell_meta = self.get_cell_meta(&row_id, &field_id).await?; // Update the changeset.data property with the return value. - changeset.data = Some(apply_cell_data_changeset(cell_data_changeset, cell_meta, field_meta)?); + cell_content_changeset = Some(apply_cell_data_changeset( + cell_content_changeset.unwrap(), + cell_meta, + field_meta, + )?); let field_metas = self.get_field_metas::(None).await?; + let cell_changeset = CellChangeset { + grid_id, + row_id, + field_id, + cell_content_changeset, + }; let _ = self .block_meta_manager - .update_cell(changeset, |row_meta| make_row_from_row_meta(&field_metas, row_meta)) + .update_cell(cell_changeset, |row_meta| { + make_row_from_row_meta(&field_metas, row_meta) + }) .await?; Ok(()) } diff --git a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs index 99ff127b32..5f6dbc74fd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/cell_data_operation.rs @@ -1,15 +1,12 @@ use crate::services::field::*; -use std::borrow::Cow; -use std::fmt::Formatter; -use std::sync::Arc; - use flowy_error::FlowyError; use flowy_grid_data_model::entities::{CellMeta, FieldMeta, FieldType}; use serde::{Deserialize, Serialize}; +use std::fmt::Formatter; pub trait CellDataOperation { fn decode_cell_data(&self, data: String, field_meta: &FieldMeta) -> DecodedCellData; - fn apply_changeset>( + fn apply_changeset>( &self, changeset: T, cell_meta: Option, @@ -17,22 +14,22 @@ pub trait CellDataOperation { } #[derive(Debug)] -pub struct CellDataChangeset(String); +pub struct CellContentChangeset(String); -impl std::fmt::Display for CellDataChangeset { +impl std::fmt::Display for CellContentChangeset { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", &self.0) } } -impl> std::convert::From for CellDataChangeset { +impl> std::convert::From for CellContentChangeset { fn from(s: T) -> Self { let s = s.as_ref().to_owned(); - CellDataChangeset(s) + CellContentChangeset(s) } } -impl std::ops::Deref for CellDataChangeset { +impl std::ops::Deref for CellContentChangeset { type Target = str; fn deref(&self) -> &Self::Target { @@ -94,7 +91,7 @@ impl TypeOptionCellData { /// The changeset will be deserialized into specific data base on the FieldType. /// For example, it's String on FieldType::RichText, and SelectOptionChangeset on FieldType::SingleSelect -pub fn apply_cell_data_changeset>( +pub fn apply_cell_data_changeset>( changeset: T, cell_meta: Option, field_meta: &FieldMeta, @@ -109,29 +106,6 @@ pub fn apply_cell_data_changeset>( } } -#[derive(Default)] -pub struct DecodedCellData { - raw: String, - content: String, -} - -impl DecodedCellData { - pub fn from_content(content: String) -> Self { - Self { - raw: content.clone(), - content, - } - } - - pub fn new(raw: String, content: String) -> Self { - Self { raw, content } - } - - pub fn split(self) -> (String, String) { - (self.raw, self.content) - } -} - pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &FieldType) -> Option { let s = match field_type { FieldType::RichText => field_meta @@ -159,3 +133,26 @@ pub fn decode_cell_data(data: String, field_meta: &FieldMeta, field_type: &Field ); Some(s) } + +#[derive(Default)] +pub struct DecodedCellData { + pub raw: String, + pub content: String, +} + +impl DecodedCellData { + pub fn from_content(content: String) -> Self { + Self { + raw: content.clone(), + content, + } + } + + pub fn new(raw: String, content: String) -> Self { + Self { raw, content } + } + + pub fn split(self) -> (String, String) { + (self.raw, self.content) + } +} diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs index fa5298fd39..a354232a95 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_builder.rs @@ -1,4 +1,4 @@ -use crate::services::field::SelectOptionCellChangeset; +use crate::services::field::SelectOptionCellContentChangeset; use crate::services::row::apply_cell_data_changeset; use flowy_error::{FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{gen_row_id, CellMeta, FieldMeta, RowMeta, DEFAULT_ROW_HEIGHT}; @@ -52,7 +52,7 @@ impl<'a> CreateRowMetaBuilder<'a> { Err(FlowyError::internal().context(msg)) } Some(field_meta) => { - let cell_data = SelectOptionCellChangeset::from_insert(&data).cell_data(); + let cell_data = SelectOptionCellContentChangeset::from_insert(&data).to_str(); let data = apply_cell_data_changeset(&cell_data, None, field_meta)?; let cell = CellMeta::new(data); self.payload.cell_by_field_id.insert(field_id.to_owned(), cell); diff --git a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs index 543e743a51..edcb102595 100644 --- a/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs +++ b/frontend/rust-lib/flowy-grid/src/services/row/row_loader.rs @@ -31,14 +31,14 @@ pub fn make_cell_by_field_id( cell_meta: CellMeta, ) -> Option<(String, Cell)> { let field_meta = field_map.get(&field_id)?; - let (raw, content) = decode_cell_data(cell_meta.data.clone(), field_meta, &field_meta.field_type)?.split(); + let (raw, content) = decode_cell_data(cell_meta.data, field_meta, &field_meta.field_type)?.split(); let cell = Cell::new(&field_id, content, raw); Some((field_id, cell)) } pub fn make_cell(field_id: &str, field_meta: &FieldMeta, row_meta: &RowMeta) -> Option { let cell_meta = row_meta.cells.get(field_id)?.clone(); - let (raw, content) = decode_cell_data(cell_meta.data.clone(), field_meta, &field_meta.field_type)?.split(); + let (raw, content) = decode_cell_data(cell_meta.data, field_meta, &field_meta.field_type)?.split(); Some(Cell::new(field_id, content, raw)) } diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs index 9ac18aed7f..9f8ee392d5 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs @@ -2,7 +2,8 @@ use crate::grid::script::EditorScript::*; use crate::grid::script::*; use chrono::NaiveDateTime; use flowy_grid::services::field::{ - MultiSelectTypeOption, SelectOption, SelectOptionCellChangeset, SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, + MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset, SingleSelectTypeOption, + SELECTION_IDS_SEPARATOR, }; use flowy_grid::services::row::{decode_cell_data, CreateRowMetaBuilder}; use flowy_grid_data_model::entities::{ @@ -317,11 +318,11 @@ async fn grid_cell_update() { FieldType::DateTime => "123".to_string(), FieldType::SingleSelect => { let type_option = SingleSelectTypeOption::from(field_meta); - SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).cell_data() + SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() } FieldType::MultiSelect => { let type_option = MultiSelectTypeOption::from(field_meta); - SelectOptionCellChangeset::from_insert(&type_option.options.first().unwrap().id).cell_data() + SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() } FieldType::Checkbox => "1".to_string(), }; @@ -331,7 +332,7 @@ async fn grid_cell_update() { grid_id: block_id.to_string(), row_id: row_meta.id.clone(), field_id: field_meta.id.clone(), - data: Some(data), + cell_content_changeset: Some(data), }, is_err: false, }); @@ -342,8 +343,8 @@ async fn grid_cell_update() { FieldType::RichText => ("1".to_string().repeat(10001), true), FieldType::Number => ("abc".to_string(), true), FieldType::DateTime => ("abc".to_string(), true), - FieldType::SingleSelect => (SelectOptionCellChangeset::from_insert("abc").cell_data(), false), - FieldType::MultiSelect => (SelectOptionCellChangeset::from_insert("abc").cell_data(), false), + FieldType::SingleSelect => (SelectOptionCellContentChangeset::from_insert("abc").to_str(), false), + FieldType::MultiSelect => (SelectOptionCellContentChangeset::from_insert("abc").to_str(), false), FieldType::Checkbox => ("2".to_string(), false), }; @@ -352,7 +353,7 @@ async fn grid_cell_update() { grid_id: block_id.to_string(), row_id: row_meta.id.clone(), field_id: field_meta.id.clone(), - data: Some(data), + cell_content_changeset: Some(data), }, is_err, }); diff --git a/shared-lib/flowy-grid-data-model/src/entities/grid.rs b/shared-lib/flowy-grid-data-model/src/entities/grid.rs index 42c280aec5..0dae40658c 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -902,7 +902,7 @@ pub struct CellChangeset { pub field_id: String, #[pb(index = 4, one_of)] - pub data: Option, + pub cell_content_changeset: Option, } impl std::convert::From for RowMetaChangeset { @@ -910,7 +910,7 @@ impl std::convert::From for RowMetaChangeset { let mut cell_by_field_id = HashMap::with_capacity(1); let field_id = changeset.field_id; let cell_meta = CellMeta { - data: changeset.data.unwrap_or_else(|| "".to_owned()), + data: changeset.cell_content_changeset.unwrap_or_else(|| "".to_owned()), }; cell_by_field_id.insert(field_id, cell_meta); diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs index 8391c13453..614d0e8b21 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/protobuf/model/grid.rs @@ -7803,7 +7803,7 @@ pub struct CellChangeset { pub row_id: ::std::string::String, pub field_id: ::std::string::String, // message oneof groups - pub one_of_data: ::std::option::Option, + pub one_of_cell_content_changeset: ::std::option::Option, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -7816,8 +7816,8 @@ impl<'a> ::std::default::Default for &'a CellChangeset { } #[derive(Clone,PartialEq,Debug)] -pub enum CellChangeset_oneof_one_of_data { - data(::std::string::String), +pub enum CellChangeset_oneof_one_of_cell_content_changeset { + cell_content_changeset(::std::string::String), } impl CellChangeset { @@ -7903,48 +7903,48 @@ impl CellChangeset { ::std::mem::replace(&mut self.field_id, ::std::string::String::new()) } - // string data = 4; + // string cell_content_changeset = 4; - pub fn get_data(&self) -> &str { - match self.one_of_data { - ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(ref v)) => v, + pub fn get_cell_content_changeset(&self) -> &str { + match self.one_of_cell_content_changeset { + ::std::option::Option::Some(CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(ref v)) => v, _ => "", } } - pub fn clear_data(&mut self) { - self.one_of_data = ::std::option::Option::None; + pub fn clear_cell_content_changeset(&mut self) { + self.one_of_cell_content_changeset = ::std::option::Option::None; } - pub fn has_data(&self) -> bool { - match self.one_of_data { - ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(..)) => true, + pub fn has_cell_content_changeset(&self) -> bool { + match self.one_of_cell_content_changeset { + ::std::option::Option::Some(CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(..)) => true, _ => false, } } // Param is passed by value, moved - pub fn set_data(&mut self, v: ::std::string::String) { - self.one_of_data = ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(v)) + pub fn set_cell_content_changeset(&mut self, v: ::std::string::String) { + self.one_of_cell_content_changeset = ::std::option::Option::Some(CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(v)) } // Mutable pointer to the field. - pub fn mut_data(&mut self) -> &mut ::std::string::String { - if let ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(_)) = self.one_of_data { + pub fn mut_cell_content_changeset(&mut self) -> &mut ::std::string::String { + if let ::std::option::Option::Some(CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(_)) = self.one_of_cell_content_changeset { } else { - self.one_of_data = ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(::std::string::String::new())); + self.one_of_cell_content_changeset = ::std::option::Option::Some(CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(::std::string::String::new())); } - match self.one_of_data { - ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(ref mut v)) => v, + match self.one_of_cell_content_changeset { + ::std::option::Option::Some(CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(ref mut v)) => v, _ => panic!(), } } // Take field - pub fn take_data(&mut self) -> ::std::string::String { - if self.has_data() { - match self.one_of_data.take() { - ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(v)) => v, + pub fn take_cell_content_changeset(&mut self) -> ::std::string::String { + if self.has_cell_content_changeset() { + match self.one_of_cell_content_changeset.take() { + ::std::option::Option::Some(CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(v)) => v, _ => panic!(), } } else { @@ -7975,7 +7975,7 @@ impl ::protobuf::Message for CellChangeset { if wire_type != ::protobuf::wire_format::WireTypeLengthDelimited { return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); } - self.one_of_data = ::std::option::Option::Some(CellChangeset_oneof_one_of_data::data(is.read_string()?)); + self.one_of_cell_content_changeset = ::std::option::Option::Some(CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(is.read_string()?)); }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; @@ -7998,9 +7998,9 @@ impl ::protobuf::Message for CellChangeset { if !self.field_id.is_empty() { my_size += ::protobuf::rt::string_size(3, &self.field_id); } - if let ::std::option::Option::Some(ref v) = self.one_of_data { + if let ::std::option::Option::Some(ref v) = self.one_of_cell_content_changeset { match v { - &CellChangeset_oneof_one_of_data::data(ref v) => { + &CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(ref v) => { my_size += ::protobuf::rt::string_size(4, &v); }, }; @@ -8020,9 +8020,9 @@ impl ::protobuf::Message for CellChangeset { if !self.field_id.is_empty() { os.write_string(3, &self.field_id)?; } - if let ::std::option::Option::Some(ref v) = self.one_of_data { + if let ::std::option::Option::Some(ref v) = self.one_of_cell_content_changeset { match v { - &CellChangeset_oneof_one_of_data::data(ref v) => { + &CellChangeset_oneof_one_of_cell_content_changeset::cell_content_changeset(ref v) => { os.write_string(4, v)?; }, }; @@ -8081,9 +8081,9 @@ impl ::protobuf::Message for CellChangeset { |m: &mut CellChangeset| { &mut m.field_id }, )); fields.push(::protobuf::reflect::accessor::make_singular_string_accessor::<_>( - "data", - CellChangeset::has_data, - CellChangeset::get_data, + "cell_content_changeset", + CellChangeset::has_cell_content_changeset, + CellChangeset::get_cell_content_changeset, )); ::protobuf::reflect::MessageDescriptor::new_pb_name::( "CellChangeset", @@ -8104,7 +8104,7 @@ impl ::protobuf::Clear for CellChangeset { self.grid_id.clear(); self.row_id.clear(); self.field_id.clear(); - self.one_of_data = ::std::option::Option::None; + self.one_of_cell_content_changeset = ::std::option::Option::None; self.unknown_fields.clear(); } } @@ -8321,14 +8321,15 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x01(\tR\x06gridId\x12\x17\n\x07item_id\x18\x02\x20\x01(\tR\x06itemId\ \x12\x1d\n\nfrom_index\x18\x03\x20\x01(\x05R\tfromIndex\x12\x19\n\x08to_\ index\x18\x04\x20\x01(\x05R\x07toIndex\x12\x1d\n\x02ty\x18\x05\x20\x01(\ - \x0e2\r.MoveItemTypeR\x02ty\"\x7f\n\rCellChangeset\x12\x17\n\x07grid_id\ - \x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\tR\ - \x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x12\x14\n\ - \x04data\x18\x04\x20\x01(\tH\0R\x04dataB\r\n\x0bone_of_data**\n\x0cMoveI\ - temType\x12\r\n\tMoveField\x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tField\ - Type\x12\x0c\n\x08RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08\ - DateTime\x10\x02\x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSel\ - ect\x10\x04\x12\x0c\n\x08Checkbox\x10\x05b\x06proto3\ + \x0e2\r.MoveItemTypeR\x02ty\"\xb3\x01\n\rCellChangeset\x12\x17\n\x07grid\ + _id\x18\x01\x20\x01(\tR\x06gridId\x12\x15\n\x06row_id\x18\x02\x20\x01(\t\ + R\x05rowId\x12\x19\n\x08field_id\x18\x03\x20\x01(\tR\x07fieldId\x126\n\ + \x16cell_content_changeset\x18\x04\x20\x01(\tH\0R\x14cellContentChangese\ + tB\x1f\n\x1done_of_cell_content_changeset**\n\x0cMoveItemType\x12\r\n\tM\ + oveField\x10\0\x12\x0b\n\x07MoveRow\x10\x01*d\n\tFieldType\x12\x0c\n\x08\ + RichText\x10\0\x12\n\n\x06Number\x10\x01\x12\x0c\n\x08DateTime\x10\x02\ + \x12\x10\n\x0cSingleSelect\x10\x03\x12\x0f\n\x0bMultiSelect\x10\x04\x12\ + \x0c\n\x08Checkbox\x10\x05b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto index 4295dee2bb..5913b0ca0e 100644 --- a/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto +++ b/shared-lib/flowy-grid-data-model/src/protobuf/proto/grid.proto @@ -153,7 +153,7 @@ message CellChangeset { string grid_id = 1; string row_id = 2; string field_id = 3; - oneof one_of_data { string data = 4; }; + oneof one_of_cell_content_changeset { string cell_content_changeset = 4; }; } enum MoveItemType { MoveField = 0; diff --git a/shared-lib/flowy-user-data-model/src/parser/user_email.rs b/shared-lib/flowy-user-data-model/src/parser/user_email.rs index 9b254f2957..e1b276a46b 100644 --- a/shared-lib/flowy-user-data-model/src/parser/user_email.rs +++ b/shared-lib/flowy-user-data-model/src/parser/user_email.rs @@ -56,6 +56,7 @@ mod tests { impl quickcheck::Arbitrary for ValidEmailFixture { fn arbitrary(g: &mut quickcheck::Gen) -> Self { let mut rand_slice: [u8; 32] = [0; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { rand_slice[i] = u8::arbitrary(g); } From 6fb163b29656068f8560c47056e154b72a399732 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 11 May 2022 20:38:07 +0800 Subject: [PATCH 08/14] refactor: customize cell data persistence --- .../app_flowy/lib/startup/deps_resolver.dart | 8 +- .../application/grid/cell/cell_service.dart | 379 ------------------ .../grid/cell/cell_service/cell_service.dart | 73 ++++ .../cell/cell_service/context_builder.dart | 182 +++++++++ .../grid/cell/cell_service/data_cache.dart | 109 +++++ .../grid/cell/cell_service/data_loader.dart | 83 ++++ .../cell/cell_service/data_persistence.dart | 67 ++++ .../grid/cell/checkbox_cell_bloc.dart | 4 +- .../application/grid/cell/date_cal_bloc.dart | 7 +- .../application/grid/cell/date_cell_bloc.dart | 15 +- .../grid/cell/number_cell_bloc.dart | 6 +- .../grid/cell/select_option_service.dart | 25 +- .../grid/cell/selection_cell_bloc.dart | 2 +- .../grid/cell/selection_editor_bloc.dart | 2 +- .../application/grid/cell/text_cell_bloc.dart | 6 +- .../workspace/application/grid/grid_bloc.dart | 2 +- .../application/grid/grid_service.dart | 2 +- .../workspace/application/grid/prelude.dart | 2 +- .../application/grid/row/row_bloc.dart | 2 +- .../application/grid/row/row_detail_bloc.dart | 2 +- .../application/grid/row/row_service.dart | 2 +- .../grid/src/widgets/cell/cell_builder.dart | 2 +- .../src/widgets/cell/date_cell/calendar.dart | 10 +- .../cell/selection_cell/selection_editor.dart | 2 +- .../grid/src/widgets/row/row_detail.dart | 2 +- .../flowy_sdk/lib/dispatch/dispatch.dart | 1 + .../field/type_options/date_type_option.rs | 48 ++- 27 files changed, 594 insertions(+), 451 deletions(-) delete mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart create mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart create mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart create mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart create mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart create mode 100644 frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 976665c8cb..8bc5d4dd41 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -164,7 +164,7 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => TextCellBloc( cellContext: context, ), @@ -176,19 +176,19 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => NumberCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (context, _) => DateCellBloc( cellContext: context, ), ); - getIt.registerFactoryParam( + getIt.registerFactoryParam( (cellData, _) => CheckboxCellBloc( service: CellService(), cellContext: cellData, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart deleted file mode 100644 index fc8bb001e4..0000000000 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart +++ /dev/null @@ -1,379 +0,0 @@ -import 'dart:async'; -import 'dart:collection'; - -import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; -import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; -import 'package:dartz/dartz.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flowy_sdk/dispatch/dispatch.dart'; -import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; -import 'package:flutter/foundation.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; - -part 'cell_service.freezed.dart'; - -typedef GridDefaultCellContext = GridCellContext; -typedef GridSelectOptionCellContext = GridCellContext; - -class GridCellContextBuilder { - final GridCellCache _cellCache; - final GridCell _gridCell; - GridCellContextBuilder({ - required GridCellCache cellCache, - required GridCell gridCell, - }) : _cellCache = cellCache, - _gridCell = gridCell; - - GridCellContext build() { - switch (_gridCell.field.fieldType) { - case FieldType.Checkbox: - case FieldType.DateTime: - case FieldType.Number: - return GridDefaultCellContext( - gridCell: _gridCell, - cellCache: _cellCache, - cellDataLoader: DefaultCellDataLoader(gridCell: _gridCell, reloadOnCellChanged: true), - ); - case FieldType.RichText: - return GridDefaultCellContext( - gridCell: _gridCell, - cellCache: _cellCache, - cellDataLoader: DefaultCellDataLoader(gridCell: _gridCell), - ); - case FieldType.MultiSelect: - case FieldType.SingleSelect: - return GridSelectOptionCellContext( - gridCell: _gridCell, - cellCache: _cellCache, - cellDataLoader: SelectOptionCellDataLoader(gridCell: _gridCell), - ); - default: - throw UnimplementedError; - } - } -} - -// ignore: must_be_immutable -class GridCellContext extends Equatable { - final GridCell gridCell; - final GridCellCache cellCache; - final GridCellCacheKey _cacheKey; - final GridCellDataLoader cellDataLoader; - final CellService _cellService = CellService(); - final FieldService _fieldService; - - late final CellListener _cellListener; - late final ValueNotifier _cellDataNotifier; - bool isListening = false; - VoidCallback? _onFieldChangedFn; - Timer? _delayOperation; - - GridCellContext({ - required this.gridCell, - required this.cellCache, - required this.cellDataLoader, - }) : _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), - _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id); - - GridCellContext clone() { - return GridCellContext( - gridCell: gridCell, - cellDataLoader: cellDataLoader, - cellCache: cellCache, - ); - } - - String get gridId => gridCell.gridId; - - String get rowId => gridCell.rowId; - - String get cellId => gridCell.rowId + gridCell.field.id; - - String get fieldId => gridCell.field.id; - - Field get field => gridCell.field; - - FieldType get fieldType => gridCell.field.fieldType; - - VoidCallback? startListening({required void Function(T) onCellChanged}) { - if (isListening) { - Log.error("Already started. It seems like you should call clone first"); - return null; - } - - isListening = true; - _cellDataNotifier = ValueNotifier(cellCache.get(_cacheKey)); - _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); - _cellListener.start(onCellChanged: (result) { - result.fold( - (_) => _loadData(), - (err) => Log.error(err), - ); - }); - - if (cellDataLoader.reloadOnFieldChanged) { - _onFieldChangedFn = () { - _loadData(); - }; - cellCache.addListener(_cacheKey, _onFieldChangedFn!); - } - - onCellChangedFn() { - final value = _cellDataNotifier.value; - if (value is T) { - onCellChanged(value); - } - - if (cellDataLoader.reloadOnCellChanged) { - _loadData(); - } - } - - _cellDataNotifier.addListener(onCellChangedFn); - return onCellChangedFn; - } - - void removeListener(VoidCallback fn) { - _cellDataNotifier.removeListener(fn); - } - - T? getCellData() { - final data = cellCache.get(_cacheKey); - if (data == null) { - _loadData(); - } - return data; - } - - Future, FlowyError>> getTypeOptionData() { - return _fieldService.getTypeOptionData(fieldType: fieldType); - } - - void saveCellData(String data) { - _cellService.updateCell(gridId: gridId, fieldId: field.id, rowId: rowId, data: data).then((result) { - result.fold((l) => null, (err) => Log.error(err)); - }); - } - - void _loadData() { - _delayOperation?.cancel(); - _delayOperation = Timer(const Duration(milliseconds: 10), () { - cellDataLoader.loadData().then((data) { - _cellDataNotifier.value = data; - cellCache.insert(GridCellCacheData(key: _cacheKey, object: data)); - }); - }); - } - - void dispose() { - _delayOperation?.cancel(); - - if (_onFieldChangedFn != null) { - cellCache.removeListener(_cacheKey, _onFieldChangedFn!); - _onFieldChangedFn = null; - } - } - - @override - List get props => [cellCache.get(_cacheKey) ?? "", cellId]; -} - -abstract class GridCellDataLoader { - Future loadData(); - - bool get reloadOnFieldChanged => true; - bool get reloadOnCellChanged => false; -} - -abstract class GridCellDataConfig { - bool get reloadOnFieldChanged => true; - bool get reloadOnCellChanged => false; -} - -class DefaultCellDataLoader extends GridCellDataLoader { - final CellService service = CellService(); - final GridCell gridCell; - @override - final bool reloadOnCellChanged; - - DefaultCellDataLoader({ - required this.gridCell, - this.reloadOnCellChanged = false, - }); - - @override - Future loadData() { - final fut = service.getCell( - gridId: gridCell.gridId, - fieldId: gridCell.field.id, - rowId: gridCell.rowId, - ); - return fut.then((result) { - return result.fold((data) => data, (err) { - Log.error(err); - return null; - }); - }); - } -} - -// key: rowId -typedef GridCellMap = LinkedHashMap; - -class GridCellCacheData { - GridCellCacheKey key; - dynamic object; - GridCellCacheData({ - required this.key, - required this.object, - }); -} - -class GridCellCacheKey { - final String fieldId; - final String objectId; - GridCellCacheKey({ - required this.fieldId, - required this.objectId, - }); -} - -abstract class GridCellFieldDelegate { - void onFieldChanged(void Function(String) callback); - void dispose(); -} - -class GridCellCache { - final String gridId; - final GridCellFieldDelegate fieldDelegate; - - /// fieldId: {objectId: callback} - final Map>> _listenerByFieldId = {}; - - /// fieldId: {cacheKey: cacheData} - final Map> _cellDataByFieldId = {}; - GridCellCache({ - required this.gridId, - required this.fieldDelegate, - }) { - fieldDelegate.onFieldChanged((fieldId) { - _cellDataByFieldId.remove(fieldId); - final map = _listenerByFieldId[fieldId]; - if (map != null) { - for (final callbacks in map.values) { - for (final callback in callbacks) { - callback(); - } - } - } - }); - } - - void addListener(GridCellCacheKey cacheKey, VoidCallback callback) { - var map = _listenerByFieldId[cacheKey.fieldId]; - if (map == null) { - _listenerByFieldId[cacheKey.fieldId] = {}; - map = _listenerByFieldId[cacheKey.fieldId]; - map![cacheKey.objectId] = [callback]; - } else { - var objects = map[cacheKey.objectId]; - if (objects == null) { - map[cacheKey.objectId] = [callback]; - } else { - objects.add(callback); - } - } - } - - void removeListener(GridCellCacheKey cacheKey, VoidCallback fn) { - var callbacks = _listenerByFieldId[cacheKey.fieldId]?[cacheKey.objectId]; - final index = callbacks?.indexWhere((callback) => callback == fn); - if (index != null && index != -1) { - callbacks?.removeAt(index); - } - } - - void insert(T item) { - var map = _cellDataByFieldId[item.key.fieldId]; - if (map == null) { - _cellDataByFieldId[item.key.fieldId] = {}; - map = _cellDataByFieldId[item.key.fieldId]; - } - - map![item.key.objectId] = item.object; - } - - T? get(GridCellCacheKey key) { - final map = _cellDataByFieldId[key.fieldId]; - if (map == null) { - return null; - } else { - final object = map[key.objectId]; - if (object is T) { - return object; - } else { - if (object != null) { - Log.error("Cache data type does not match the cache data type"); - } - - return null; - } - } - } - - Future dispose() async { - fieldDelegate.dispose(); - } -} - -class CellService { - CellService(); - - Future> updateCell({ - required String gridId, - required String fieldId, - required String rowId, - required String data, - }) { - final payload = CellChangeset.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId - ..cellContentChangeset = data; - return GridEventUpdateCell(payload).send(); - } - - Future> getCell({ - required String gridId, - required String fieldId, - required String rowId, - }) { - final payload = CellIdentifierPayload.create() - ..gridId = gridId - ..fieldId = fieldId - ..rowId = rowId; - return GridEventGetCell(payload).send(); - } -} - -@freezed -class GridCell with _$GridCell { - const factory GridCell({ - required String gridId, - required String rowId, - required Field field, - Cell? cell, - }) = _GridCell; - - // ignore: unused_element - const GridCell._(); - - String cellId() { - return rowId + field.id + "${field.fieldType}"; - } -} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart new file mode 100644 index 0000000000..07be14efa2 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/cell_service.dart @@ -0,0 +1,73 @@ +import 'dart:async'; +import 'dart:collection'; + +import 'package:dartz/dartz.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter/foundation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; + +import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart'; +import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; + +part 'cell_service.freezed.dart'; +part 'data_loader.dart'; +part 'context_builder.dart'; +part 'data_cache.dart'; +part 'data_persistence.dart'; + +// key: rowId + +class CellService { + CellService(); + + Future> updateCell({ + required String gridId, + required String fieldId, + required String rowId, + required String data, + }) { + final payload = CellChangeset.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId + ..cellContentChangeset = data; + return GridEventUpdateCell(payload).send(); + } + + Future> getCell({ + required String gridId, + required String fieldId, + required String rowId, + }) { + final payload = CellIdentifierPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..rowId = rowId; + return GridEventGetCell(payload).send(); + } +} + +@freezed +class GridCell with _$GridCell { + const factory GridCell({ + required String gridId, + required String rowId, + required Field field, + Cell? cell, + }) = _GridCell; + + // ignore: unused_element + const GridCell._(); + + String cellId() { + return rowId + field.id + "${field.fieldType}"; + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart new file mode 100644 index 0000000000..ec2f498275 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart @@ -0,0 +1,182 @@ +part of 'cell_service.dart'; + +typedef GridCellContext = _GridCellContext; +typedef GridSelectOptionCellContext = _GridCellContext; +typedef GridDateCellContext = _GridCellContext; + +class GridCellContextBuilder { + final GridCellCache _cellCache; + final GridCell _gridCell; + GridCellContextBuilder({ + required GridCellCache cellCache, + required GridCell gridCell, + }) : _cellCache = cellCache, + _gridCell = gridCell; + + _GridCellContext build() { + switch (_gridCell.field.fieldType) { + case FieldType.Checkbox: + return GridCellContext( + gridCell: _gridCell, + cellCache: _cellCache, + cellDataLoader: CellDataLoader(gridCell: _gridCell), + cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + ); + case FieldType.DateTime: + return GridDateCellContext( + gridCell: _gridCell, + cellCache: _cellCache, + cellDataLoader: CellDataLoader(gridCell: _gridCell), + cellDataPersistence: NumberCellDataPersistence(gridCell: _gridCell), + ); + case FieldType.Number: + return GridCellContext( + gridCell: _gridCell, + cellCache: _cellCache, + cellDataLoader: CellDataLoader(gridCell: _gridCell, reloadOnCellChanged: true), + cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + ); + case FieldType.RichText: + return GridCellContext( + gridCell: _gridCell, + cellCache: _cellCache, + cellDataLoader: CellDataLoader(gridCell: _gridCell), + cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + ); + case FieldType.MultiSelect: + case FieldType.SingleSelect: + return GridSelectOptionCellContext( + gridCell: _gridCell, + cellCache: _cellCache, + cellDataLoader: SelectOptionCellDataLoader(gridCell: _gridCell), + cellDataPersistence: CellDataPersistence(gridCell: _gridCell), + ); + default: + throw UnimplementedError; + } + } +} + +// ignore: must_be_immutable +class _GridCellContext extends Equatable { + final GridCell gridCell; + final GridCellCache cellCache; + final GridCellCacheKey _cacheKey; + final _GridCellDataLoader cellDataLoader; + final _GridCellDataPersistence cellDataPersistence; + final FieldService _fieldService; + + late final CellListener _cellListener; + late final ValueNotifier _cellDataNotifier; + bool isListening = false; + VoidCallback? _onFieldChangedFn; + Timer? _delayOperation; + + _GridCellContext({ + required this.gridCell, + required this.cellCache, + required this.cellDataLoader, + required this.cellDataPersistence, + }) : _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), + _cacheKey = GridCellCacheKey(objectId: gridCell.rowId, fieldId: gridCell.field.id); + + _GridCellContext clone() { + return _GridCellContext( + gridCell: gridCell, + cellDataLoader: cellDataLoader, + cellCache: cellCache, + cellDataPersistence: cellDataPersistence); + } + + String get gridId => gridCell.gridId; + + String get rowId => gridCell.rowId; + + String get cellId => gridCell.rowId + gridCell.field.id; + + String get fieldId => gridCell.field.id; + + Field get field => gridCell.field; + + FieldType get fieldType => gridCell.field.fieldType; + + VoidCallback? startListening({required void Function(T) onCellChanged}) { + if (isListening) { + Log.error("Already started. It seems like you should call clone first"); + return null; + } + + isListening = true; + _cellDataNotifier = ValueNotifier(cellCache.get(_cacheKey)); + _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); + _cellListener.start(onCellChanged: (result) { + result.fold( + (_) => _loadData(), + (err) => Log.error(err), + ); + }); + + if (cellDataLoader.config.reloadOnFieldChanged) { + _onFieldChangedFn = () { + _loadData(); + }; + cellCache.addListener(_cacheKey, _onFieldChangedFn!); + } + + onCellChangedFn() { + final value = _cellDataNotifier.value; + if (value is T) { + onCellChanged(value); + } + + if (cellDataLoader.config.reloadOnCellChanged) { + _loadData(); + } + } + + _cellDataNotifier.addListener(onCellChangedFn); + return onCellChangedFn; + } + + void removeListener(VoidCallback fn) { + _cellDataNotifier.removeListener(fn); + } + + T? getCellData() { + final data = cellCache.get(_cacheKey); + if (data == null) { + _loadData(); + } + return data; + } + + Future, FlowyError>> getTypeOptionData() { + return _fieldService.getTypeOptionData(fieldType: fieldType); + } + + void saveCellData(D data) { + cellDataPersistence.save(data); + } + + void _loadData() { + _delayOperation?.cancel(); + _delayOperation = Timer(const Duration(milliseconds: 10), () { + cellDataLoader.loadData().then((data) { + _cellDataNotifier.value = data; + cellCache.insert(GridCellCacheData(key: _cacheKey, object: data)); + }); + }); + } + + void dispose() { + _delayOperation?.cancel(); + + if (_onFieldChangedFn != null) { + cellCache.removeListener(_cacheKey, _onFieldChangedFn!); + _onFieldChangedFn = null; + } + } + + @override + List get props => [cellCache.get(_cacheKey) ?? "", cellId]; +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart new file mode 100644 index 0000000000..71adf0d059 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart @@ -0,0 +1,109 @@ +part of 'cell_service.dart'; + +typedef GridCellMap = LinkedHashMap; + +class GridCellCacheData { + GridCellCacheKey key; + dynamic object; + GridCellCacheData({ + required this.key, + required this.object, + }); +} + +class GridCellCacheKey { + final String fieldId; + final String objectId; + GridCellCacheKey({ + required this.fieldId, + required this.objectId, + }); +} + +abstract class GridCellFieldDelegate { + void onFieldChanged(void Function(String) callback); + void dispose(); +} + +class GridCellCache { + final String gridId; + final GridCellFieldDelegate fieldDelegate; + + /// fieldId: {objectId: callback} + final Map>> _listenerByFieldId = {}; + + /// fieldId: {cacheKey: cacheData} + final Map> _cellDataByFieldId = {}; + GridCellCache({ + required this.gridId, + required this.fieldDelegate, + }) { + fieldDelegate.onFieldChanged((fieldId) { + _cellDataByFieldId.remove(fieldId); + final map = _listenerByFieldId[fieldId]; + if (map != null) { + for (final callbacks in map.values) { + for (final callback in callbacks) { + callback(); + } + } + } + }); + } + + void addListener(GridCellCacheKey cacheKey, VoidCallback callback) { + var map = _listenerByFieldId[cacheKey.fieldId]; + if (map == null) { + _listenerByFieldId[cacheKey.fieldId] = {}; + map = _listenerByFieldId[cacheKey.fieldId]; + map![cacheKey.objectId] = [callback]; + } else { + var objects = map[cacheKey.objectId]; + if (objects == null) { + map[cacheKey.objectId] = [callback]; + } else { + objects.add(callback); + } + } + } + + void removeListener(GridCellCacheKey cacheKey, VoidCallback fn) { + var callbacks = _listenerByFieldId[cacheKey.fieldId]?[cacheKey.objectId]; + final index = callbacks?.indexWhere((callback) => callback == fn); + if (index != null && index != -1) { + callbacks?.removeAt(index); + } + } + + void insert(T item) { + var map = _cellDataByFieldId[item.key.fieldId]; + if (map == null) { + _cellDataByFieldId[item.key.fieldId] = {}; + map = _cellDataByFieldId[item.key.fieldId]; + } + + map![item.key.objectId] = item.object; + } + + T? get(GridCellCacheKey key) { + final map = _cellDataByFieldId[key.fieldId]; + if (map == null) { + return null; + } else { + final object = map[key.objectId]; + if (object is T) { + return object; + } else { + if (object != null) { + Log.error("Cache data type does not match the cache data type"); + } + + return null; + } + } + } + + Future dispose() async { + fieldDelegate.dispose(); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart new file mode 100644 index 0000000000..0a630deba9 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart @@ -0,0 +1,83 @@ +part of 'cell_service.dart'; + +abstract class GridCellDataConfig { + // The cell data will reload if it receives the field's change notification. + bool get reloadOnFieldChanged; + + // The cell data will reload if it receives the cell's change notification. + // For example, the number cell should be reloaded after user input the number. + // user input: 12 + // cell display: $12 + bool get reloadOnCellChanged; +} + +class DefaultCellDataConfig implements GridCellDataConfig { + @override + final bool reloadOnCellChanged; + + @override + final bool reloadOnFieldChanged; + + DefaultCellDataConfig({ + this.reloadOnCellChanged = false, + this.reloadOnFieldChanged = false, + }); +} + +abstract class _GridCellDataLoader { + Future loadData(); + + GridCellDataConfig get config; +} + +class CellDataLoader extends _GridCellDataLoader { + final CellService service = CellService(); + final GridCell gridCell; + final GridCellDataConfig _config; + + CellDataLoader({ + required this.gridCell, + bool reloadOnCellChanged = false, + }) : _config = DefaultCellDataConfig(reloadOnCellChanged: reloadOnCellChanged); + + @override + Future loadData() { + final fut = service.getCell( + gridId: gridCell.gridId, + fieldId: gridCell.field.id, + rowId: gridCell.rowId, + ); + return fut.then((result) { + return result.fold((data) => data, (err) { + Log.error(err); + return null; + }); + }); + } + + @override + GridCellDataConfig get config => _config; +} + +class SelectOptionCellDataLoader extends _GridCellDataLoader { + final SelectOptionService service; + final GridCell gridCell; + SelectOptionCellDataLoader({ + required this.gridCell, + }) : service = SelectOptionService(gridCell: gridCell); + @override + Future loadData() async { + return service.getOpitonContext().then((result) { + return result.fold( + (data) => data, + (err) { + Log.error(err); + return null; + }, + ); + }); + } + + @override + GridCellDataConfig get config => DefaultCellDataConfig(); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart new file mode 100644 index 0000000000..5aec905007 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart @@ -0,0 +1,67 @@ +part of 'cell_service.dart'; + +abstract class _GridCellDataPersistence { + void save(D data); +} + +class CellDataPersistence implements _GridCellDataPersistence { + final GridCell gridCell; + + CellDataPersistence({ + required this.gridCell, + }); + final CellService _cellService = CellService(); + + @override + void save(String data) { + _cellService + .updateCell( + gridId: gridCell.gridId, + fieldId: gridCell.field.id, + rowId: gridCell.rowId, + data: data, + ) + .then((result) { + result.fold((l) => null, (err) => Log.error(err)); + }); + } +} + +class DateCellPersistenceData { + final DateTime date; + final String? time; + DateCellPersistenceData({ + required this.date, + this.time, + }); +} + +class NumberCellDataPersistence implements _GridCellDataPersistence { + final GridCell gridCell; + NumberCellDataPersistence({ + required this.gridCell, + }); + + @override + void save(DateCellPersistenceData data) { + var payload = DateChangesetPayload.create()..cellIdentifier = _cellIdentifier(gridCell); + + final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString(); + payload.date = date; + + if (data.time != null) { + payload.time = data.time!; + } + + GridEventUpdateDateCell(payload).send().then((result) { + result.fold((l) => null, (err) => Log.error(err)); + }); + } +} + +CellIdentifierPayload _cellIdentifier(GridCell gridCell) { + return CellIdentifierPayload.create() + ..gridId = gridCell.gridId + ..fieldId = gridCell.field.id + ..rowId = gridCell.rowId; +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart index 4703502cdd..cecfaa2f04 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/checkbox_cell_bloc.dart @@ -2,12 +2,12 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; -import 'cell_service.dart'; +import 'cell_service/cell_service.dart'; part 'checkbox_cell_bloc.freezed.dart'; class CheckboxCellBloc extends Bloc { - final GridDefaultCellContext cellContext; + final GridCellContext cellContext; void Function()? _onCellChangedFn; CheckboxCellBloc({ diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 7f7d64cd26..92c9a03243 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -7,14 +7,14 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:table_calendar/table_calendar.dart'; import 'dart:async'; -import 'cell_service.dart'; +import 'cell_service/cell_service.dart'; import 'package:dartz/dartz.dart'; import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart'; part 'date_cal_bloc.freezed.dart'; class DateCalBloc extends Bloc { - final GridDefaultCellContext cellContext; + final GridDateCellContext cellContext; void Function()? _onCellChangedFn; DateCalBloc({ @@ -103,8 +103,7 @@ class DateCalBloc extends Bloc { } void _updateCellData(DateTime day) { - final data = day.millisecondsSinceEpoch ~/ 1000; - cellContext.saveCellData(data.toString()); + cellContext.saveCellData(DateCellPersistenceData(date: day)); } Future? _updateTypeOption( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index 002bc945bc..c740cf0e57 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -2,11 +2,11 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; -import 'cell_service.dart'; +import 'cell_service/cell_service.dart'; part 'date_cell_bloc.freezed.dart'; class DateCellBloc extends Bloc { - final GridDefaultCellContext cellContext; + final GridDateCellContext cellContext; void Function()? _onCellChangedFn; DateCellBloc({required this.cellContext}) : super(DateCellState.initial(cellContext)) { @@ -17,7 +17,7 @@ class DateCellBloc extends Bloc { _startListening(); }, selectDay: (_SelectDay value) { - _updateCellData(value.day); + cellContext.saveCellData(value.data); }, didReceiveCellUpdate: (_DidReceiveCellUpdate value) { emit(state.copyWith( @@ -51,17 +51,12 @@ class DateCellBloc extends Bloc { }), ); } - - void _updateCellData(DateTime day) { - final data = day.millisecondsSinceEpoch ~/ 1000; - cellContext.saveCellData(data.toString()); - } } @freezed class DateCellEvent with _$DateCellEvent { const factory DateCellEvent.initial() = _InitialCell; - const factory DateCellEvent.selectDay(DateTime day) = _SelectDay; + const factory DateCellEvent.selectDay(DateCellPersistenceData data) = _SelectDay; const factory DateCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; } @@ -73,7 +68,7 @@ class DateCellState with _$DateCellState { required Field field, }) = _DateCellState; - factory DateCellState.initial(GridCellContext context) => DateCellState( + factory DateCellState.initial(GridDateCellContext context) => DateCellState( field: context.field, content: context.getCellData()?.content ?? "", ); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart index ce801f0385..217ae4d384 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/number_cell_bloc.dart @@ -2,12 +2,12 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; -import 'cell_service.dart'; +import 'cell_service/cell_service.dart'; part 'number_cell_bloc.freezed.dart'; class NumberCellBloc extends Bloc { - final GridDefaultCellContext cellContext; + final GridCellContext cellContext; void Function()? _onCellChangedFn; NumberCellBloc({ @@ -68,7 +68,7 @@ class NumberCellState with _$NumberCellState { required String content, }) = _NumberCellState; - factory NumberCellState.initial(GridDefaultCellContext context) { + factory NumberCellState.initial(GridCellContext context) { final cell = context.getCellData(); return NumberCellState(content: cell?.content ?? ""); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart index f8795c4510..eeabdfbd67 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -1,33 +1,10 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; - import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart'; - -import 'cell_service.dart'; - -class SelectOptionCellDataLoader extends GridCellDataLoader { - final SelectOptionService service; - final GridCell gridCell; - SelectOptionCellDataLoader({ - required this.gridCell, - }) : service = SelectOptionService(gridCell: gridCell); - @override - Future loadData() async { - return service.getOpitonContext().then((result) { - return result.fold( - (data) => data, - (err) { - Log.error(err); - return null; - }, - ); - }); - } -} +import 'cell_service/cell_service.dart'; class SelectOptionService { final GridCell gridCell; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart index 2d770aaba5..794ccd3002 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_cell_bloc.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; part 'selection_cell_bloc.freezed.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index cefa0153a7..cc7af58531 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -4,7 +4,7 @@ import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'select_option_service.dart'; part 'selection_editor_bloc.freezed.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart index 41e2745fb5..0b8b8be5e0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/text_cell_bloc.dart @@ -2,12 +2,12 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; -import 'cell_service.dart'; +import 'cell_service/cell_service.dart'; part 'text_cell_bloc.freezed.dart'; class TextCellBloc extends Bloc { - final GridDefaultCellContext cellContext; + final GridCellContext cellContext; void Function()? _onCellChangedFn; TextCellBloc({ required this.cellContext, @@ -70,7 +70,7 @@ class TextCellState with _$TextCellState { required String content, }) = _TextCellState; - factory TextCellState.initial(GridDefaultCellContext context) => TextCellState( + factory TextCellState.initial(GridCellContext context) => TextCellState( content: context.getCellData()?.content ?? "", ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart index 4915d77087..7f35d50978 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -5,7 +5,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/protobuf.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'cell/cell_service.dart'; +import 'cell/cell_service/cell_service.dart'; import 'grid_service.dart'; import 'row/row_service.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index d217d2c6b7..98827e6b72 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -8,7 +8,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter/foundation.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'cell/cell_service.dart'; +import 'cell/cell_service/cell_service.dart'; import 'row/row_service.dart'; class GridService { diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 92b4d757f0..e06f5d9da8 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -21,7 +21,7 @@ export 'cell/number_cell_bloc.dart'; export 'cell/selection_cell_bloc.dart'; export 'cell/date_cell_bloc.dart'; export 'cell/checkbox_cell_bloc.dart'; -export 'cell/cell_service.dart'; +export 'cell/cell_service/cell_service.dart'; // Setting export 'setting/setting_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index 3eb0ca16f4..3d3e3486a5 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart @@ -1,5 +1,5 @@ import 'dart:collection'; -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:equatable/equatable.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; import 'package:flutter_bloc/flutter_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart index 2edd818b9b..671bbe5fa1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_detail_bloc.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart index 232b8fbf0e..07712ec845 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_service.dart @@ -1,6 +1,6 @@ import 'dart:collection'; -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/log.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index aba03ba837..7d21cb7e9a 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; import 'package:flutter/widgets.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 0efe2d4c7e..6de870f0d3 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -32,8 +32,8 @@ class CellCalendar with FlowyOverlayDelegate { Future show( BuildContext context, { - required GridDefaultCellContext cellContext, - required void Function(DateTime) onSelected, + required GridDateCellContext cellContext, + required void Function(DateCellPersistenceData) onSelected, }) async { CellCalendar.remove(context); @@ -88,10 +88,10 @@ class CellCalendar with FlowyOverlayDelegate { } class _CellCalendarWidget extends StatelessWidget { - final GridDefaultCellContext cellContext; + final GridDateCellContext cellContext; final DateTypeOption dateTypeOption; final DateTime? selectedDay; - final void Function(DateTime) onSelected; + final void Function(DateCellPersistenceData) onSelected; const _CellCalendarWidget({ required this.onSelected, @@ -113,7 +113,7 @@ class _CellCalendarWidget extends StatelessWidget { child: BlocConsumer( listener: (context, state) { if (state.selectedDay != null) { - onSelected(state.selectedDay!); + onSelected(DateCellPersistenceData(date: state.selectedDay!)); } }, listenWhen: (p, c) => p.selectedDay != c.selectedDay, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart index ef5122a4bc..6e96fccbfb 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart @@ -1,5 +1,5 @@ import 'dart:collection'; -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/cell/selection_editor_bloc.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart index 6984d1ebca..a6f86cafee 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -1,4 +1,4 @@ -import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart'; +import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/workspace/application/grid/row/row_detail_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart index db010e9f75..ca3596e48a 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart @@ -5,6 +5,7 @@ import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/dart-ffi/ffi_response.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 844d7568db..b8a858c80d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -79,14 +79,25 @@ impl CellDataOperation for DateTypeOption { fn apply_changeset>( &self, changeset: T, - _cell_meta: Option, + cell_meta: Option, ) -> Result { - let changeset = changeset.into(); - if changeset.parse::().is_err() || changeset.parse::().is_err() { - return Err(FlowyError::internal().context(format!("Parse {} failed", changeset))); - }; + let content_changeset: DateCellContentChangeset = serde_json::from_str(&changeset.into())?; + match cell_meta { + None => Ok(TypeOptionCellData::new("", self.field_type()).json()), + Some(cell_meta) => { + let s = match content_changeset.timestamp() { + None => get_cell_data(&cell_meta), + Some(timestamp) => timestamp.to_string(), + }; - Ok(TypeOptionCellData::new(changeset, self.field_type()).json()) + Ok(TypeOptionCellData::new(s, self.field_type()).json()) + + // let changeset = changeset.into(); + // if changeset.parse::().is_err() || changeset.parse::().is_err() { + // return Err(FlowyError::internal().context(format!("Parse {} failed", changeset))); + // }; + } + } } } @@ -235,6 +246,31 @@ pub struct DateCellContentChangeset { pub time: Option, } +impl DateCellContentChangeset { + pub fn timestamp(self) -> Option { + let mut timestamp = 0; + if let Some(date) = self.date { + match date.parse::() { + Ok(date_timestamp) => { + timestamp += date_timestamp; + } + Err(_) => {} + } + } else { + return None; + } + + if let Some(time) = self.time { + match time.parse::() { + Ok(time_timestamp) => timestamp += time_timestamp, + Err(_) => {} + } + } + + return Some(timestamp); + } +} + impl std::convert::From for CellChangeset { fn from(params: DateChangesetParams) -> Self { let changeset = DateCellContentChangeset { From a178546acdcd6844ac98fc06521bd299a9955810 Mon Sep 17 00:00:00 2001 From: appflowy Date: Wed, 11 May 2022 21:34:58 +0800 Subject: [PATCH 09/14] chore: save date cell data with time --- .../cell/cell_service/data_persistence.dart | 10 +-- .../application/grid/cell/date_cal_bloc.dart | 71 ++++++++----------- .../src/widgets/cell/date_cell/calendar.dart | 12 ++-- 3 files changed, 40 insertions(+), 53 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart index 5aec905007..b6a615a1b0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart @@ -27,13 +27,9 @@ class CellDataPersistence implements _GridCellDataPersistence { } } -class DateCellPersistenceData { - final DateTime date; - final String? time; - DateCellPersistenceData({ - required this.date, - this.time, - }); +@freezed +class DateCellPersistenceData with _$DateCellPersistenceData { + const factory DateCellPersistenceData({required DateTime date, String? time}) = _DateCellPersistenceData; } class NumberCellDataPersistence implements _GridCellDataPersistence { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 92c9a03243..0f980d4a98 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -9,7 +9,6 @@ import 'package:table_calendar/table_calendar.dart'; import 'dart:async'; import 'cell_service/cell_service.dart'; import 'package:dartz/dartz.dart'; -import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart'; part 'date_cal_bloc.freezed.dart'; @@ -30,9 +29,13 @@ class DateCalBloc extends Bloc { // await _loadDateTypeOption(emit); }, selectDay: (_SelectDay value) { - if (!isSameDay(state.selectedDay, value.day)) { - _updateCellData(value.day); - emit(state.copyWith(selectedDay: value.day)); + if (state.dateData != null) { + if (!isSameDay(state.dateData!.date, value.day)) { + final newDateData = state.dateData!.copyWith(date: value.day); + emit(state.copyWith(dateData: newDateData)); + } + } else { + emit(state.copyWith(dateData: DateCellPersistenceData(date: value.day))); } }, setCalFormat: (_CalendarFormat value) { @@ -52,7 +55,12 @@ class DateCalBloc extends Bloc { await _updateTypeOption(emit, timeFormat: value.timeFormat); }, setTime: (_Time value) { - // + if (state.dateData != null) { + final newDateData = state.dateData!.copyWith(time: value.time); + emit(state.copyWith(dateData: newDateData)); + } else { + emit(state.copyWith(dateData: DateCellPersistenceData(date: DateTime.now(), time: value.time))); + } }, ); }, @@ -79,33 +87,6 @@ class DateCalBloc extends Bloc { ); } - // ignore: unused_element - Future _loadDateTypeOption(Emitter emit) async { - final result = await cellContext.getTypeOptionData(); - result.fold( - (data) { - final typeOptionData = DateTypeOption.fromBuffer(data); - DateTime? selectedDay; - final cellData = cellContext.getCellData()?.data; - - if (cellData != null) { - final timestamp = $fixnum.Int64.parseInt(cellData).toInt(); - selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); - } - - emit(state.copyWith( - dateTypeOption: typeOptionData, - selectedDay: selectedDay, - )); - }, - (err) => Log.error(err), - ); - } - - void _updateCellData(DateTime day) { - cellContext.saveCellData(DateCellPersistenceData(date: day)); - } - Future? _updateTypeOption( Emitter emit, { DateFormat? dateFormat, @@ -161,19 +142,25 @@ class DateCalState with _$DateCalState { required DateTime focusedDay, required String time, required Option inputTimeError, - DateTime? selectedDay, + DateCellPersistenceData? dateData, }) = _DateCalState; factory DateCalState.initial( DateTypeOption dateTypeOption, DateTime? selectedDay, - ) => - DateCalState( - dateTypeOption: dateTypeOption, - format: CalendarFormat.month, - focusedDay: DateTime.now(), - selectedDay: selectedDay, - time: "", - inputTimeError: none(), - ); + ) { + DateCellPersistenceData? dateData; + if (selectedDay != null) { + dateData = DateCellPersistenceData(date: selectedDay); + } + + return DateCalState( + dateTypeOption: dateTypeOption, + format: CalendarFormat.month, + focusedDay: DateTime.now(), + dateData: dateData, + time: "", + inputTimeError: none(), + ); + } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 6de870f0d3..84a4760f0c 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -112,11 +112,11 @@ class _CellCalendarWidget extends StatelessWidget { )..add(const DateCalEvent.initial()), child: BlocConsumer( listener: (context, state) { - if (state.selectedDay != null) { - onSelected(DateCellPersistenceData(date: state.selectedDay!)); + if (state.dateData != null) { + onSelected(state.dateData!); } }, - listenWhen: (p, c) => p.selectedDay != c.selectedDay, + listenWhen: (p, c) => p.dateData != c.dateData, builder: (context, state) { List children = []; @@ -190,7 +190,11 @@ class _CellCalendarWidget extends StatelessWidget { ), ), selectedDayPredicate: (day) { - return isSameDay(state.selectedDay, day); + if (state.dateData != null) { + return isSameDay(state.dateData!.date, day); + } else { + return false; + } }, onDaySelected: (selectedDay, focusedDay) { context.read().add(DateCalEvent.selectDay(selectedDay)); From 4f9470b076c3b47a2f68b48ae1aa55f3ad543029 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 12 May 2022 18:07:26 +0800 Subject: [PATCH 10/14] chore: add date type option test --- .../application/grid/cell/date_cal_bloc.dart | 81 +++--- .../application/grid/cell/date_cell_bloc.dart | 22 +- .../src/widgets/cell/date_cell/calendar.dart | 70 +++++- .../src/widgets/cell/date_cell/date_cell.dart | 2 +- .../field/type_options/date_type_option.rs | 233 ++++++++++++------ .../flowy-grid/src/services/grid_editor.rs | 2 +- 6 files changed, 274 insertions(+), 136 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 0f980d4a98..8ec623f042 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -23,50 +23,61 @@ class DateCalBloc extends Bloc { }) : super(DateCalState.initial(dateTypeOption, selectedDay)) { on( (event, emit) async { - await event.map( - initial: (_Initial value) async { - _startListening(); - // await _loadDateTypeOption(emit); + await event.when( + initial: () async => _startListening(), + selectDay: (date) { + _updateDateData(emit, date: date); }, - selectDay: (_SelectDay value) { - if (state.dateData != null) { - if (!isSameDay(state.dateData!.date, value.day)) { - final newDateData = state.dateData!.copyWith(date: value.day); - emit(state.copyWith(dateData: newDateData)); - } - } else { - emit(state.copyWith(dateData: DateCellPersistenceData(date: value.day))); - } + setCalFormat: (format) { + emit(state.copyWith(format: format)); }, - setCalFormat: (_CalendarFormat value) { - emit(state.copyWith(format: value.format)); + setFocusedDay: (focusedDay) { + emit(state.copyWith(focusedDay: focusedDay)); }, - setFocusedDay: (_FocusedDay value) { - emit(state.copyWith(focusedDay: value.day)); + didReceiveCellUpdate: (value) {}, + setIncludeTime: (includeTime) async { + await _updateTypeOption(emit, includeTime: includeTime); }, - didReceiveCellUpdate: (_DidReceiveCellUpdate value) {}, - setIncludeTime: (_IncludeTime value) async { - await _updateTypeOption(emit, includeTime: value.includeTime); + setDateFormat: (dateFormat) async { + await _updateTypeOption(emit, dateFormat: dateFormat); }, - setDateFormat: (_DateFormat value) async { - await _updateTypeOption(emit, dateFormat: value.dateFormat); + setTimeFormat: (timeFormat) async { + await _updateTypeOption(emit, timeFormat: timeFormat); }, - setTimeFormat: (_TimeFormat value) async { - await _updateTypeOption(emit, timeFormat: value.timeFormat); - }, - setTime: (_Time value) { - if (state.dateData != null) { - final newDateData = state.dateData!.copyWith(time: value.time); - emit(state.copyWith(dateData: newDateData)); - } else { - emit(state.copyWith(dateData: DateCellPersistenceData(date: DateTime.now(), time: value.time))); - } + setTime: (time) { + _updateDateData(emit, time: time); }, ); }, ); } + void _updateDateData(Emitter emit, {DateTime? date, String? time}) { + state.dateData.fold( + () { + var newDateData = DateCellPersistenceData(date: date ?? DateTime.now()); + if (time != null) { + newDateData = newDateData.copyWith(time: time); + } + emit(state.copyWith(dateData: Some(newDateData))); + }, + (dateData) { + var newDateData = dateData; + if (date != null && !isSameDay(newDateData.date, date)) { + newDateData = newDateData.copyWith(date: date); + } + + if (newDateData.time != time) { + newDateData = newDateData.copyWith(time: time); + } + + if (newDateData != dateData) { + emit(state.copyWith(dateData: Some(newDateData))); + } + }, + ); + } + @override Future close() async { if (_onCellChangedFn != null) { @@ -142,16 +153,16 @@ class DateCalState with _$DateCalState { required DateTime focusedDay, required String time, required Option inputTimeError, - DateCellPersistenceData? dateData, + required Option dateData, }) = _DateCalState; factory DateCalState.initial( DateTypeOption dateTypeOption, DateTime? selectedDay, ) { - DateCellPersistenceData? dateData; + Option dateData = none(); if (selectedDay != null) { - dateData = DateCellPersistenceData(date: selectedDay); + dateData = Some(DateCellPersistenceData(date: selectedDay)); } return DateCalState( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index c740cf0e57..24ddb564cd 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -12,21 +12,11 @@ class DateCellBloc extends Bloc { DateCellBloc({required this.cellContext}) : super(DateCellState.initial(cellContext)) { on( (event, emit) async { - event.map( - initial: (_InitialCell value) { - _startListening(); - }, - selectDay: (_SelectDay value) { - cellContext.saveCellData(value.data); - }, - didReceiveCellUpdate: (_DidReceiveCellUpdate value) { - emit(state.copyWith( - content: value.cell.content, - )); - }, - didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - emit(state.copyWith(field: value.field)); - }, + event.when( + initial: () => _startListening(), + selectDate: (DateCellPersistenceData value) => cellContext.saveCellData(value), + didReceiveCellUpdate: (Cell value) => emit(state.copyWith(content: value.content)), + didReceiveFieldUpdate: (Field value) => emit(state.copyWith(field: value)), ); }, ); @@ -56,7 +46,7 @@ class DateCellBloc extends Bloc { @freezed class DateCellEvent with _$DateCellEvent { const factory DateCellEvent.initial() = _InitialCell; - const factory DateCellEvent.selectDay(DateCellPersistenceData data) = _SelectDay; + const factory DateCellEvent.selectDate(DateCellPersistenceData data) = _SelectDay; const factory DateCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 84a4760f0c..8c34105f0b 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -112,9 +112,10 @@ class _CellCalendarWidget extends StatelessWidget { )..add(const DateCalEvent.initial()), child: BlocConsumer( listener: (context, state) { - if (state.dateData != null) { - onSelected(state.dateData!); - } + state.dateData.fold( + () => null, + (dateData) => onSelected(dateData), + ); }, listenWhen: (p, c) => p.dateData != c.dateData, builder: (context, state) { @@ -127,7 +128,13 @@ class _CellCalendarWidget extends StatelessWidget { if (state.dateTypeOption.includeTime) { children.addAll([ - const _TimeTextField(), + _TimeTextField( + time: "", + errorText: state.inputTimeError.fold(() => "", (error) => error.toString()), + onEditingComplete: (text) { + context.read().add(DateCalEvent.setTime(text)); + }, + ), ]); } @@ -190,11 +197,10 @@ class _CellCalendarWidget extends StatelessWidget { ), ), selectedDayPredicate: (day) { - if (state.dateData != null) { - return isSameDay(state.dateData!.date, day); - } else { - return false; - } + return state.dateData.fold( + () => false, + (dateData) => isSameDay(dateData.date, day), + ); }, onDaySelected: (selectedDay, focusedDay) { context.read().add(DateCalEvent.selectDay(selectedDay)); @@ -241,8 +247,36 @@ class _IncludeTimeButton extends StatelessWidget { } } -class _TimeTextField extends StatelessWidget { - const _TimeTextField({Key? key}) : super(key: key); +class _TimeTextField extends StatefulWidget { + final String errorText; + final String time; + final void Function(String) onEditingComplete; + const _TimeTextField({ + Key? key, + required this.time, + required this.errorText, + required this.onEditingComplete, + }) : super(key: key); + + @override + State<_TimeTextField> createState() => _TimeTextFieldState(); +} + +class _TimeTextFieldState extends State<_TimeTextField> { + late final FocusNode _focusNode; + late final TextEditingController _controller; + + @override + void initState() { + _focusNode = FocusNode(); + _controller = TextEditingController(text: widget.time); + _focusNode.addListener(() { + if (mounted) { + widget.onEditingComplete(_controller.text); + } + }); + super.initState(); + } @override Widget build(BuildContext context) { @@ -251,15 +285,25 @@ class _TimeTextField extends StatelessWidget { padding: kMargin, child: RoundedInputField( height: 40, + focusNode: _focusNode, + controller: _controller, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), normalBorderColor: theme.shader4, errorBorderColor: theme.red, cursorColor: theme.main1, - errorText: context.read().state.inputTimeError.fold(() => "", (error) => error.toString()), - onEditingComplete: (value) => context.read().add(DateCalEvent.setTime(value)), + errorText: widget.errorText, + onEditingComplete: (value) { + widget.onEditingComplete(value); + }, ), ); } + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } } class _DateTypeOptionButton extends StatelessWidget { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart index bbf0f55ffc..1a278ce1da 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart @@ -78,7 +78,7 @@ class _DateCellState extends State { calendar.show( context, cellContext: bloc.cellContext.clone(), - onSelected: (day) => bloc.add(DateCellEvent.selectDay(day)), + onSelected: (data) => bloc.add(DateCellEvent.selectDate(data)), ); } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index b8a858c80d..01a748ea68 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -1,20 +1,18 @@ use crate::impl_type_option; +use crate::services::entities::{CellIdentifier, CellIdentifierPayload}; +use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellData, TypeOptionCellData}; use bytes::Bytes; use chrono::format::strftime::StrftimeItems; -use chrono::{Datelike, NaiveDateTime}; +use chrono::NaiveDateTime; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error::{ErrorCode, FlowyError}; +use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{ CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, }; - use serde::{Deserialize, Serialize}; +use std::ops::Add; use std::str::FromStr; - -use crate::services::entities::{CellIdentifier, CellIdentifierPayload}; -use crate::services::field::type_options::util::get_cell_data; -use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use strum_macros::EnumIter; // Date @@ -33,18 +31,45 @@ impl_type_option!(DateTypeOption, FieldType::DateTime); impl DateTypeOption { #[allow(dead_code)] - fn today_from_timestamp(&self, timestamp: i64) -> String { + fn today_desc_from_timestamp(&self, timestamp: i64) -> String { let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0); - self.today_from_native(native) + self.today_desc_from_native(native) } - fn today_from_native(&self, naive: chrono::NaiveDateTime) -> String { - let utc: chrono::DateTime = chrono::DateTime::from_utc(naive, chrono::Utc); - let local: chrono::DateTime = chrono::DateTime::from(utc); - let output = format!("{}", local.format_with_items(StrftimeItems::new(&self.fmt_str()))); + fn today_desc_from_str(&self, s: String) -> String { + match NaiveDateTime::parse_from_str(&s, &self.fmt_str()) { + Ok(native) => self.today_desc_from_native(native), + Err(_) => "".to_owned(), + } + } + + fn today_desc_from_native(&self, native: chrono::NaiveDateTime) -> String { + let utc = self.utc_date_time_from_native(native); + // let china_timezone = FixedOffset::east(8 * 3600); + // let a = utc.with_timezone(&china_timezone); + let output = format!("{}", utc.format_with_items(StrftimeItems::new(&self.fmt_str()))); output } + fn timestamp_from_str(&self, s: &str) -> FlowyResult { + match NaiveDateTime::parse_from_str(s, &self.fmt_str()) { + Ok(native) => { + let utc = self.utc_date_time_from_native(native); + Ok(utc.timestamp()) + } + Err(_) => Err(ErrorCode::InvalidData.into()), + } + } + + fn utc_date_time_from_timestamp(&self, timestamp: i64) -> chrono::DateTime { + let native = NaiveDateTime::from_timestamp(timestamp, 0); + self.utc_date_time_from_native(native) + } + + fn utc_date_time_from_native(&self, naive: chrono::NaiveDateTime) -> chrono::DateTime { + chrono::DateTime::::from_utc(naive, chrono::Utc) + } + fn fmt_str(&self) -> String { if self.include_time { format!("{} {}", self.date_format.format_str(), self.time_format.format_str()) @@ -63,14 +88,11 @@ impl CellDataOperation for DateTypeOption { let cell_data = type_option_cell_data.data; if let Ok(timestamp) = cell_data.parse::() { - let native = NaiveDateTime::from_timestamp(timestamp, 0); - return DecodedCellData::new(format!("{}", timestamp), self.today_from_native(native)); + return DecodedCellData::new(format!("{}", timestamp), self.today_desc_from_timestamp(timestamp)); } - return match NaiveDateTime::parse_from_str(&cell_data, &self.fmt_str()) { - Ok(date_time) => DecodedCellData::new(format!("{}", date_time.timestamp()), cell_data), - Err(_) => DecodedCellData::default(), - }; + let cell_content = self.today_desc_from_str(cell_data.clone()); + return DecodedCellData::new(cell_data, cell_content); } DecodedCellData::default() @@ -79,25 +101,29 @@ impl CellDataOperation for DateTypeOption { fn apply_changeset>( &self, changeset: T, - cell_meta: Option, + _cell_meta: Option, ) -> Result { let content_changeset: DateCellContentChangeset = serde_json::from_str(&changeset.into())?; - match cell_meta { - None => Ok(TypeOptionCellData::new("", self.field_type()).json()), - Some(cell_meta) => { - let s = match content_changeset.timestamp() { - None => get_cell_data(&cell_meta), - Some(timestamp) => timestamp.to_string(), - }; - - Ok(TypeOptionCellData::new(s, self.field_type()).json()) - - // let changeset = changeset.into(); - // if changeset.parse::().is_err() || changeset.parse::().is_err() { - // return Err(FlowyError::internal().context(format!("Parse {} failed", changeset))); - // }; + let cell_content = match content_changeset.date_timestamp() { + None => "".to_owned(), + Some(date_timestamp) => { + // + match (self.include_time, content_changeset.time) { + (true, Some(time)) => { + let utc = self.utc_date_time_from_timestamp(date_timestamp); + let mut date_str = format!( + "{}", + utc.format_with_items(StrftimeItems::new(self.date_format.format_str())) + ); + date_str = date_str.add(&time); + let timestamp = self.timestamp_from_str(&date_str)?; + timestamp.to_string() + } + _ => date_timestamp.to_string(), + } } - } + }; + Ok(TypeOptionCellData::new(cell_content, self.field_type()).json()) } } @@ -197,7 +223,7 @@ impl TimeFormat { // https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html pub fn format_str(&self) -> &'static str { match self { - TimeFormat::TwelveHour => "%r", + TimeFormat::TwelveHour => "%I:%M %p", TimeFormat::TwentyFourHour => "%R", } } @@ -240,37 +266,6 @@ impl TryInto for DateChangesetPayload { } } -#[derive(Clone, Serialize, Deserialize)] -pub struct DateCellContentChangeset { - pub date: Option, - pub time: Option, -} - -impl DateCellContentChangeset { - pub fn timestamp(self) -> Option { - let mut timestamp = 0; - if let Some(date) = self.date { - match date.parse::() { - Ok(date_timestamp) => { - timestamp += date_timestamp; - } - Err(_) => {} - } - } else { - return None; - } - - if let Some(time) = self.time { - match time.parse::() { - Ok(time_timestamp) => timestamp += time_timestamp, - Err(_) => {} - } - } - - return Some(timestamp); - } -} - impl std::convert::From for CellChangeset { fn from(params: DateChangesetParams) -> Self { let changeset = DateCellContentChangeset { @@ -287,10 +282,36 @@ impl std::convert::From for CellChangeset { } } +#[derive(Clone, Serialize, Deserialize)] +pub struct DateCellContentChangeset { + pub date: Option, + pub time: Option, +} + +impl DateCellContentChangeset { + pub fn date_timestamp(&self) -> Option { + if let Some(date) = &self.date { + match date.parse::() { + Ok(date_timestamp) => Some(date_timestamp), + Err(_) => None, + } + } else { + None + } + } +} + +impl std::convert::From for CellContentChangeset { + fn from(changeset: DateCellContentChangeset) -> Self { + let s = serde_json::to_string(&changeset).unwrap(); + CellContentChangeset::from(s) + } +} + #[cfg(test)] mod tests { use crate::services::field::FieldBuilder; - use crate::services::field::{DateFormat, DateTypeOption, TimeFormat}; + use crate::services::field::{DateCellContentChangeset, DateFormat, DateTypeOption, TimeFormat}; use crate::services::row::{CellDataOperation, TypeOptionCellData}; use flowy_grid_data_model::entities::FieldType; use strum::IntoEnumIterator; @@ -362,14 +383,20 @@ mod tests { type_option.time_format = time_format; match time_format { TimeFormat::TwentyFourHour => { - assert_eq!("Mar 14,2022".to_owned(), type_option.today_from_timestamp(1647251762)); + assert_eq!( + "Mar 14,2022".to_owned(), + type_option.today_desc_from_timestamp(1647251762) + ); assert_eq!( "Mar 14,2022".to_owned(), type_option.decode_cell_data(data("1647251762"), &field_meta).content ); } TimeFormat::TwelveHour => { - assert_eq!("Mar 14,2022".to_owned(), type_option.today_from_timestamp(1647251762)); + assert_eq!( + "Mar 14,2022".to_owned(), + type_option.today_desc_from_timestamp(1647251762) + ); assert_eq!( "Mar 14,2022".to_owned(), type_option.decode_cell_data(data("1647251762"), &field_meta).content @@ -379,6 +406,72 @@ mod tests { } } + #[test] + fn date_description_apply_changeset_test() { + let mut type_option = DateTypeOption::default(); + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + let date_timestamp = "1653609600".to_owned(); + + let changeset = DateCellContentChangeset { + date: Some(date_timestamp.clone()), + time: None, + }; + let result = type_option.apply_changeset(changeset, None).unwrap(); + let content = type_option.decode_cell_data(result.clone(), &field_meta).content; + assert_eq!(content, "May 27,2022".to_owned()); + + type_option.include_time = true; + let content = type_option.decode_cell_data(result, &field_meta).content; + assert_eq!(content, "May 27,2022 00:00".to_owned()); + + let changeset = DateCellContentChangeset { + date: Some(date_timestamp.clone()), + time: Some("1:00".to_owned()), + }; + let result = type_option.apply_changeset(changeset, None).unwrap(); + let content = type_option.decode_cell_data(result, &field_meta).content; + assert_eq!(content, "May 27,2022 01:00".to_owned()); + + let changeset = DateCellContentChangeset { + date: Some(date_timestamp), + time: Some("1:00 am".to_owned()), + }; + type_option.time_format = TimeFormat::TwelveHour; + let result = type_option.apply_changeset(changeset, None).unwrap(); + let content = type_option.decode_cell_data(result, &field_meta).content; + assert_eq!(content, "May 27,2022 01:00 AM".to_owned()); + } + + #[test] + #[should_panic] + fn date_description_apply_changeset_error_test() { + let mut type_option = DateTypeOption::default(); + type_option.include_time = true; + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + let date_timestamp = "1653609600".to_owned(); + + let changeset = DateCellContentChangeset { + date: Some(date_timestamp.clone()), + time: Some("1:a0".to_owned()), + }; + let _ = type_option.apply_changeset(changeset, None).unwrap(); + + let changeset = DateCellContentChangeset { + date: Some(date_timestamp.clone()), + time: Some("1:".to_owned()), + }; + let _ = type_option.apply_changeset(changeset, None).unwrap(); + + // let changeset = DateCellContentChangeset { + // date: Some(date_timestamp), + // time: Some("1:00 am".to_owned()), + // }; + // type_option.time_format = TimeFormat::TwelveHour; + // let result = type_option.apply_changeset(changeset, None).unwrap(); + // let content = type_option.decode_cell_data(result, &field_meta).content; + // assert_eq!(content, "May 27,2022 01:00 AM".to_owned()); + } + #[test] #[should_panic] fn date_description_invalid_data_test() { diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index c07b81ac58..b0695af1fd 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -337,7 +337,7 @@ impl ClientGridEditor { } #[tracing::instrument(level = "trace", skip_all, err)] - pub async fn update_cell(&self, mut cell_changeset: CellChangeset) -> FlowyResult<()> { + pub async fn update_cell(&self, cell_changeset: CellChangeset) -> FlowyResult<()> { if cell_changeset.cell_content_changeset.as_ref().is_none() { return Ok(()); } From 76079d8ce0b61889812b89b0534b8344ce738db5 Mon Sep 17 00:00:00 2001 From: appflowy Date: Thu, 12 May 2022 22:36:39 +0800 Subject: [PATCH 11/14] chore: display time --- .../cell/cell_service/context_builder.dart | 10 +- .../grid/cell/cell_service/data_loader.dart | 32 ++- .../cell/cell_service/data_persistence.dart | 26 ++- .../application/grid/cell/date_cal_bloc.dart | 17 +- .../application/grid/cell/date_cell_bloc.dart | 31 ++- .../grid/cell/select_option_service.dart | 4 +- .../src/widgets/cell/date_cell/calendar.dart | 28 ++- .../src/widgets/cell/date_cell/date_cell.dart | 5 +- .../dart_event/flowy-grid/dart_event.dart | 27 ++- .../flowy-grid/date_type_option.pb.dart | 61 +++++ .../flowy-grid/date_type_option.pbjson.dart | 11 + .../protobuf/flowy-grid/event_map.pbenum.dart | 6 +- .../protobuf/flowy-grid/event_map.pbjson.dart | 5 +- .../flowy-grid/selection_type_option.pb.dart | 26 +-- .../selection_type_option.pbjson.dart | 10 +- .../rust-lib/flowy-grid/src/event_handler.rs | 39 ++-- frontend/rust-lib/flowy-grid/src/event_map.rs | 10 +- .../src/protobuf/model/date_type_option.rs | 217 +++++++++++++++++- .../src/protobuf/model/event_map.rs | 17 +- .../protobuf/model/selection_type_option.rs | 50 ++-- .../src/protobuf/proto/date_type_option.proto | 4 + .../src/protobuf/proto/event_map.proto | 3 +- .../proto/selection_type_option.proto | 2 +- .../field/type_options/date_type_option.rs | 33 ++- .../type_options/selection_type_option.rs | 12 +- 25 files changed, 533 insertions(+), 153 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart index ec2f498275..47492ab602 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart @@ -1,8 +1,8 @@ part of 'cell_service.dart'; typedef GridCellContext = _GridCellContext; -typedef GridSelectOptionCellContext = _GridCellContext; -typedef GridDateCellContext = _GridCellContext; +typedef GridSelectOptionCellContext = _GridCellContext; +typedef GridDateCellContext = _GridCellContext; class GridCellContextBuilder { final GridCellCache _cellCache; @@ -26,7 +26,7 @@ class GridCellContextBuilder { return GridDateCellContext( gridCell: _gridCell, cellCache: _cellCache, - cellDataLoader: CellDataLoader(gridCell: _gridCell), + cellDataLoader: DateCellDataLoader(gridCell: _gridCell), cellDataPersistence: NumberCellDataPersistence(gridCell: _gridCell), ); case FieldType.Number: @@ -154,8 +154,8 @@ class _GridCellContext extends Equatable { return _fieldService.getTypeOptionData(fieldType: fieldType); } - void saveCellData(D data) { - cellDataPersistence.save(data); + Future> saveCellData(D data) { + return cellDataPersistence.save(data); } void _loadData() { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart index 0a630deba9..c74ee1a8ae 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart @@ -59,14 +59,42 @@ class CellDataLoader extends _GridCellDataLoader { GridCellDataConfig get config => _config; } -class SelectOptionCellDataLoader extends _GridCellDataLoader { +class DateCellDataLoader extends _GridCellDataLoader { + final GridCell gridCell; + DateCellDataLoader({ + required this.gridCell, + }); + + @override + GridCellDataConfig get config => DefaultCellDataConfig(); + + @override + Future loadData() { + final payload = CellIdentifierPayload.create() + ..gridId = gridCell.gridId + ..fieldId = gridCell.field.id + ..rowId = gridCell.rowId; + + return GridEventGetDateCellData(payload).send().then((result) { + return result.fold( + (data) => data, + (err) { + Log.error(err); + return null; + }, + ); + }); + } +} + +class SelectOptionCellDataLoader extends _GridCellDataLoader { final SelectOptionService service; final GridCell gridCell; SelectOptionCellDataLoader({ required this.gridCell, }) : service = SelectOptionService(gridCell: gridCell); @override - Future loadData() async { + Future loadData() async { return service.getOpitonContext().then((result) { return result.fold( (data) => data, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart index b6a615a1b0..f76d4c607e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart @@ -1,7 +1,7 @@ part of 'cell_service.dart'; abstract class _GridCellDataPersistence { - void save(D data); + Future> save(D data); } class CellDataPersistence implements _GridCellDataPersistence { @@ -13,16 +13,19 @@ class CellDataPersistence implements _GridCellDataPersistence { final CellService _cellService = CellService(); @override - void save(String data) { - _cellService - .updateCell( + Future> save(String data) async { + final fut = _cellService.updateCell( gridId: gridCell.gridId, fieldId: gridCell.field.id, rowId: gridCell.rowId, data: data, - ) - .then((result) { - result.fold((l) => null, (err) => Log.error(err)); + ); + + return fut.then((result) { + return result.fold( + (l) => none(), + (err) => Some(err), + ); }); } } @@ -39,7 +42,7 @@ class NumberCellDataPersistence implements _GridCellDataPersistence> save(DateCellPersistenceData data) { var payload = DateChangesetPayload.create()..cellIdentifier = _cellIdentifier(gridCell); final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString(); @@ -49,8 +52,11 @@ class NumberCellDataPersistence implements _GridCellDataPersistence null, (err) => Log.error(err)); + return GridEventUpdateDateCell(payload).send().then((result) { + return result.fold( + (l) => none(), + (err) => Some(err), + ); }); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 8ec623f042..a59ec3bf9e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -1,7 +1,6 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -10,6 +9,7 @@ import 'dart:async'; import 'cell_service/cell_service.dart'; import 'package:dartz/dartz.dart'; import 'package:protobuf/protobuf.dart'; +import 'package:fixnum/fixnum.dart' as $fixnum; part 'date_cal_bloc.freezed.dart'; class DateCalBloc extends Bloc { @@ -18,9 +18,9 @@ class DateCalBloc extends Bloc { DateCalBloc({ required DateTypeOption dateTypeOption, - required DateTime? selectedDay, + required DateCellData? cellData, required this.cellContext, - }) : super(DateCalState.initial(dateTypeOption, selectedDay)) { + }) : super(DateCalState.initial(dateTypeOption, cellData)) { on( (event, emit) async { await event.when( @@ -142,7 +142,7 @@ class DateCalEvent with _$DateCalEvent { const factory DateCalEvent.setDateFormat(DateFormat dateFormat) = _DateFormat; const factory DateCalEvent.setIncludeTime(bool includeTime) = _IncludeTime; const factory DateCalEvent.setTime(String time) = _Time; - const factory DateCalEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; + const factory DateCalEvent.didReceiveCellUpdate(DateCellData data) = _DidReceiveCellUpdate; } @freezed @@ -158,10 +158,13 @@ class DateCalState with _$DateCalState { factory DateCalState.initial( DateTypeOption dateTypeOption, - DateTime? selectedDay, + DateCellData? cellData, ) { Option dateData = none(); - if (selectedDay != null) { + final time = cellData?.time ?? ""; + if (cellData != null) { + final timestamp = $fixnum.Int64.parseInt(cellData.date).toInt(); + final selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); dateData = Some(DateCellPersistenceData(date: selectedDay)); } @@ -170,7 +173,7 @@ class DateCalState with _$DateCalState { format: CalendarFormat.month, focusedDay: DateTime.now(), dateData: dateData, - time: "", + time: time, inputTimeError: none(), ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index 24ddb564cd..844ba6ca81 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -1,8 +1,10 @@ -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; +import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; import 'cell_service/cell_service.dart'; +import 'package:dartz/dartz.dart'; part 'date_cell_bloc.freezed.dart'; class DateCellBloc extends Bloc { @@ -15,7 +17,7 @@ class DateCellBloc extends Bloc { event.when( initial: () => _startListening(), selectDate: (DateCellPersistenceData value) => cellContext.saveCellData(value), - didReceiveCellUpdate: (Cell value) => emit(state.copyWith(content: value.content)), + didReceiveCellUpdate: (DateCellData value) => emit(state.copyWith(data: Some(value))), didReceiveFieldUpdate: (Field value) => emit(state.copyWith(field: value)), ); }, @@ -34,9 +36,9 @@ class DateCellBloc extends Bloc { void _startListening() { _onCellChangedFn = cellContext.startListening( - onCellChanged: ((cell) { + onCellChanged: ((data) { if (!isClosed) { - add(DateCellEvent.didReceiveCellUpdate(cell)); + add(DateCellEvent.didReceiveCellUpdate(data)); } }), ); @@ -47,19 +49,28 @@ class DateCellBloc extends Bloc { class DateCellEvent with _$DateCellEvent { const factory DateCellEvent.initial() = _InitialCell; const factory DateCellEvent.selectDate(DateCellPersistenceData data) = _SelectDay; - const factory DateCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate; + const factory DateCellEvent.didReceiveCellUpdate(DateCellData data) = _DidReceiveCellUpdate; const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; } @freezed class DateCellState with _$DateCellState { const factory DateCellState({ - required String content, + required Option data, required Field field, }) = _DateCellState; - factory DateCellState.initial(GridDateCellContext context) => DateCellState( - field: context.field, - content: context.getCellData()?.content ?? "", - ); + factory DateCellState.initial(GridDateCellContext context) { + final cellData = context.getCellData(); + Option data = none(); + + if (cellData != null) { + data = Some(cellData); + } + + return DateCellState( + field: context.field, + data: data, + ); + } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart index eeabdfbd67..806389d67c 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -53,13 +53,13 @@ class SelectOptionService { return GridEventUpdateSelectOption(payload).send(); } - Future> getOpitonContext() { + Future> getOpitonContext() { final payload = CellIdentifierPayload.create() ..gridId = gridId ..fieldId = fieldId ..rowId = rowId; - return GridEventGetSelectOptionContext(payload).send(); + return GridEventGetSelectOptionCellData(payload).send(); } Future> select({required String optionId}) { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 8c34105f0b..7136ad6216 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -16,7 +16,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:table_calendar/table_calendar.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; -import 'package:fixnum/fixnum.dart' as $fixnum; final kToday = DateTime.now(); final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); @@ -41,19 +40,18 @@ class CellCalendar with FlowyOverlayDelegate { result.fold( (data) { final typeOptionData = DateTypeOption.fromBuffer(data); - DateTime? selectedDay; - final cellData = cellContext.getCellData()?.data; + // DateTime? selectedDay; + // final cellData = cellContext.getCellData(); - if (cellData != null) { - final timestamp = $fixnum.Int64.parseInt(cellData).toInt(); - selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); - } + // if (cellData != null) { + // final timestamp = $fixnum.Int64.parseInt(cellData).toInt(); + // selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); + // } final calendar = _CellCalendarWidget( onSelected: onSelected, cellContext: cellContext, dateTypeOption: typeOptionData, - selectedDay: selectedDay, ); FlowyOverlay.of(context).insertWithAnchor( @@ -90,14 +88,12 @@ class CellCalendar with FlowyOverlayDelegate { class _CellCalendarWidget extends StatelessWidget { final GridDateCellContext cellContext; final DateTypeOption dateTypeOption; - final DateTime? selectedDay; final void Function(DateCellPersistenceData) onSelected; const _CellCalendarWidget({ required this.onSelected, required this.cellContext, required this.dateTypeOption, - this.selectedDay, Key? key, }) : super(key: key); @@ -105,11 +101,13 @@ class _CellCalendarWidget extends StatelessWidget { Widget build(BuildContext context) { final theme = context.watch(); return BlocProvider( - create: (context) => DateCalBloc( - dateTypeOption: dateTypeOption, - selectedDay: selectedDay, - cellContext: cellContext, - )..add(const DateCalEvent.initial()), + create: (context) { + return DateCalBloc( + dateTypeOption: dateTypeOption, + cellData: cellContext.getCellData(), + cellContext: cellContext, + )..add(const DateCalEvent.initial()); + }, child: BlocConsumer( listener: (context, state) { state.dateData.fold( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart index 1a278ce1da..e69f7cf10a 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart @@ -62,7 +62,10 @@ class _DateCellState extends State { child: MouseRegion( opaque: false, cursor: SystemMouseCursors.click, - child: Align(alignment: alignment, child: FlowyText.medium(state.content, fontSize: 12)), + child: Align( + alignment: alignment, + child: FlowyText.medium(state.data.foldRight("", (data, _) => data.date), fontSize: 12), + ), ), ), ); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart index ea1c73ec35..a1208075f5 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dart_event/flowy-grid/dart_event.dart @@ -222,18 +222,18 @@ class GridEventNewSelectOption { } } -class GridEventGetSelectOptionContext { +class GridEventGetSelectOptionCellData { CellIdentifierPayload request; - GridEventGetSelectOptionContext(this.request); + GridEventGetSelectOptionCellData(this.request); - Future> send() { + Future> send() { final request = FFIRequest.create() - ..event = GridEvent.GetSelectOptionContext.toString() + ..event = GridEvent.GetSelectOptionCellData.toString() ..payload = requestToBytes(this.request); return Dispatch.asyncRequest(request) .then((bytesResult) => bytesResult.fold( - (okBytes) => left(SelectOptionContext.fromBuffer(okBytes)), + (okBytes) => left(SelectOptionCellData.fromBuffer(okBytes)), (errBytes) => right(FlowyError.fromBuffer(errBytes)), )); } @@ -392,3 +392,20 @@ class GridEventUpdateDateCell { } } +class GridEventGetDateCellData { + CellIdentifierPayload request; + GridEventGetDateCellData(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.GetDateCellData.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(DateCellData.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart index 1f77ca10fb..80fcfabfe5 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart @@ -90,6 +90,67 @@ class DateTypeOption extends $pb.GeneratedMessage { void clearIncludeTime() => clearField(3); } +class DateCellData extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DateCellData', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'date') + ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'time') + ..hasRequiredFields = false + ; + + DateCellData._() : super(); + factory DateCellData({ + $core.String? date, + $core.String? time, + }) { + final _result = create(); + if (date != null) { + _result.date = date; + } + if (time != null) { + _result.time = time; + } + return _result; + } + factory DateCellData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory DateCellData.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') + DateCellData clone() => DateCellData()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + DateCellData copyWith(void Function(DateCellData) updates) => super.copyWith((message) => updates(message as DateCellData)) as DateCellData; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static DateCellData create() => DateCellData._(); + DateCellData createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static DateCellData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static DateCellData? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get date => $_getSZ(0); + @$pb.TagNumber(1) + set date($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasDate() => $_has(0); + @$pb.TagNumber(1) + void clearDate() => clearField(1); + + @$pb.TagNumber(2) + $core.String get time => $_getSZ(1); + @$pb.TagNumber(2) + set time($core.String v) { $_setString(1, v); } + @$pb.TagNumber(2) + $core.bool hasTime() => $_has(1); + @$pb.TagNumber(2) + void clearTime() => clearField(2); +} + enum DateChangesetPayload_OneOfDate { date, notSet diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart index 58f9ed5c31..722ad469bf 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart @@ -44,6 +44,17 @@ const DateTypeOption$json = const { /// Descriptor for `DateTypeOption`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List dateTypeOptionDescriptor = $convert.base64Decode('Cg5EYXRlVHlwZU9wdGlvbhIsCgtkYXRlX2Zvcm1hdBgBIAEoDjILLkRhdGVGb3JtYXRSCmRhdGVGb3JtYXQSLAoLdGltZV9mb3JtYXQYAiABKA4yCy5UaW1lRm9ybWF0Ugp0aW1lRm9ybWF0EiEKDGluY2x1ZGVfdGltZRgDIAEoCFILaW5jbHVkZVRpbWU='); +@$core.Deprecated('Use dateCellDataDescriptor instead') +const DateCellData$json = const { + '1': 'DateCellData', + '2': const [ + const {'1': 'date', '3': 1, '4': 1, '5': 9, '10': 'date'}, + const {'1': 'time', '3': 2, '4': 1, '5': 9, '10': 'time'}, + ], +}; + +/// Descriptor for `DateCellData`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List dateCellDataDescriptor = $convert.base64Decode('CgxEYXRlQ2VsbERhdGESEgoEZGF0ZRgBIAEoCVIEZGF0ZRISCgR0aW1lGAIgASgJUgR0aW1l'); @$core.Deprecated('Use dateChangesetPayloadDescriptor instead') const DateChangesetPayload$json = const { '1': 'DateChangesetPayload', diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart index 42f454d42c..0035c0f24d 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbenum.dart @@ -23,7 +23,7 @@ class GridEvent extends $pb.ProtobufEnum { static const GridEvent MoveItem = GridEvent._(23, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem'); static const GridEvent GetFieldTypeOption = GridEvent._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetFieldTypeOption'); static const GridEvent NewSelectOption = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'NewSelectOption'); - static const GridEvent GetSelectOptionContext = GridEvent._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetSelectOptionContext'); + static const GridEvent GetSelectOptionCellData = GridEvent._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetSelectOptionCellData'); static const GridEvent UpdateSelectOption = GridEvent._(32, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOption'); 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'); @@ -33,6 +33,7 @@ class GridEvent extends $pb.ProtobufEnum { static const GridEvent UpdateCell = GridEvent._(71, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCell'); static const GridEvent UpdateSelectOptionCell = GridEvent._(72, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateSelectOptionCell'); static const GridEvent UpdateDateCell = GridEvent._(80, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateDateCell'); + static const GridEvent GetDateCellData = GridEvent._(90, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetDateCellData'); static const $core.List values = [ GetGridData, @@ -48,7 +49,7 @@ class GridEvent extends $pb.ProtobufEnum { MoveItem, GetFieldTypeOption, NewSelectOption, - GetSelectOptionContext, + GetSelectOptionCellData, UpdateSelectOption, CreateRow, GetRow, @@ -58,6 +59,7 @@ class GridEvent extends $pb.ProtobufEnum { UpdateCell, UpdateSelectOptionCell, UpdateDateCell, + GetDateCellData, ]; static final $core.Map<$core.int, GridEvent> _byValue = $pb.ProtobufEnum.initByValue(values); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart index 54b39477ba..5088625002 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/event_map.pbjson.dart @@ -25,7 +25,7 @@ const GridEvent$json = const { const {'1': 'MoveItem', '2': 23}, const {'1': 'GetFieldTypeOption', '2': 24}, const {'1': 'NewSelectOption', '2': 30}, - const {'1': 'GetSelectOptionContext', '2': 31}, + const {'1': 'GetSelectOptionCellData', '2': 31}, const {'1': 'UpdateSelectOption', '2': 32}, const {'1': 'CreateRow', '2': 50}, const {'1': 'GetRow', '2': 51}, @@ -35,8 +35,9 @@ const GridEvent$json = const { const {'1': 'UpdateCell', '2': 71}, const {'1': 'UpdateSelectOptionCell', '2': 72}, const {'1': 'UpdateDateCell', '2': 80}, + const {'1': 'GetDateCellData', '2': 90}, ], }; /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAWEgwKCE1vdmVJdGVtEBcSFgoSR2V0RmllbGRUeXBlT3B0aW9uEBgSEwoPTmV3U2VsZWN0T3B0aW9uEB4SGgoWR2V0U2VsZWN0T3B0aW9uQ29udGV4dBAfEhYKElVwZGF0ZVNlbGVjdE9wdGlvbhAgEg0KCUNyZWF0ZVJvdxAyEgoKBkdldFJvdxAzEg0KCURlbGV0ZVJvdxA0EhAKDER1cGxpY2F0ZVJvdxA1EgsKB0dldENlbGwQRhIOCgpVcGRhdGVDZWxsEEcSGgoWVXBkYXRlU2VsZWN0T3B0aW9uQ2VsbBBIEhIKDlVwZGF0ZURhdGVDZWxsEFA='); +final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIZChVVcGRhdGVGaWVsZFR5cGVPcHRpb24QDBIPCgtJbnNlcnRGaWVsZBANEg8KC0RlbGV0ZUZpZWxkEA4SEQoNU3dpdGNoVG9GaWVsZBAUEhIKDkR1cGxpY2F0ZUZpZWxkEBUSFwoTR2V0RWRpdEZpZWxkQ29udGV4dBAWEgwKCE1vdmVJdGVtEBcSFgoSR2V0RmllbGRUeXBlT3B0aW9uEBgSEwoPTmV3U2VsZWN0T3B0aW9uEB4SGwoXR2V0U2VsZWN0T3B0aW9uQ2VsbERhdGEQHxIWChJVcGRhdGVTZWxlY3RPcHRpb24QIBINCglDcmVhdGVSb3cQMhIKCgZHZXRSb3cQMxINCglEZWxldGVSb3cQNBIQCgxEdXBsaWNhdGVSb3cQNRILCgdHZXRDZWxsEEYSDgoKVXBkYXRlQ2VsbBBHEhoKFlVwZGF0ZVNlbGVjdE9wdGlvbkNlbGwQSBISCg5VcGRhdGVEYXRlQ2VsbBBQEhMKD0dldERhdGVDZWxsRGF0YRBa'); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart index 53d5c5069e..fd19fd3188 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pb.dart @@ -439,15 +439,15 @@ class SelectOptionCellChangesetPayload extends $pb.GeneratedMessage { void clearDeleteOptionId() => clearField(3); } -class SelectOptionContext extends $pb.GeneratedMessage { - static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SelectOptionContext', createEmptyInstance: create) +class SelectOptionCellData extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SelectOptionCellData', createEmptyInstance: create) ..pc(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'options', $pb.PbFieldType.PM, subBuilder: SelectOption.create) ..pc(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'selectOptions', $pb.PbFieldType.PM, subBuilder: SelectOption.create) ..hasRequiredFields = false ; - SelectOptionContext._() : super(); - factory SelectOptionContext({ + SelectOptionCellData._() : super(); + factory SelectOptionCellData({ $core.Iterable? options, $core.Iterable? selectOptions, }) { @@ -460,26 +460,26 @@ class SelectOptionContext extends $pb.GeneratedMessage { } return _result; } - factory SelectOptionContext.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); - factory SelectOptionContext.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); + factory SelectOptionCellData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory SelectOptionCellData.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') - SelectOptionContext clone() => SelectOptionContext()..mergeFromMessage(this); + SelectOptionCellData clone() => SelectOptionCellData()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') - SelectOptionContext copyWith(void Function(SelectOptionContext) updates) => super.copyWith((message) => updates(message as SelectOptionContext)) as SelectOptionContext; // ignore: deprecated_member_use + SelectOptionCellData copyWith(void Function(SelectOptionCellData) updates) => super.copyWith((message) => updates(message as SelectOptionCellData)) as SelectOptionCellData; // ignore: deprecated_member_use $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') - static SelectOptionContext create() => SelectOptionContext._(); - SelectOptionContext createEmptyInstance() => create(); - static $pb.PbList createRepeated() => $pb.PbList(); + static SelectOptionCellData create() => SelectOptionCellData._(); + SelectOptionCellData createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') - static SelectOptionContext getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); - static SelectOptionContext? _defaultInstance; + static SelectOptionCellData getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static SelectOptionCellData? _defaultInstance; @$pb.TagNumber(1) $core.List get options => $_getList(0); diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart index 2166a01087..9b830bd531 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/selection_type_option.pbjson.dart @@ -94,14 +94,14 @@ const SelectOptionCellChangesetPayload$json = const { /// Descriptor for `SelectOptionCellChangesetPayload`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List selectOptionCellChangesetPayloadDescriptor = $convert.base64Decode('CiBTZWxlY3RPcHRpb25DZWxsQ2hhbmdlc2V0UGF5bG9hZBI/Cg9jZWxsX2lkZW50aWZpZXIYASABKAsyFi5DZWxsSWRlbnRpZmllclBheWxvYWRSDmNlbGxJZGVudGlmaWVyEioKEGluc2VydF9vcHRpb25faWQYAiABKAlIAFIOaW5zZXJ0T3B0aW9uSWQSKgoQZGVsZXRlX29wdGlvbl9pZBgDIAEoCUgBUg5kZWxldGVPcHRpb25JZEIZChdvbmVfb2ZfaW5zZXJ0X29wdGlvbl9pZEIZChdvbmVfb2ZfZGVsZXRlX29wdGlvbl9pZA=='); -@$core.Deprecated('Use selectOptionContextDescriptor instead') -const SelectOptionContext$json = const { - '1': 'SelectOptionContext', +@$core.Deprecated('Use selectOptionCellDataDescriptor instead') +const SelectOptionCellData$json = const { + '1': 'SelectOptionCellData', '2': const [ const {'1': 'options', '3': 1, '4': 3, '5': 11, '6': '.SelectOption', '10': 'options'}, const {'1': 'select_options', '3': 2, '4': 3, '5': 11, '6': '.SelectOption', '10': 'selectOptions'}, ], }; -/// Descriptor for `SelectOptionContext`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List selectOptionContextDescriptor = $convert.base64Decode('ChNTZWxlY3RPcHRpb25Db250ZXh0EicKB29wdGlvbnMYASADKAsyDS5TZWxlY3RPcHRpb25SB29wdGlvbnMSNAoOc2VsZWN0X29wdGlvbnMYAiADKAsyDS5TZWxlY3RPcHRpb25SDXNlbGVjdE9wdGlvbnM='); +/// Descriptor for `SelectOptionCellData`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List selectOptionCellDataDescriptor = $convert.base64Decode('ChRTZWxlY3RPcHRpb25DZWxsRGF0YRInCgdvcHRpb25zGAEgAygLMg0uU2VsZWN0T3B0aW9uUgdvcHRpb25zEjQKDnNlbGVjdF9vcHRpb25zGAIgAygLMg0uU2VsZWN0T3B0aW9uUg1zZWxlY3RPcHRpb25z'); diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index c87c94de7c..9f59899063 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -274,6 +274,27 @@ pub(crate) async fn update_cell_handler( Ok(()) } +#[tracing::instrument(level = "debug", skip(data, manager), err)] +pub(crate) async fn get_date_cell_data_handler( + data: Data, + manager: AppData>, +) -> DataResult { + let params: CellIdentifier = data.into_inner().try_into()?; + let editor = manager.get_grid_editor(¶ms.grid_id)?; + match editor.get_field_meta(¶ms.field_id).await { + None => { + tracing::error!("Can't find the corresponding field with id: {}", params.field_id); + data_result(DateCellData::default()) + } + Some(field_meta) => { + let cell_meta = editor.get_cell_meta(¶ms.row_id, ¶ms.field_id).await?; + let type_option = DateTypeOption::from(&field_meta); + let date_cell_data = type_option.date_cell_data(&cell_meta)?; + data_result(date_cell_data) + } + } +} + #[tracing::instrument(level = "debug", skip_all, err)] pub(crate) async fn new_select_option_handler( data: Data, @@ -330,35 +351,23 @@ pub(crate) async fn update_select_option_handler( } Ok(()) } -// -// #[tracing::instrument(level = "debug", skip_all, err)] -// pub(crate) async fn update_date_option_handler( -// data: Data, -// manager: AppData>, -// ) -> Result<(), FlowyError> { -// let params: SelectOptionCellChangesetParams = data.into_inner().try_into()?; -// let editor = manager.get_grid_editor(¶ms.grid_id)?; -// let changeset: CellChangeset = params.into(); -// let _ = editor.update_cell(changeset).await?; -// Ok(()) -// } #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn get_select_option_handler( data: Data, manager: AppData>, -) -> DataResult { +) -> DataResult { let params: CellIdentifier = data.into_inner().try_into()?; let editor = manager.get_grid_editor(¶ms.grid_id)?; match editor.get_field_meta(¶ms.field_id).await { None => { tracing::error!("Can't find the corresponding field with id: {}", params.field_id); - data_result(SelectOptionContext::default()) + data_result(SelectOptionCellData::default()) } Some(field_meta) => { let cell_meta = editor.get_cell_meta(¶ms.row_id, ¶ms.field_id).await?; let type_option = select_option_operation(&field_meta)?; - let option_context = type_option.option_context(&cell_meta); + let option_context = type_option.select_option_cell_data(&cell_meta); data_result(option_context) } } diff --git a/frontend/rust-lib/flowy-grid/src/event_map.rs b/frontend/rust-lib/flowy-grid/src/event_map.rs index ccd437c0a0..2d29d7f096 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -29,10 +29,11 @@ pub fn create(grid_manager: Arc) -> Module { // Cell .event(GridEvent::GetCell, get_cell_handler) .event(GridEvent::UpdateCell, update_cell_handler) + .event(GridEvent::GetDateCellData, get_date_cell_data_handler) // SelectOption .event(GridEvent::NewSelectOption, new_select_option_handler) .event(GridEvent::UpdateSelectOption, update_select_option_handler) - .event(GridEvent::GetSelectOptionContext, get_select_option_handler) + .event(GridEvent::GetSelectOptionCellData, get_select_option_handler) .event(GridEvent::UpdateSelectOptionCell, update_select_option_cell_handler) // Date .event(GridEvent::UpdateDateCell, update_date_cell_handler); @@ -82,8 +83,8 @@ pub enum GridEvent { #[event(input = "CreateSelectOptionPayload", output = "SelectOption")] NewSelectOption = 30, - #[event(input = "CellIdentifierPayload", output = "SelectOptionContext")] - GetSelectOptionContext = 31, + #[event(input = "CellIdentifierPayload", output = "SelectOptionCellData")] + GetSelectOptionCellData = 31, #[event(input = "SelectOptionChangesetPayload")] UpdateSelectOption = 32, @@ -111,4 +112,7 @@ pub enum GridEvent { #[event(input = "DateChangesetPayload")] UpdateDateCell = 80, + + #[event(input = "CellIdentifierPayload", output = "DateCellData")] + GetDateCellData = 90, } diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs index 0d84c294ac..2e80c2ad81 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs @@ -237,6 +237,207 @@ impl ::protobuf::reflect::ProtobufValue for DateTypeOption { } } +#[derive(PartialEq,Clone,Default)] +pub struct DateCellData { + // message fields + pub date: ::std::string::String, + pub time: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a DateCellData { + fn default() -> &'a DateCellData { + ::default_instance() + } +} + +impl DateCellData { + pub fn new() -> DateCellData { + ::std::default::Default::default() + } + + // string date = 1; + + + pub fn get_date(&self) -> &str { + &self.date + } + pub fn clear_date(&mut self) { + self.date.clear(); + } + + // Param is passed by value, moved + pub fn set_date(&mut self, v: ::std::string::String) { + self.date = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_date(&mut self) -> &mut ::std::string::String { + &mut self.date + } + + // Take field + pub fn take_date(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.date, ::std::string::String::new()) + } + + // string time = 2; + + + pub fn get_time(&self) -> &str { + &self.time + } + pub fn clear_time(&mut self) { + self.time.clear(); + } + + // Param is passed by value, moved + pub fn set_time(&mut self, v: ::std::string::String) { + self.time = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_time(&mut self) -> &mut ::std::string::String { + &mut self.time + } + + // Take field + pub fn take_time(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.time, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for DateCellData { + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> { + while !is.eof()? { + let (field_number, wire_type) = is.read_tag_unpack()?; + match field_number { + 1 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.date)?; + }, + 2 => { + ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.time)?; + }, + _ => { + ::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.date.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.date); + } + if !self.time.is_empty() { + my_size += ::protobuf::rt::string_size(2, &self.time); + } + 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.date.is_empty() { + os.write_string(1, &self.date)?; + } + if !self.time.is_empty() { + os.write_string(2, &self.time)?; + } + os.write_unknown_fields(self.get_unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn get_cached_size(&self) -> u32 { + self.cached_size.get() + } + + fn get_unknown_fields(&self) -> &::protobuf::UnknownFields { + &self.unknown_fields + } + + fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields { + &mut self.unknown_fields + } + + fn as_any(&self) -> &dyn (::std::any::Any) { + self as &dyn (::std::any::Any) + } + fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) { + self as &mut dyn (::std::any::Any) + } + fn into_any(self: ::std::boxed::Box) -> ::std::boxed::Box { + self + } + + fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor { + Self::descriptor_static() + } + + fn new() -> DateCellData { + DateCellData::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>( + "date", + |m: &DateCellData| { &m.date }, + |m: &mut DateCellData| { &mut m.date }, + )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( + "time", + |m: &DateCellData| { &m.time }, + |m: &mut DateCellData| { &mut m.time }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "DateCellData", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static DateCellData { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(DateCellData::new) + } +} + +impl ::protobuf::Clear for DateCellData { + fn clear(&mut self) { + self.date.clear(); + self.time.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for DateCellData { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for DateCellData { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + #[derive(PartialEq,Clone,Default)] pub struct DateChangesetPayload { // message fields @@ -685,13 +886,15 @@ static file_descriptor_proto_data: &'static [u8] = b"\ ateTypeOption\x12,\n\x0bdate_format\x18\x01\x20\x01(\x0e2\x0b.DateFormat\ R\ndateFormat\x12,\n\x0btime_format\x18\x02\x20\x01(\x0e2\x0b.TimeFormat\ R\ntimeFormat\x12!\n\x0cinclude_time\x18\x03\x20\x01(\x08R\x0bincludeTim\ - e\"\xa1\x01\n\x14DateChangesetPayload\x12?\n\x0fcell_identifier\x18\x01\ - \x20\x01(\x0b2\x16.CellIdentifierPayloadR\x0ecellIdentifier\x12\x14\n\ - \x04date\x18\x02\x20\x01(\tH\0R\x04date\x12\x14\n\x04time\x18\x03\x20\ - \x01(\tH\x01R\x04timeB\r\n\x0bone_of_dateB\r\n\x0bone_of_time*6\n\nDateF\ - ormat\x12\t\n\x05Local\x10\0\x12\x06\n\x02US\x10\x01\x12\x07\n\x03ISO\ - \x10\x02\x12\x0c\n\x08Friendly\x10\x03*0\n\nTimeFormat\x12\x0e\n\nTwelve\ - Hour\x10\0\x12\x12\n\x0eTwentyFourHour\x10\x01b\x06proto3\ + e\"6\n\x0cDateCellData\x12\x12\n\x04date\x18\x01\x20\x01(\tR\x04date\x12\ + \x12\n\x04time\x18\x02\x20\x01(\tR\x04time\"\xa1\x01\n\x14DateChangesetP\ + ayload\x12?\n\x0fcell_identifier\x18\x01\x20\x01(\x0b2\x16.CellIdentifie\ + rPayloadR\x0ecellIdentifier\x12\x14\n\x04date\x18\x02\x20\x01(\tH\0R\x04\ + date\x12\x14\n\x04time\x18\x03\x20\x01(\tH\x01R\x04timeB\r\n\x0bone_of_d\ + ateB\r\n\x0bone_of_time*6\n\nDateFormat\x12\t\n\x05Local\x10\0\x12\x06\n\ + \x02US\x10\x01\x12\x07\n\x03ISO\x10\x02\x12\x0c\n\x08Friendly\x10\x03*0\ + \n\nTimeFormat\x12\x0e\n\nTwelveHour\x10\0\x12\x12\n\x0eTwentyFourHour\ + \x10\x01b\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs index 0b2648208c..bb7494ec3e 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/event_map.rs @@ -38,7 +38,7 @@ pub enum GridEvent { MoveItem = 23, GetFieldTypeOption = 24, NewSelectOption = 30, - GetSelectOptionContext = 31, + GetSelectOptionCellData = 31, UpdateSelectOption = 32, CreateRow = 50, GetRow = 51, @@ -48,6 +48,7 @@ pub enum GridEvent { UpdateCell = 71, UpdateSelectOptionCell = 72, UpdateDateCell = 80, + GetDateCellData = 90, } impl ::protobuf::ProtobufEnum for GridEvent { @@ -70,7 +71,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { 23 => ::std::option::Option::Some(GridEvent::MoveItem), 24 => ::std::option::Option::Some(GridEvent::GetFieldTypeOption), 30 => ::std::option::Option::Some(GridEvent::NewSelectOption), - 31 => ::std::option::Option::Some(GridEvent::GetSelectOptionContext), + 31 => ::std::option::Option::Some(GridEvent::GetSelectOptionCellData), 32 => ::std::option::Option::Some(GridEvent::UpdateSelectOption), 50 => ::std::option::Option::Some(GridEvent::CreateRow), 51 => ::std::option::Option::Some(GridEvent::GetRow), @@ -80,6 +81,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { 71 => ::std::option::Option::Some(GridEvent::UpdateCell), 72 => ::std::option::Option::Some(GridEvent::UpdateSelectOptionCell), 80 => ::std::option::Option::Some(GridEvent::UpdateDateCell), + 90 => ::std::option::Option::Some(GridEvent::GetDateCellData), _ => ::std::option::Option::None } } @@ -99,7 +101,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { GridEvent::MoveItem, GridEvent::GetFieldTypeOption, GridEvent::NewSelectOption, - GridEvent::GetSelectOptionContext, + GridEvent::GetSelectOptionCellData, GridEvent::UpdateSelectOption, GridEvent::CreateRow, GridEvent::GetRow, @@ -109,6 +111,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { GridEvent::UpdateCell, GridEvent::UpdateSelectOptionCell, GridEvent::UpdateDateCell, + GridEvent::GetDateCellData, ]; values } @@ -137,18 +140,18 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\xc4\x03\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ + \n\x0fevent_map.proto*\xda\x03\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\x19\n\x15UpdateFieldTypeOption\x10\x0c\x12\ \x0f\n\x0bInsertField\x10\r\x12\x0f\n\x0bDeleteField\x10\x0e\x12\x11\n\r\ SwitchToField\x10\x14\x12\x12\n\x0eDuplicateField\x10\x15\x12\x17\n\x13G\ etEditFieldContext\x10\x16\x12\x0c\n\x08MoveItem\x10\x17\x12\x16\n\x12Ge\ - tFieldTypeOption\x10\x18\x12\x13\n\x0fNewSelectOption\x10\x1e\x12\x1a\n\ - \x16GetSelectOptionContext\x10\x1f\x12\x16\n\x12UpdateSelectOption\x10\ + tFieldTypeOption\x10\x18\x12\x13\n\x0fNewSelectOption\x10\x1e\x12\x1b\n\ + \x17GetSelectOptionCellData\x10\x1f\x12\x16\n\x12UpdateSelectOption\x10\ \x20\x12\r\n\tCreateRow\x102\x12\n\n\x06GetRow\x103\x12\r\n\tDeleteRow\ \x104\x12\x10\n\x0cDuplicateRow\x105\x12\x0b\n\x07GetCell\x10F\x12\x0e\n\ \nUpdateCell\x10G\x12\x1a\n\x16UpdateSelectOptionCell\x10H\x12\x12\n\x0e\ - UpdateDateCell\x10Pb\x06proto3\ + UpdateDateCell\x10P\x12\x13\n\x0fGetDateCellData\x10Zb\x06proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs index d81b9ce6cb..7d6177ee58 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/selection_type_option.rs @@ -1437,7 +1437,7 @@ impl ::protobuf::reflect::ProtobufValue for SelectOptionCellChangesetPayload { } #[derive(PartialEq,Clone,Default)] -pub struct SelectOptionContext { +pub struct SelectOptionCellData { // message fields pub options: ::protobuf::RepeatedField, pub select_options: ::protobuf::RepeatedField, @@ -1446,14 +1446,14 @@ pub struct SelectOptionContext { pub cached_size: ::protobuf::CachedSize, } -impl<'a> ::std::default::Default for &'a SelectOptionContext { - fn default() -> &'a SelectOptionContext { - ::default_instance() +impl<'a> ::std::default::Default for &'a SelectOptionCellData { + fn default() -> &'a SelectOptionCellData { + ::default_instance() } } -impl SelectOptionContext { - pub fn new() -> SelectOptionContext { +impl SelectOptionCellData { + pub fn new() -> SelectOptionCellData { ::std::default::Default::default() } @@ -1508,7 +1508,7 @@ impl SelectOptionContext { } } -impl ::protobuf::Message for SelectOptionContext { +impl ::protobuf::Message for SelectOptionCellData { fn is_initialized(&self) -> bool { for v in &self.options { if !v.is_initialized() { @@ -1599,8 +1599,8 @@ impl ::protobuf::Message for SelectOptionContext { Self::descriptor_static() } - fn new() -> SelectOptionContext { - SelectOptionContext::new() + fn new() -> SelectOptionCellData { + SelectOptionCellData::new() } fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor { @@ -1609,29 +1609,29 @@ impl ::protobuf::Message for SelectOptionContext { let mut fields = ::std::vec::Vec::new(); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "options", - |m: &SelectOptionContext| { &m.options }, - |m: &mut SelectOptionContext| { &mut m.options }, + |m: &SelectOptionCellData| { &m.options }, + |m: &mut SelectOptionCellData| { &mut m.options }, )); fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage>( "select_options", - |m: &SelectOptionContext| { &m.select_options }, - |m: &mut SelectOptionContext| { &mut m.select_options }, + |m: &SelectOptionCellData| { &m.select_options }, + |m: &mut SelectOptionCellData| { &mut m.select_options }, )); - ::protobuf::reflect::MessageDescriptor::new_pb_name::( - "SelectOptionContext", + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "SelectOptionCellData", fields, file_descriptor_proto() ) }) } - fn default_instance() -> &'static SelectOptionContext { - static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; - instance.get(SelectOptionContext::new) + fn default_instance() -> &'static SelectOptionCellData { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(SelectOptionCellData::new) } } -impl ::protobuf::Clear for SelectOptionContext { +impl ::protobuf::Clear for SelectOptionCellData { fn clear(&mut self) { self.options.clear(); self.select_options.clear(); @@ -1639,13 +1639,13 @@ impl ::protobuf::Clear for SelectOptionContext { } } -impl ::std::fmt::Debug for SelectOptionContext { +impl ::std::fmt::Debug for SelectOptionCellData { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { ::protobuf::text_format::fmt(self, f) } } -impl ::protobuf::reflect::ProtobufValue for SelectOptionContext { +impl ::protobuf::reflect::ProtobufValue for SelectOptionCellData { fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { ::protobuf::reflect::ReflectValueRef::Message(self) } @@ -1742,10 +1742,10 @@ static file_descriptor_proto_data: &'static [u8] = b"\ loadR\x0ecellIdentifier\x12*\n\x10insert_option_id\x18\x02\x20\x01(\tH\0\ R\x0einsertOptionId\x12*\n\x10delete_option_id\x18\x03\x20\x01(\tH\x01R\ \x0edeleteOptionIdB\x19\n\x17one_of_insert_option_idB\x19\n\x17one_of_de\ - lete_option_id\"t\n\x13SelectOptionContext\x12'\n\x07options\x18\x01\x20\ - \x03(\x0b2\r.SelectOptionR\x07options\x124\n\x0eselect_options\x18\x02\ - \x20\x03(\x0b2\r.SelectOptionR\rselectOptions*y\n\x11SelectOptionColor\ - \x12\n\n\x06Purple\x10\0\x12\x08\n\x04Pink\x10\x01\x12\r\n\tLightPink\ + lete_option_id\"u\n\x14SelectOptionCellData\x12'\n\x07options\x18\x01\ + \x20\x03(\x0b2\r.SelectOptionR\x07options\x124\n\x0eselect_options\x18\ + \x02\x20\x03(\x0b2\r.SelectOptionR\rselectOptions*y\n\x11SelectOptionCol\ + or\x12\n\n\x06Purple\x10\0\x12\x08\n\x04Pink\x10\x01\x12\r\n\tLightPink\ \x10\x02\x12\n\n\x06Orange\x10\x03\x12\n\n\x06Yellow\x10\x04\x12\x08\n\ \x04Lime\x10\x05\x12\t\n\x05Green\x10\x06\x12\x08\n\x04Aqua\x10\x07\x12\ \x08\n\x04Blue\x10\x08b\x06proto3\ diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto index 602082e8a9..ddd4197e09 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto @@ -6,6 +6,10 @@ message DateTypeOption { TimeFormat time_format = 2; bool include_time = 3; } +message DateCellData { + string date = 1; + string time = 2; +} message DateChangesetPayload { CellIdentifierPayload cell_identifier = 1; oneof one_of_date { string date = 2; }; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto index c98008d678..02f621b29e 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/event_map.proto @@ -14,7 +14,7 @@ enum GridEvent { MoveItem = 23; GetFieldTypeOption = 24; NewSelectOption = 30; - GetSelectOptionContext = 31; + GetSelectOptionCellData = 31; UpdateSelectOption = 32; CreateRow = 50; GetRow = 51; @@ -24,4 +24,5 @@ enum GridEvent { UpdateCell = 71; UpdateSelectOptionCell = 72; UpdateDateCell = 80; + GetDateCellData = 90; } diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto index 822d0933cb..0ad96d7dd2 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/selection_type_option.proto @@ -25,7 +25,7 @@ message SelectOptionCellChangesetPayload { oneof one_of_insert_option_id { string insert_option_id = 2; }; oneof one_of_delete_option_id { string delete_option_id = 3; }; } -message SelectOptionContext { +message SelectOptionCellData { repeated SelectOption options = 1; repeated SelectOption select_options = 2; } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 01a748ea68..bcdb8f616d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -77,6 +77,21 @@ impl DateTypeOption { self.date_format.format_str().to_string() } } + + pub fn date_cell_data(&self, cell_meta: &Option) -> FlowyResult { + if cell_meta.is_none() { + return Ok(DateCellData::default()); + } + + let json = &cell_meta.as_ref().unwrap().data; + let result = TypeOptionCellData::from_str(json); + if result.is_err() { + return Ok(DateCellData::default()); + } + + let data: DateCellData = serde_json::from_str(&result.unwrap().data)?; + Ok(data) + } } impl CellDataOperation for DateTypeOption { @@ -235,6 +250,15 @@ impl std::default::Default for TimeFormat { } } +#[derive(Clone, Debug, Default, ProtoBuf, Serialize, Deserialize)] +pub struct DateCellData { + #[pb(index = 1)] + pub date: String, + + #[pb(index = 2)] + pub time: String, +} + #[derive(Clone, Debug, Default, ProtoBuf)] pub struct DateChangesetPayload { #[pb(index = 1)] @@ -461,15 +485,6 @@ mod tests { time: Some("1:".to_owned()), }; let _ = type_option.apply_changeset(changeset, None).unwrap(); - - // let changeset = DateCellContentChangeset { - // date: Some(date_timestamp), - // time: Some("1:00 am".to_owned()), - // }; - // type_option.time_format = TimeFormat::TwelveHour; - // let result = type_option.apply_changeset(changeset, None).unwrap(); - // let content = type_option.decode_cell_data(result, &field_meta).content; - // assert_eq!(content, "May 27,2022 01:00 AM".to_owned()); } #[test] diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs index e6a37d546e..30ecfabd9d 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/selection_type_option.rs @@ -42,7 +42,7 @@ pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync { SelectOption::with_color(name, color) } - fn option_context(&self, cell_meta: &Option) -> SelectOptionContext; + fn select_option_cell_data(&self, cell_meta: &Option) -> SelectOptionCellData; fn options(&self) -> &Vec; @@ -78,9 +78,9 @@ pub struct SingleSelectTypeOption { impl_type_option!(SingleSelectTypeOption, FieldType::SingleSelect); impl SelectOptionOperation for SingleSelectTypeOption { - fn option_context(&self, cell_meta: &Option) -> SelectOptionContext { + fn select_option_cell_data(&self, cell_meta: &Option) -> SelectOptionCellData { let select_options = make_select_context_from(cell_meta, &self.options); - SelectOptionContext { + SelectOptionCellData { options: self.options.clone(), select_options, } @@ -167,9 +167,9 @@ pub struct MultiSelectTypeOption { impl_type_option!(MultiSelectTypeOption, FieldType::MultiSelect); impl SelectOptionOperation for MultiSelectTypeOption { - fn option_context(&self, cell_meta: &Option) -> SelectOptionContext { + fn select_option_cell_data(&self, cell_meta: &Option) -> SelectOptionCellData { let select_options = make_select_context_from(cell_meta, &self.options); - SelectOptionContext { + SelectOptionCellData { options: self.options.clone(), select_options, } @@ -426,7 +426,7 @@ impl SelectOptionCellContentChangeset { } #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] -pub struct SelectOptionContext { +pub struct SelectOptionCellData { #[pb(index = 1)] pub options: Vec, From efbac6c92d0f3827b28784f0ee7d3c38a125fd82 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 13 May 2022 11:31:40 +0800 Subject: [PATCH 12/14] chore: check time format & add time format test --- .../application/grid/cell/date_cal_bloc.dart | 9 +- .../src/widgets/cell/date_cell/calendar.dart | 8 +- .../lib/widget/rounded_input_field.dart | 6 + .../flowy-grid/date_type_option.pb.dart | 15 ++ .../flowy-grid/date_type_option.pbjson.dart | 3 +- .../src/protobuf/model/date_type_option.rs | 54 +++++- .../src/protobuf/proto/date_type_option.proto | 1 + .../field/type_options/date_type_option.rs | 175 ++++++++++++------ 8 files changed, 199 insertions(+), 72 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index a59ec3bf9e..e39bbd97da 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -9,7 +9,7 @@ import 'dart:async'; import 'cell_service/cell_service.dart'; import 'package:dartz/dartz.dart'; import 'package:protobuf/protobuf.dart'; -import 'package:fixnum/fixnum.dart' as $fixnum; +// import 'package:fixnum/fixnum.dart' as $fixnum; part 'date_cal_bloc.freezed.dart'; class DateCalBloc extends Bloc { @@ -163,9 +163,10 @@ class DateCalState with _$DateCalState { Option dateData = none(); final time = cellData?.time ?? ""; if (cellData != null) { - final timestamp = $fixnum.Int64.parseInt(cellData.date).toInt(); - final selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000); - dateData = Some(DateCellPersistenceData(date: selectedDay)); + // final timestamp = $fixnum.Int64.parseInt(cellData.timestamp).toInt(); + final timestamp = cellData.timestamp * 1000; + final selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt()); + dateData = Some(DateCellPersistenceData(date: selectedDay, time: time)); } return DateCalState( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 7136ad6216..878aac6b94 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -127,7 +127,7 @@ class _CellCalendarWidget extends StatelessWidget { if (state.dateTypeOption.includeTime) { children.addAll([ _TimeTextField( - time: "", + text: state.time, errorText: state.inputTimeError.fold(() => "", (error) => error.toString()), onEditingComplete: (text) { context.read().add(DateCalEvent.setTime(text)); @@ -247,11 +247,11 @@ class _IncludeTimeButton extends StatelessWidget { class _TimeTextField extends StatefulWidget { final String errorText; - final String time; + final String text; final void Function(String) onEditingComplete; const _TimeTextField({ Key? key, - required this.time, + required this.text, required this.errorText, required this.onEditingComplete, }) : super(key: key); @@ -267,7 +267,7 @@ class _TimeTextFieldState extends State<_TimeTextField> { @override void initState() { _focusNode = FocusNode(); - _controller = TextEditingController(text: widget.time); + _controller = TextEditingController(text: widget.text); _focusNode.addListener(() { if (mounted) { widget.onEditingComplete(_controller.text); diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart index 66e40a380b..712fba3c6c 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/widget/rounded_input_field.dart @@ -60,6 +60,12 @@ class _RoundedInputFieldState extends State { @override void initState() { obscuteText = widget.obscureText; + if (widget.controller != null) { + inputText = widget.controller!.text; + } else { + inputText = widget.initialValue ?? ""; + } + super.initState(); } diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart index 80fcfabfe5..dbf93d3f76 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pb.dart @@ -7,6 +7,7 @@ import 'dart:core' as $core; +import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart' as $pb; import 'cell_entities.pb.dart' as $0; @@ -94,6 +95,7 @@ class DateCellData extends $pb.GeneratedMessage { static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'DateCellData', createEmptyInstance: create) ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'date') ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'time') + ..aInt64(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'timestamp') ..hasRequiredFields = false ; @@ -101,6 +103,7 @@ class DateCellData extends $pb.GeneratedMessage { factory DateCellData({ $core.String? date, $core.String? time, + $fixnum.Int64? timestamp, }) { final _result = create(); if (date != null) { @@ -109,6 +112,9 @@ class DateCellData extends $pb.GeneratedMessage { if (time != null) { _result.time = time; } + if (timestamp != null) { + _result.timestamp = timestamp; + } return _result; } factory DateCellData.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); @@ -149,6 +155,15 @@ class DateCellData extends $pb.GeneratedMessage { $core.bool hasTime() => $_has(1); @$pb.TagNumber(2) void clearTime() => clearField(2); + + @$pb.TagNumber(3) + $fixnum.Int64 get timestamp => $_getI64(2); + @$pb.TagNumber(3) + set timestamp($fixnum.Int64 v) { $_setInt64(2, v); } + @$pb.TagNumber(3) + $core.bool hasTimestamp() => $_has(2); + @$pb.TagNumber(3) + void clearTimestamp() => clearField(3); } enum DateChangesetPayload_OneOfDate { diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart index 722ad469bf..928412422a 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-grid/date_type_option.pbjson.dart @@ -50,11 +50,12 @@ const DateCellData$json = const { '2': const [ const {'1': 'date', '3': 1, '4': 1, '5': 9, '10': 'date'}, const {'1': 'time', '3': 2, '4': 1, '5': 9, '10': 'time'}, + const {'1': 'timestamp', '3': 3, '4': 1, '5': 3, '10': 'timestamp'}, ], }; /// Descriptor for `DateCellData`. Decode as a `google.protobuf.DescriptorProto`. -final $typed_data.Uint8List dateCellDataDescriptor = $convert.base64Decode('CgxEYXRlQ2VsbERhdGESEgoEZGF0ZRgBIAEoCVIEZGF0ZRISCgR0aW1lGAIgASgJUgR0aW1l'); +final $typed_data.Uint8List dateCellDataDescriptor = $convert.base64Decode('CgxEYXRlQ2VsbERhdGESEgoEZGF0ZRgBIAEoCVIEZGF0ZRISCgR0aW1lGAIgASgJUgR0aW1lEhwKCXRpbWVzdGFtcBgDIAEoA1IJdGltZXN0YW1w'); @$core.Deprecated('Use dateChangesetPayloadDescriptor instead') const DateChangesetPayload$json = const { '1': 'DateChangesetPayload', diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs index 2e80c2ad81..0375d32e60 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/protobuf/model/date_type_option.rs @@ -242,6 +242,7 @@ pub struct DateCellData { // message fields pub date: ::std::string::String, pub time: ::std::string::String, + pub timestamp: i64, // special fields pub unknown_fields: ::protobuf::UnknownFields, pub cached_size: ::protobuf::CachedSize, @@ -309,6 +310,21 @@ impl DateCellData { pub fn take_time(&mut self) -> ::std::string::String { ::std::mem::replace(&mut self.time, ::std::string::String::new()) } + + // int64 timestamp = 3; + + + pub fn get_timestamp(&self) -> i64 { + self.timestamp + } + pub fn clear_timestamp(&mut self) { + self.timestamp = 0; + } + + // Param is passed by value, moved + pub fn set_timestamp(&mut self, v: i64) { + self.timestamp = v; + } } impl ::protobuf::Message for DateCellData { @@ -326,6 +342,13 @@ impl ::protobuf::Message for DateCellData { 2 => { ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.time)?; }, + 3 => { + if wire_type != ::protobuf::wire_format::WireTypeVarint { + return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type)); + } + let tmp = is.read_int64()?; + self.timestamp = tmp; + }, _ => { ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; }, @@ -344,6 +367,9 @@ impl ::protobuf::Message for DateCellData { if !self.time.is_empty() { my_size += ::protobuf::rt::string_size(2, &self.time); } + if self.timestamp != 0 { + my_size += ::protobuf::rt::value_size(3, self.timestamp, ::protobuf::wire_format::WireTypeVarint); + } my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); self.cached_size.set(my_size); my_size @@ -356,6 +382,9 @@ impl ::protobuf::Message for DateCellData { if !self.time.is_empty() { os.write_string(2, &self.time)?; } + if self.timestamp != 0 { + os.write_int64(3, self.timestamp)?; + } os.write_unknown_fields(self.get_unknown_fields())?; ::std::result::Result::Ok(()) } @@ -404,6 +433,11 @@ impl ::protobuf::Message for DateCellData { |m: &DateCellData| { &m.time }, |m: &mut DateCellData| { &mut m.time }, )); + fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt64>( + "timestamp", + |m: &DateCellData| { &m.timestamp }, + |m: &mut DateCellData| { &mut m.timestamp }, + )); ::protobuf::reflect::MessageDescriptor::new_pb_name::( "DateCellData", fields, @@ -422,6 +456,7 @@ impl ::protobuf::Clear for DateCellData { fn clear(&mut self) { self.date.clear(); self.time.clear(); + self.timestamp = 0; self.unknown_fields.clear(); } } @@ -886,15 +921,16 @@ static file_descriptor_proto_data: &'static [u8] = b"\ ateTypeOption\x12,\n\x0bdate_format\x18\x01\x20\x01(\x0e2\x0b.DateFormat\ R\ndateFormat\x12,\n\x0btime_format\x18\x02\x20\x01(\x0e2\x0b.TimeFormat\ R\ntimeFormat\x12!\n\x0cinclude_time\x18\x03\x20\x01(\x08R\x0bincludeTim\ - e\"6\n\x0cDateCellData\x12\x12\n\x04date\x18\x01\x20\x01(\tR\x04date\x12\ - \x12\n\x04time\x18\x02\x20\x01(\tR\x04time\"\xa1\x01\n\x14DateChangesetP\ - ayload\x12?\n\x0fcell_identifier\x18\x01\x20\x01(\x0b2\x16.CellIdentifie\ - rPayloadR\x0ecellIdentifier\x12\x14\n\x04date\x18\x02\x20\x01(\tH\0R\x04\ - date\x12\x14\n\x04time\x18\x03\x20\x01(\tH\x01R\x04timeB\r\n\x0bone_of_d\ - ateB\r\n\x0bone_of_time*6\n\nDateFormat\x12\t\n\x05Local\x10\0\x12\x06\n\ - \x02US\x10\x01\x12\x07\n\x03ISO\x10\x02\x12\x0c\n\x08Friendly\x10\x03*0\ - \n\nTimeFormat\x12\x0e\n\nTwelveHour\x10\0\x12\x12\n\x0eTwentyFourHour\ - \x10\x01b\x06proto3\ + e\"T\n\x0cDateCellData\x12\x12\n\x04date\x18\x01\x20\x01(\tR\x04date\x12\ + \x12\n\x04time\x18\x02\x20\x01(\tR\x04time\x12\x1c\n\ttimestamp\x18\x03\ + \x20\x01(\x03R\ttimestamp\"\xa1\x01\n\x14DateChangesetPayload\x12?\n\x0f\ + cell_identifier\x18\x01\x20\x01(\x0b2\x16.CellIdentifierPayloadR\x0ecell\ + Identifier\x12\x14\n\x04date\x18\x02\x20\x01(\tH\0R\x04date\x12\x14\n\ + \x04time\x18\x03\x20\x01(\tH\x01R\x04timeB\r\n\x0bone_of_dateB\r\n\x0bon\ + e_of_time*6\n\nDateFormat\x12\t\n\x05Local\x10\0\x12\x06\n\x02US\x10\x01\ + \x12\x07\n\x03ISO\x10\x02\x12\x0c\n\x08Friendly\x10\x03*0\n\nTimeFormat\ + \x12\x0e\n\nTwelveHour\x10\0\x12\x12\n\x0eTwentyFourHour\x10\x01b\x06pro\ + to3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto b/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto index ddd4197e09..b441f29f9d 100644 --- a/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto +++ b/frontend/rust-lib/flowy-grid/src/protobuf/proto/date_type_option.proto @@ -9,6 +9,7 @@ message DateTypeOption { message DateCellData { string date = 1; string time = 2; + int64 timestamp = 3; } message DateChangesetPayload { CellIdentifierPayload cell_identifier = 1; diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index bcdb8f616d..778076d8e5 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -6,7 +6,7 @@ use bytes::Bytes; use chrono::format::strftime::StrftimeItems; use chrono::NaiveDateTime; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; -use flowy_error::{ErrorCode, FlowyError, FlowyResult}; +use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{ CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, }; @@ -30,12 +30,12 @@ pub struct DateTypeOption { impl_type_option!(DateTypeOption, FieldType::DateTime); impl DateTypeOption { - #[allow(dead_code)] fn today_desc_from_timestamp(&self, timestamp: i64) -> String { let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0); self.today_desc_from_native(native) } + #[allow(dead_code)] fn today_desc_from_str(&self, s: String) -> String { match NaiveDateTime::parse_from_str(&s, &self.fmt_str()) { Ok(native) => self.today_desc_from_native(native), @@ -89,25 +89,47 @@ impl DateTypeOption { return Ok(DateCellData::default()); } - let data: DateCellData = serde_json::from_str(&result.unwrap().data)?; - Ok(data) + let serde_cell_data = DateCellDataSerde::from_str(&result.unwrap().data)?; + let time = serde_cell_data.time; + let timestamp = serde_cell_data.timestamp; + let date = self.decode_cell_data_from_timestamp(serde_cell_data.timestamp).content; + + return Ok(DateCellData { date, time, timestamp }); + } + + fn decode_cell_data_from_timestamp(&self, timestamp: i64) -> DecodedCellData { + if timestamp == 0 { + return DecodedCellData::default(); + } + + let cell_content = self.today_desc_from_timestamp(timestamp); + return DecodedCellData::new(timestamp.to_string(), cell_content); + } + + fn timestamp_from_utc_with_time(&self, utc: &chrono::DateTime, time: &str) -> FlowyResult { + let mut date_str = format!( + "{}", + utc.format_with_items(StrftimeItems::new(self.date_format.format_str())) + ); + date_str = date_str.add(&time); + self.timestamp_from_str(&date_str) } } impl CellDataOperation for DateTypeOption { fn decode_cell_data(&self, data: String, _field_meta: &FieldMeta) -> DecodedCellData { if let Ok(type_option_cell_data) = TypeOptionCellData::from_str(&data) { + // Return default data if the type_option_cell_data is not FieldType::DateTime. + // It happens when switching from one field to another. + // For example: + // FieldType::RichText -> FieldType::DateTime, it will display empty content on the screen. if !type_option_cell_data.is_date() { return DecodedCellData::default(); } - - let cell_data = type_option_cell_data.data; - if let Ok(timestamp) = cell_data.parse::() { - return DecodedCellData::new(format!("{}", timestamp), self.today_desc_from_timestamp(timestamp)); - } - - let cell_content = self.today_desc_from_str(cell_data.clone()); - return DecodedCellData::new(cell_data, cell_content); + return match DateCellDataSerde::from_str(&type_option_cell_data.data) { + Ok(serde_cell_data) => self.decode_cell_data_from_timestamp(serde_cell_data.timestamp), + Err(_) => DecodedCellData::default(), + }; } DecodedCellData::default() @@ -119,26 +141,20 @@ impl CellDataOperation for DateTypeOption { _cell_meta: Option, ) -> Result { let content_changeset: DateCellContentChangeset = serde_json::from_str(&changeset.into())?; - let cell_content = match content_changeset.date_timestamp() { - None => "".to_owned(), - Some(date_timestamp) => { - // - match (self.include_time, content_changeset.time) { - (true, Some(time)) => { - let utc = self.utc_date_time_from_timestamp(date_timestamp); - let mut date_str = format!( - "{}", - utc.format_with_items(StrftimeItems::new(self.date_format.format_str())) - ); - date_str = date_str.add(&time); - let timestamp = self.timestamp_from_str(&date_str)?; - timestamp.to_string() - } - _ => date_timestamp.to_string(), + let cell_data = match content_changeset.date_timestamp() { + None => DateCellDataSerde::default(), + Some(date_timestamp) => match (self.include_time, content_changeset.time) { + (true, Some(time)) => { + let time = time.to_uppercase(); + let utc = self.utc_date_time_from_timestamp(date_timestamp); + let timestamp = self.timestamp_from_utc_with_time(&utc, &time)?; + DateCellDataSerde { timestamp, time } } - } + _ => DateCellDataSerde::from_timestamp(date_timestamp), + }, }; - Ok(TypeOptionCellData::new(cell_content, self.field_type()).json()) + + Ok(TypeOptionCellData::new(cell_data.to_string(), self.field_type()).json()) } } @@ -250,13 +266,39 @@ impl std::default::Default for TimeFormat { } } -#[derive(Clone, Debug, Default, ProtoBuf, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, ProtoBuf)] pub struct DateCellData { #[pb(index = 1)] pub date: String, #[pb(index = 2)] pub time: String, + + #[pb(index = 3)] + pub timestamp: i64, +} + +#[derive(Default, Serialize, Deserialize)] +pub struct DateCellDataSerde { + pub timestamp: i64, + pub time: String, +} + +impl DateCellDataSerde { + fn from_timestamp(timestamp: i64) -> Self { + Self { + timestamp, + time: "".to_string(), + } + } + + fn to_string(self) -> String { + serde_json::to_string(&self).unwrap_or("".to_string()) + } + + fn from_str(s: &str) -> FlowyResult { + serde_json::from_str::(s).map_err(internal_error) + } } #[derive(Clone, Debug, Default, ProtoBuf)] @@ -335,7 +377,9 @@ impl std::convert::From for CellContentChangeset { #[cfg(test)] mod tests { use crate::services::field::FieldBuilder; - use crate::services::field::{DateCellContentChangeset, DateFormat, DateTypeOption, TimeFormat}; + use crate::services::field::{ + DateCellContentChangeset, DateCellData, DateCellDataSerde, DateFormat, DateTypeOption, TimeFormat, + }; use crate::services::row::{CellDataOperation, TypeOptionCellData}; use flowy_grid_data_model::entities::FieldType; use strum::IntoEnumIterator; @@ -360,39 +404,25 @@ mod tests { DateFormat::Friendly => { assert_eq!( "Mar 14,2022".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta).content - ); - assert_eq!( - // "Mar 14,2022".to_owned(), - "".to_owned(), - type_option - .decode_cell_data(data("Mar 14,2022 17:56"), &field_meta) - .content + type_option.decode_cell_data(data(1647251762), &field_meta).content ); } DateFormat::US => { assert_eq!( "2022/03/14".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta).content - ); - assert_eq!( - // "2022/03/14".to_owned(), - "".to_owned(), - type_option - .decode_cell_data(data("2022/03/14 17:56"), &field_meta) - .content + type_option.decode_cell_data(data(1647251762), &field_meta).content ); } DateFormat::ISO => { assert_eq!( "2022-03-14".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta).content + type_option.decode_cell_data(data(1647251762), &field_meta).content ); } DateFormat::Local => { assert_eq!( "2022/03/14".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta).content + type_option.decode_cell_data(data(1647251762), &field_meta).content ); } } @@ -413,7 +443,7 @@ mod tests { ); assert_eq!( "Mar 14,2022".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta).content + type_option.decode_cell_data(data(1647251762), &field_meta).content ); } TimeFormat::TwelveHour => { @@ -423,7 +453,39 @@ mod tests { ); assert_eq!( "Mar 14,2022".to_owned(), - type_option.decode_cell_data(data("1647251762"), &field_meta).content + type_option.decode_cell_data(data(1647251762), &field_meta).content + ); + } + } + } + } + + #[test] + fn date_description_time_format_test2() { + let mut type_option = DateTypeOption::default(); + let field_meta = FieldBuilder::from_field_type(&FieldType::Number).build(); + for time_format in TimeFormat::iter() { + type_option.time_format = time_format; + type_option.include_time = true; + match time_format { + TimeFormat::TwentyFourHour => { + assert_eq!( + "May 27,2022 00:00".to_owned(), + type_option.today_desc_from_timestamp(1653609600) + ); + assert_eq!( + "May 27,2022 00:00".to_owned(), + type_option.decode_cell_data(data(1653609600), &field_meta).content + ); + } + TimeFormat::TwelveHour => { + assert_eq!( + "May 27,2022 12:00 AM".to_owned(), + type_option.today_desc_from_timestamp(1653609600) + ); + assert_eq!( + "May 27,2022 12:00 AM".to_owned(), + type_option.decode_cell_data(data(1653609600), &field_meta).content ); } } @@ -494,7 +556,12 @@ mod tests { type_option.apply_changeset("he", None).unwrap(); } - fn data(s: &str) -> String { - TypeOptionCellData::new(s, FieldType::DateTime).json() + fn data(s: i64) -> String { + let json = serde_json::to_string(&DateCellDataSerde { + timestamp: s, + time: "".to_string(), + }) + .unwrap(); + TypeOptionCellData::new(&json, FieldType::DateTime).json() } } From c6edd1a6da1a8fc8b727deb25061bea16e296b60 Mon Sep 17 00:00:00 2001 From: appflowy Date: Fri, 13 May 2022 22:58:49 +0800 Subject: [PATCH 13/14] chore: update data & time format --- .../cell/cell_service/context_builder.dart | 6 +- .../grid/cell/cell_service/data_cache.dart | 22 +- .../grid/cell/cell_service/data_loader.dart | 5 +- .../cell/cell_service/data_persistence.dart | 9 +- .../application/grid/cell/date_cal_bloc.dart | 52 +++-- .../application/grid/cell/date_cell_bloc.dart | 2 - .../src/widgets/cell/date_cell/calendar.dart | 204 ++++++++---------- .../src/widgets/cell/date_cell/date_cell.dart | 1 - .../flowy-error-code/code.pbenum.dart | 4 +- .../flowy-error-code/code.pbjson.dart | 5 +- .../field/type_options/date_type_option.rs | 165 +++++++++----- shared-lib/flowy-error-code/src/code.rs | 5 +- .../src/protobuf/model/code.rs | 14 +- .../src/protobuf/proto/code.proto | 3 +- 14 files changed, 283 insertions(+), 214 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart index 47492ab602..12ec88f219 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart @@ -27,7 +27,7 @@ class GridCellContextBuilder { gridCell: _gridCell, cellCache: _cellCache, cellDataLoader: DateCellDataLoader(gridCell: _gridCell), - cellDataPersistence: NumberCellDataPersistence(gridCell: _gridCell), + cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell), ); case FieldType.Number: return GridCellContext( @@ -120,7 +120,7 @@ class _GridCellContext extends Equatable { _onFieldChangedFn = () { _loadData(); }; - cellCache.addListener(_cacheKey, _onFieldChangedFn!); + cellCache.addFieldListener(_cacheKey, _onFieldChangedFn!); } onCellChangedFn() { @@ -172,7 +172,7 @@ class _GridCellContext extends Equatable { _delayOperation?.cancel(); if (_onFieldChangedFn != null) { - cellCache.removeListener(_cacheKey, _onFieldChangedFn!); + cellCache.removeFieldListener(_cacheKey, _onFieldChangedFn!); _onFieldChangedFn = null; } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart index 71adf0d059..409c236881 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_cache.dart @@ -30,7 +30,7 @@ class GridCellCache { final GridCellFieldDelegate fieldDelegate; /// fieldId: {objectId: callback} - final Map>> _listenerByFieldId = {}; + final Map>> _fieldListenerByFieldId = {}; /// fieldId: {cacheKey: cacheData} final Map> _cellDataByFieldId = {}; @@ -40,7 +40,7 @@ class GridCellCache { }) { fieldDelegate.onFieldChanged((fieldId) { _cellDataByFieldId.remove(fieldId); - final map = _listenerByFieldId[fieldId]; + final map = _fieldListenerByFieldId[fieldId]; if (map != null) { for (final callbacks in map.values) { for (final callback in callbacks) { @@ -51,24 +51,24 @@ class GridCellCache { }); } - void addListener(GridCellCacheKey cacheKey, VoidCallback callback) { - var map = _listenerByFieldId[cacheKey.fieldId]; + void addFieldListener(GridCellCacheKey cacheKey, VoidCallback onFieldChanged) { + var map = _fieldListenerByFieldId[cacheKey.fieldId]; if (map == null) { - _listenerByFieldId[cacheKey.fieldId] = {}; - map = _listenerByFieldId[cacheKey.fieldId]; - map![cacheKey.objectId] = [callback]; + _fieldListenerByFieldId[cacheKey.fieldId] = {}; + map = _fieldListenerByFieldId[cacheKey.fieldId]; + map![cacheKey.objectId] = [onFieldChanged]; } else { var objects = map[cacheKey.objectId]; if (objects == null) { - map[cacheKey.objectId] = [callback]; + map[cacheKey.objectId] = [onFieldChanged]; } else { - objects.add(callback); + objects.add(onFieldChanged); } } } - void removeListener(GridCellCacheKey cacheKey, VoidCallback fn) { - var callbacks = _listenerByFieldId[cacheKey.fieldId]?[cacheKey.objectId]; + void removeFieldListener(GridCellCacheKey cacheKey, VoidCallback fn) { + var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.objectId]; final index = callbacks?.indexWhere((callback) => callback == fn); if (index != null && index != -1) { callbacks?.removeAt(index); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart index c74ee1a8ae..f625af9ad0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_loader.dart @@ -61,12 +61,13 @@ class CellDataLoader extends _GridCellDataLoader { class DateCellDataLoader extends _GridCellDataLoader { final GridCell gridCell; + final GridCellDataConfig _config; DateCellDataLoader({ required this.gridCell, - }); + }) : _config = DefaultCellDataConfig(reloadOnFieldChanged: true); @override - GridCellDataConfig get config => DefaultCellDataConfig(); + GridCellDataConfig get config => _config; @override Future loadData() { diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart index f76d4c607e..2b882fdcbf 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart @@ -35,9 +35,9 @@ class DateCellPersistenceData with _$DateCellPersistenceData { const factory DateCellPersistenceData({required DateTime date, String? time}) = _DateCellPersistenceData; } -class NumberCellDataPersistence implements _GridCellDataPersistence { +class DateCellDataPersistence implements _GridCellDataPersistence { final GridCell gridCell; - NumberCellDataPersistence({ + DateCellDataPersistence({ required this.gridCell, }); @@ -47,10 +47,7 @@ class NumberCellDataPersistence implements _GridCellDataPersistence { (event, emit) async { await event.when( initial: () async => _startListening(), - selectDay: (date) { - _updateDateData(emit, date: date); + selectDay: (date) async { + await _updateDateData(emit, date: date, time: state.time); }, setCalFormat: (format) { emit(state.copyWith(format: format)); @@ -44,22 +44,19 @@ class DateCalBloc extends Bloc { setTimeFormat: (timeFormat) async { await _updateTypeOption(emit, timeFormat: timeFormat); }, - setTime: (time) { - _updateDateData(emit, time: time); + setTime: (time) async { + await _updateDateData(emit, time: time); }, ); }, ); } - void _updateDateData(Emitter emit, {DateTime? date, String? time}) { - state.dateData.fold( + Future _updateDateData(Emitter emit, {DateTime? date, String? time}) { + final DateCellPersistenceData newDateData = state.dateData.fold( () { var newDateData = DateCellPersistenceData(date: date ?? DateTime.now()); - if (time != null) { - newDateData = newDateData.copyWith(time: time); - } - emit(state.copyWith(dateData: Some(newDateData))); + return newDateData.copyWith(time: time); }, (dateData) { var newDateData = dateData; @@ -70,9 +67,34 @@ class DateCalBloc extends Bloc { if (newDateData.time != time) { newDateData = newDateData.copyWith(time: time); } + return newDateData; + }, + ); - if (newDateData != dateData) { - emit(state.copyWith(dateData: Some(newDateData))); + return _saveDateData(emit, newDateData); + } + + Future _saveDateData(Emitter emit, DateCellPersistenceData newDateData) async { + if (state.dateData == Some(newDateData)) { + return; + } + + final result = await cellContext.saveCellData(newDateData); + result.fold( + () => emit(state.copyWith( + dateData: Some(newDateData), + timeFormatError: none(), + )), + (err) { + switch (ErrorCode.valueOf(err.code)!) { + case ErrorCode.InvalidDateTimeFormat: + emit(state.copyWith( + dateData: Some(newDateData), + timeFormatError: Some(err.toString()), + )); + break; + default: + Log.error(err); } }, ); @@ -152,7 +174,7 @@ class DateCalState with _$DateCalState { required CalendarFormat format, required DateTime focusedDay, required String time, - required Option inputTimeError, + required Option timeFormatError, required Option dateData, }) = _DateCalState; @@ -175,7 +197,7 @@ class DateCalState with _$DateCalState { focusedDay: DateTime.now(), dateData: dateData, time: time, - inputTimeError: none(), + timeFormatError: none(), ); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart index 844ba6ca81..4b068dd289 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cell_bloc.dart @@ -16,7 +16,6 @@ class DateCellBloc extends Bloc { (event, emit) async { event.when( initial: () => _startListening(), - selectDate: (DateCellPersistenceData value) => cellContext.saveCellData(value), didReceiveCellUpdate: (DateCellData value) => emit(state.copyWith(data: Some(value))), didReceiveFieldUpdate: (Field value) => emit(state.copyWith(field: value)), ); @@ -48,7 +47,6 @@ class DateCellBloc extends Bloc { @freezed class DateCellEvent with _$DateCellEvent { const factory DateCellEvent.initial() = _InitialCell; - const factory DateCellEvent.selectDate(DateCellPersistenceData data) = _SelectDay; const factory DateCellEvent.didReceiveCellUpdate(DateCellData data) = _DidReceiveCellUpdate; const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate; } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 878aac6b94..6217eaa53d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -32,7 +32,6 @@ class CellCalendar with FlowyOverlayDelegate { Future show( BuildContext context, { required GridDateCellContext cellContext, - required void Function(DateCellPersistenceData) onSelected, }) async { CellCalendar.remove(context); @@ -49,7 +48,6 @@ class CellCalendar with FlowyOverlayDelegate { // } final calendar = _CellCalendarWidget( - onSelected: onSelected, cellContext: cellContext, dateTypeOption: typeOptionData, ); @@ -88,10 +86,8 @@ class CellCalendar with FlowyOverlayDelegate { class _CellCalendarWidget extends StatelessWidget { final GridDateCellContext cellContext; final DateTypeOption dateTypeOption; - final void Function(DateCellPersistenceData) onSelected; const _CellCalendarWidget({ - required this.onSelected, required this.cellContext, required this.dateTypeOption, Key? key, @@ -108,40 +104,16 @@ class _CellCalendarWidget extends StatelessWidget { cellContext: cellContext, )..add(const DateCalEvent.initial()); }, - child: BlocConsumer( - listener: (context, state) { - state.dateData.fold( - () => null, - (dateData) => onSelected(dateData), - ); - }, - listenWhen: (p, c) => p.dateData != c.dateData, + child: BlocBuilder( + buildWhen: (p, c) => false, builder: (context, state) { - List children = []; - - children.addAll([ - _buildCalendar(state, theme, context), - const VSpace(10), - ]); - - if (state.dateTypeOption.includeTime) { - children.addAll([ - _TimeTextField( - text: state.time, - errorText: state.inputTimeError.fold(() => "", (error) => error.toString()), - onEditingComplete: (text) { - context.read().add(DateCalEvent.setTime(text)); - }, - ), - ]); - } - - children.addAll([ + List children = [ + _buildCalendar(theme, context), + _TimeTextField(bloc: context.read()), Divider(height: 1, color: theme.shader5), const _IncludeTimeButton(), - ]); - - children.add(const _DateTypeOptionButton()); + const _DateTypeOptionButton() + ]; return ListView.separated( shrinkWrap: true, @@ -159,56 +131,60 @@ class _CellCalendarWidget extends StatelessWidget { ); } - TableCalendar _buildCalendar(DateCalState state, AppTheme theme, BuildContext context) { - return TableCalendar( - firstDay: kFirstDay, - lastDay: kLastDay, - focusedDay: state.focusedDay, - rowHeight: 40, - calendarFormat: state.format, - headerStyle: HeaderStyle( - formatButtonVisible: false, - titleCentered: true, - leftChevronMargin: EdgeInsets.zero, - leftChevronPadding: EdgeInsets.zero, - leftChevronIcon: svgWidget("home/arrow_left"), - rightChevronPadding: EdgeInsets.zero, - rightChevronMargin: EdgeInsets.zero, - rightChevronIcon: svgWidget("home/arrow_right"), - ), - calendarStyle: CalendarStyle( - selectedDecoration: BoxDecoration( - color: theme.main1, - shape: BoxShape.circle, - ), - todayDecoration: BoxDecoration( - color: theme.shader4, - shape: BoxShape.circle, - ), - selectedTextStyle: TextStyle( - color: theme.surface, - fontSize: 14.0, - ), - todayTextStyle: TextStyle( - color: theme.surface, - fontSize: 14.0, - ), - ), - selectedDayPredicate: (day) { - return state.dateData.fold( - () => false, - (dateData) => isSameDay(dateData.date, day), + Widget _buildCalendar(AppTheme theme, BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return TableCalendar( + firstDay: kFirstDay, + lastDay: kLastDay, + focusedDay: state.focusedDay, + rowHeight: 40, + calendarFormat: state.format, + headerStyle: HeaderStyle( + formatButtonVisible: false, + titleCentered: true, + leftChevronMargin: EdgeInsets.zero, + leftChevronPadding: EdgeInsets.zero, + leftChevronIcon: svgWidget("home/arrow_left"), + rightChevronPadding: EdgeInsets.zero, + rightChevronMargin: EdgeInsets.zero, + rightChevronIcon: svgWidget("home/arrow_right"), + ), + calendarStyle: CalendarStyle( + selectedDecoration: BoxDecoration( + color: theme.main1, + shape: BoxShape.circle, + ), + todayDecoration: BoxDecoration( + color: theme.shader4, + shape: BoxShape.circle, + ), + selectedTextStyle: TextStyle( + color: theme.surface, + fontSize: 14.0, + ), + todayTextStyle: TextStyle( + color: theme.surface, + fontSize: 14.0, + ), + ), + selectedDayPredicate: (day) { + return state.dateData.fold( + () => false, + (dateData) => isSameDay(dateData.date, day), + ); + }, + onDaySelected: (selectedDay, focusedDay) { + context.read().add(DateCalEvent.selectDay(selectedDay)); + }, + onFormatChanged: (format) { + context.read().add(DateCalEvent.setCalFormat(format)); + }, + onPageChanged: (focusedDay) { + context.read().add(DateCalEvent.setFocusedDay(focusedDay)); + }, ); }, - onDaySelected: (selectedDay, focusedDay) { - context.read().add(DateCalEvent.selectDay(selectedDay)); - }, - onFormatChanged: (format) { - context.read().add(DateCalEvent.setCalFormat(format)); - }, - onPageChanged: (focusedDay) { - context.read().add(DateCalEvent.setFocusedDay(focusedDay)); - }, ); } } @@ -246,14 +222,10 @@ class _IncludeTimeButton extends StatelessWidget { } class _TimeTextField extends StatefulWidget { - final String errorText; - final String text; - final void Function(String) onEditingComplete; + final DateCalBloc bloc; const _TimeTextField({ + required this.bloc, Key? key, - required this.text, - required this.errorText, - required this.onEditingComplete, }) : super(key: key); @override @@ -267,33 +239,45 @@ class _TimeTextFieldState extends State<_TimeTextField> { @override void initState() { _focusNode = FocusNode(); - _controller = TextEditingController(text: widget.text); - _focusNode.addListener(() { - if (mounted) { - widget.onEditingComplete(_controller.text); - } - }); + _controller = TextEditingController(text: widget.bloc.state.time); + if (widget.bloc.state.dateTypeOption.includeTime) { + _focusNode.addListener(() { + if (mounted) { + widget.bloc.add(DateCalEvent.setTime(_controller.text)); + } + }); + } + super.initState(); } @override Widget build(BuildContext context) { final theme = context.watch(); - return Padding( - padding: kMargin, - child: RoundedInputField( - height: 40, - focusNode: _focusNode, - controller: _controller, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), - normalBorderColor: theme.shader4, - errorBorderColor: theme.red, - cursorColor: theme.main1, - errorText: widget.errorText, - onEditingComplete: (value) { - widget.onEditingComplete(value); - }, - ), + return BlocBuilder( + builder: (context, state) { + if (state.dateTypeOption.includeTime) { + return Padding( + padding: kMargin, + child: RoundedInputField( + height: 40, + focusNode: _focusNode, + controller: _controller, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + normalBorderColor: theme.shader4, + errorBorderColor: theme.red, + focusBorderColor: theme.main1, + cursorColor: theme.main1, + errorText: state.timeFormatError.fold(() => "", (error) => error), + onEditingComplete: (value) { + widget.bloc.add(DateCalEvent.setTime(value)); + }, + ), + ); + } else { + return const SizedBox(); + } + }, ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart index e69f7cf10a..d1d15ea4b3 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/date_cell.dart @@ -81,7 +81,6 @@ class _DateCellState extends State { calendar.show( context, cellContext: bloc.cellContext.clone(), - onSelected: (data) => bloc.add(DateCellEvent.selectDate(data)), ); } diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbenum.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbenum.dart index 0d1eabddf8..295a485d01 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbenum.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbenum.dart @@ -52,7 +52,8 @@ class ErrorCode extends $pb.ProtobufEnum { static const ErrorCode FieldNotExists = ErrorCode._(443, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FieldNotExists'); static const ErrorCode FieldInvalidOperation = ErrorCode._(444, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FieldInvalidOperation'); static const ErrorCode TypeOptionDataIsEmpty = ErrorCode._(450, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'TypeOptionDataIsEmpty'); - static const ErrorCode InvalidData = ErrorCode._(500, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InvalidData'); + static const ErrorCode InvalidDateTimeFormat = ErrorCode._(500, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InvalidDateTimeFormat'); + static const ErrorCode InvalidData = ErrorCode._(1000, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'InvalidData'); static const $core.List values = [ Internal, @@ -97,6 +98,7 @@ class ErrorCode extends $pb.ProtobufEnum { FieldNotExists, FieldInvalidOperation, TypeOptionDataIsEmpty, + InvalidDateTimeFormat, InvalidData, ]; diff --git a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbjson.dart b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbjson.dart index fa6ba4076b..1d3717a2b5 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbjson.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/protobuf/flowy-error-code/code.pbjson.dart @@ -54,9 +54,10 @@ const ErrorCode$json = const { const {'1': 'FieldNotExists', '2': 443}, const {'1': 'FieldInvalidOperation', '2': 444}, const {'1': 'TypeOptionDataIsEmpty', '2': 450}, - const {'1': 'InvalidData', '2': 500}, + const {'1': 'InvalidDateTimeFormat', '2': 500}, + const {'1': 'InvalidData', '2': 1000}, ], }; /// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSDAoISW50ZXJuYWwQABIUChBVc2VyVW5hdXRob3JpemVkEAISEgoOUmVjb3JkTm90Rm91bmQQAxIRCg1Vc2VySWRJc0VtcHR5EAQSGAoUV29ya3NwYWNlTmFtZUludmFsaWQQZBIWChJXb3Jrc3BhY2VJZEludmFsaWQQZRIYChRBcHBDb2xvclN0eWxlSW52YWxpZBBmEhgKFFdvcmtzcGFjZURlc2NUb29Mb25nEGcSGAoUV29ya3NwYWNlTmFtZVRvb0xvbmcQaBIQCgxBcHBJZEludmFsaWQQbhISCg5BcHBOYW1lSW52YWxpZBBvEhMKD1ZpZXdOYW1lSW52YWxpZBB4EhgKFFZpZXdUaHVtYm5haWxJbnZhbGlkEHkSEQoNVmlld0lkSW52YWxpZBB6EhMKD1ZpZXdEZXNjVG9vTG9uZxB7EhMKD1ZpZXdEYXRhSW52YWxpZBB8EhMKD1ZpZXdOYW1lVG9vTG9uZxB9EhEKDENvbm5lY3RFcnJvchDIARIRCgxFbWFpbElzRW1wdHkQrAISFwoSRW1haWxGb3JtYXRJbnZhbGlkEK0CEhcKEkVtYWlsQWxyZWFkeUV4aXN0cxCuAhIUCg9QYXNzd29yZElzRW1wdHkQrwISFAoPUGFzc3dvcmRUb29Mb25nELACEiUKIFBhc3N3b3JkQ29udGFpbnNGb3JiaWRDaGFyYWN0ZXJzELECEhoKFVBhc3N3b3JkRm9ybWF0SW52YWxpZBCyAhIVChBQYXNzd29yZE5vdE1hdGNoELMCEhQKD1VzZXJOYW1lVG9vTG9uZxC0AhInCiJVc2VyTmFtZUNvbnRhaW5Gb3JiaWRkZW5DaGFyYWN0ZXJzELUCEhQKD1VzZXJOYW1lSXNFbXB0eRC2AhISCg1Vc2VySWRJbnZhbGlkELcCEhEKDFVzZXJOb3RFeGlzdBC4AhIQCgtUZXh0VG9vTG9uZxCQAxISCg1HcmlkSWRJc0VtcHR5EJoDEhMKDkJsb2NrSWRJc0VtcHR5EKQDEhEKDFJvd0lkSXNFbXB0eRCuAxIUCg9PcHRpb25JZElzRW1wdHkQrwMSEwoORmllbGRJZElzRW1wdHkQuAMSFgoRRmllbGREb2VzTm90RXhpc3QQuQMSHAoXU2VsZWN0T3B0aW9uTmFtZUlzRW1wdHkQugMSEwoORmllbGROb3RFeGlzdHMQuwMSGgoVRmllbGRJbnZhbGlkT3BlcmF0aW9uELwDEhoKFVR5cGVPcHRpb25EYXRhSXNFbXB0eRDCAxIQCgtJbnZhbGlkRGF0YRD0Aw=='); +final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSDAoISW50ZXJuYWwQABIUChBVc2VyVW5hdXRob3JpemVkEAISEgoOUmVjb3JkTm90Rm91bmQQAxIRCg1Vc2VySWRJc0VtcHR5EAQSGAoUV29ya3NwYWNlTmFtZUludmFsaWQQZBIWChJXb3Jrc3BhY2VJZEludmFsaWQQZRIYChRBcHBDb2xvclN0eWxlSW52YWxpZBBmEhgKFFdvcmtzcGFjZURlc2NUb29Mb25nEGcSGAoUV29ya3NwYWNlTmFtZVRvb0xvbmcQaBIQCgxBcHBJZEludmFsaWQQbhISCg5BcHBOYW1lSW52YWxpZBBvEhMKD1ZpZXdOYW1lSW52YWxpZBB4EhgKFFZpZXdUaHVtYm5haWxJbnZhbGlkEHkSEQoNVmlld0lkSW52YWxpZBB6EhMKD1ZpZXdEZXNjVG9vTG9uZxB7EhMKD1ZpZXdEYXRhSW52YWxpZBB8EhMKD1ZpZXdOYW1lVG9vTG9uZxB9EhEKDENvbm5lY3RFcnJvchDIARIRCgxFbWFpbElzRW1wdHkQrAISFwoSRW1haWxGb3JtYXRJbnZhbGlkEK0CEhcKEkVtYWlsQWxyZWFkeUV4aXN0cxCuAhIUCg9QYXNzd29yZElzRW1wdHkQrwISFAoPUGFzc3dvcmRUb29Mb25nELACEiUKIFBhc3N3b3JkQ29udGFpbnNGb3JiaWRDaGFyYWN0ZXJzELECEhoKFVBhc3N3b3JkRm9ybWF0SW52YWxpZBCyAhIVChBQYXNzd29yZE5vdE1hdGNoELMCEhQKD1VzZXJOYW1lVG9vTG9uZxC0AhInCiJVc2VyTmFtZUNvbnRhaW5Gb3JiaWRkZW5DaGFyYWN0ZXJzELUCEhQKD1VzZXJOYW1lSXNFbXB0eRC2AhISCg1Vc2VySWRJbnZhbGlkELcCEhEKDFVzZXJOb3RFeGlzdBC4AhIQCgtUZXh0VG9vTG9uZxCQAxISCg1HcmlkSWRJc0VtcHR5EJoDEhMKDkJsb2NrSWRJc0VtcHR5EKQDEhEKDFJvd0lkSXNFbXB0eRCuAxIUCg9PcHRpb25JZElzRW1wdHkQrwMSEwoORmllbGRJZElzRW1wdHkQuAMSFgoRRmllbGREb2VzTm90RXhpc3QQuQMSHAoXU2VsZWN0T3B0aW9uTmFtZUlzRW1wdHkQugMSEwoORmllbGROb3RFeGlzdHMQuwMSGgoVRmllbGRJbnZhbGlkT3BlcmF0aW9uELwDEhoKFVR5cGVPcHRpb25EYXRhSXNFbXB0eRDCAxIaChVJbnZhbGlkRGF0ZVRpbWVGb3JtYXQQ9AMSEAoLSW52YWxpZERhdGEQ6Ac='); diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 778076d8e5..84bb5a517b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -5,6 +5,7 @@ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellD use bytes::Bytes; use chrono::format::strftime::StrftimeItems; use chrono::NaiveDateTime; +use diesel::types::Time; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{ @@ -30,37 +31,28 @@ pub struct DateTypeOption { impl_type_option!(DateTypeOption, FieldType::DateTime); impl DateTypeOption { - fn today_desc_from_timestamp(&self, timestamp: i64) -> String { + fn today_desc_from_timestamp(&self, timestamp: i64, time: &Option) -> String { let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0); - self.today_desc_from_native(native) + self.today_desc_from_native(native, time) } #[allow(dead_code)] - fn today_desc_from_str(&self, s: String) -> String { - match NaiveDateTime::parse_from_str(&s, &self.fmt_str()) { - Ok(native) => self.today_desc_from_native(native), + fn today_desc_from_str(&self, s: String, time: &Option) -> String { + match NaiveDateTime::parse_from_str(&s, &self.date_fmt(time)) { + Ok(native) => self.today_desc_from_native(native, time), Err(_) => "".to_owned(), } } - fn today_desc_from_native(&self, native: chrono::NaiveDateTime) -> String { + fn today_desc_from_native(&self, native: chrono::NaiveDateTime, time: &Option) -> String { let utc = self.utc_date_time_from_native(native); // let china_timezone = FixedOffset::east(8 * 3600); // let a = utc.with_timezone(&china_timezone); - let output = format!("{}", utc.format_with_items(StrftimeItems::new(&self.fmt_str()))); + let fmt = self.date_fmt(time); + let output = format!("{}", utc.format_with_items(StrftimeItems::new(&fmt))); output } - fn timestamp_from_str(&self, s: &str) -> FlowyResult { - match NaiveDateTime::parse_from_str(s, &self.fmt_str()) { - Ok(native) => { - let utc = self.utc_date_time_from_native(native); - Ok(utc.timestamp()) - } - Err(_) => Err(ErrorCode::InvalidData.into()), - } - } - fn utc_date_time_from_timestamp(&self, timestamp: i64) -> chrono::DateTime { let native = NaiveDateTime::from_timestamp(timestamp, 0); self.utc_date_time_from_native(native) @@ -70,9 +62,18 @@ impl DateTypeOption { chrono::DateTime::::from_utc(naive, chrono::Utc) } - fn fmt_str(&self) -> String { + fn date_fmt(&self, time: &Option) -> String { if self.include_time { - format!("{} {}", self.date_format.format_str(), self.time_format.format_str()) + match time.as_ref() { + None => self.date_format.format_str().to_string(), + Some(time_str) => { + if time_str.is_empty() { + self.date_format.format_str().to_string() + } else { + format!("{} {}", self.date_format.format_str(), self.time_format.format_str()) + } + } + } } else { self.date_format.format_str().to_string() } @@ -90,29 +91,48 @@ impl DateTypeOption { } let serde_cell_data = DateCellDataSerde::from_str(&result.unwrap().data)?; - let time = serde_cell_data.time; + let date = self.decode_cell_data_from_timestamp(&serde_cell_data).content; + let time = serde_cell_data.time.unwrap_or("".to_owned()); let timestamp = serde_cell_data.timestamp; - let date = self.decode_cell_data_from_timestamp(serde_cell_data.timestamp).content; return Ok(DateCellData { date, time, timestamp }); } - fn decode_cell_data_from_timestamp(&self, timestamp: i64) -> DecodedCellData { - if timestamp == 0 { + fn decode_cell_data_from_timestamp(&self, serde_cell_data: &DateCellDataSerde) -> DecodedCellData { + if serde_cell_data.timestamp == 0 { return DecodedCellData::default(); } - let cell_content = self.today_desc_from_timestamp(timestamp); - return DecodedCellData::new(timestamp.to_string(), cell_content); + let cell_content = self.today_desc_from_timestamp(serde_cell_data.timestamp, &serde_cell_data.time); + return DecodedCellData::new(serde_cell_data.timestamp.to_string(), cell_content); } - fn timestamp_from_utc_with_time(&self, utc: &chrono::DateTime, time: &str) -> FlowyResult { + fn timestamp_from_utc_with_time( + &self, + utc: &chrono::DateTime, + time: &Option, + ) -> FlowyResult { let mut date_str = format!( "{}", utc.format_with_items(StrftimeItems::new(self.date_format.format_str())) ); - date_str = date_str.add(&time); - self.timestamp_from_str(&date_str) + + if let Some(time_str) = time.as_ref() { + if !time_str.is_empty() { + date_str = date_str.add(&time_str); + } + } + let fmt = self.date_fmt(time); + match NaiveDateTime::parse_from_str(&date_str, &fmt) { + Ok(native) => { + let utc = self.utc_date_time_from_native(native); + Ok(utc.timestamp()) + } + Err(_e) => { + let msg = format!("Parse {} with format: {} failed", date_str, fmt); + Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg)) + } + } } } @@ -127,7 +147,7 @@ impl CellDataOperation for DateTypeOption { return DecodedCellData::default(); } return match DateCellDataSerde::from_str(&type_option_cell_data.data) { - Ok(serde_cell_data) => self.decode_cell_data_from_timestamp(serde_cell_data.timestamp), + Ok(serde_cell_data) => self.decode_cell_data_from_timestamp(&serde_cell_data), Err(_) => DecodedCellData::default(), }; } @@ -145,12 +165,12 @@ impl CellDataOperation for DateTypeOption { None => DateCellDataSerde::default(), Some(date_timestamp) => match (self.include_time, content_changeset.time) { (true, Some(time)) => { - let time = time.to_uppercase(); + let time = Some(time.trim().to_uppercase()); let utc = self.utc_date_time_from_timestamp(date_timestamp); let timestamp = self.timestamp_from_utc_with_time(&utc, &time)?; - DateCellDataSerde { timestamp, time } + DateCellDataSerde::new(timestamp, time, &self.time_format) } - _ => DateCellDataSerde::from_timestamp(date_timestamp), + _ => DateCellDataSerde::from_timestamp(date_timestamp, &self.time_format), }, }; @@ -281,14 +301,21 @@ pub struct DateCellData { #[derive(Default, Serialize, Deserialize)] pub struct DateCellDataSerde { pub timestamp: i64, - pub time: String, + pub time: Option, } impl DateCellDataSerde { - fn from_timestamp(timestamp: i64) -> Self { + fn new(timestamp: i64, time: Option, time_format: &TimeFormat) -> Self { Self { timestamp, - time: "".to_string(), + time: Some(time.unwrap_or(default_time_str(time_format))), + } + } + + fn from_timestamp(timestamp: i64, time_format: &TimeFormat) -> Self { + Self { + timestamp, + time: Some(default_time_str(time_format)), } } @@ -301,6 +328,13 @@ impl DateCellDataSerde { } } +fn default_time_str(time_format: &TimeFormat) -> String { + match time_format { + TimeFormat::TwelveHour => "12:00 AM".to_string(), + TimeFormat::TwentyFourHour => "00:00".to_string(), + } +} + #[derive(Clone, Debug, Default, ProtoBuf)] pub struct DateChangesetPayload { #[pb(index = 1)] @@ -439,7 +473,7 @@ mod tests { TimeFormat::TwentyFourHour => { assert_eq!( "Mar 14,2022".to_owned(), - type_option.today_desc_from_timestamp(1647251762) + type_option.today_desc_from_timestamp(1647251762, &None) ); assert_eq!( "Mar 14,2022".to_owned(), @@ -449,7 +483,7 @@ mod tests { TimeFormat::TwelveHour => { assert_eq!( "Mar 14,2022".to_owned(), - type_option.today_desc_from_timestamp(1647251762) + type_option.today_desc_from_timestamp(1647251762, &None) ); assert_eq!( "Mar 14,2022".to_owned(), @@ -469,24 +503,47 @@ mod tests { type_option.include_time = true; match time_format { TimeFormat::TwentyFourHour => { - assert_eq!( - "May 27,2022 00:00".to_owned(), - type_option.today_desc_from_timestamp(1653609600) - ); - assert_eq!( - "May 27,2022 00:00".to_owned(), - type_option.decode_cell_data(data(1653609600), &field_meta).content - ); + let changeset = DateCellContentChangeset { + date: Some(1653609600.to_string()), + time: None, + }; + let result = type_option.apply_changeset(changeset, None).unwrap(); + let content = type_option.decode_cell_data(result, &field_meta).content; + assert_eq!("May 27,2022 00:00".to_owned(), content); + + let changeset = DateCellContentChangeset { + date: Some(1653609600.to_string()), + time: Some("23:00".to_owned()), + }; + + let result = type_option.apply_changeset(changeset, None).unwrap(); + let content = type_option.decode_cell_data(result, &field_meta).content; + assert_eq!("May 27,2022 23:00".to_owned(), content); } TimeFormat::TwelveHour => { - assert_eq!( - "May 27,2022 12:00 AM".to_owned(), - type_option.today_desc_from_timestamp(1653609600) - ); - assert_eq!( - "May 27,2022 12:00 AM".to_owned(), - type_option.decode_cell_data(data(1653609600), &field_meta).content - ); + let changeset = DateCellContentChangeset { + date: Some(1653609600.to_string()), + time: None, + }; + let result = type_option.apply_changeset(changeset, None).unwrap(); + let content = type_option.decode_cell_data(result, &field_meta).content; + assert_eq!("May 27,2022 12:00 AM".to_owned(), content); + + let changeset = DateCellContentChangeset { + date: Some(1653609600.to_string()), + time: Some("".to_owned()), + }; + let result = type_option.apply_changeset(changeset, None).unwrap(); + let content = type_option.decode_cell_data(result, &field_meta).content; + assert_eq!("May 27,2022".to_owned(), content); + + let changeset = DateCellContentChangeset { + date: Some(1653609600.to_string()), + time: Some("11:23 pm".to_owned()), + }; + let result = type_option.apply_changeset(changeset, None).unwrap(); + let content = type_option.decode_cell_data(result, &field_meta).content; + assert_eq!("May 27,2022 11:23 PM".to_owned(), content); } } } @@ -559,7 +616,7 @@ mod tests { fn data(s: i64) -> String { let json = serde_json::to_string(&DateCellDataSerde { timestamp: s, - time: "".to_string(), + time: None, }) .unwrap(); TypeOptionCellData::new(&json, FieldType::DateTime).json() diff --git a/shared-lib/flowy-error-code/src/code.rs b/shared-lib/flowy-error-code/src/code.rs index 0315306871..8941684948 100644 --- a/shared-lib/flowy-error-code/src/code.rs +++ b/shared-lib/flowy-error-code/src/code.rs @@ -111,8 +111,11 @@ pub enum ErrorCode { #[display(fmt = "Field's type option data should not be empty")] TypeOptionDataIsEmpty = 450, + #[display(fmt = "Invalid date time format")] + InvalidDateTimeFormat = 500, + #[display(fmt = "Invalid data")] - InvalidData = 500, + InvalidData = 1000, } impl ErrorCode { diff --git a/shared-lib/flowy-error-code/src/protobuf/model/code.rs b/shared-lib/flowy-error-code/src/protobuf/model/code.rs index 5653852147..5274a61d74 100644 --- a/shared-lib/flowy-error-code/src/protobuf/model/code.rs +++ b/shared-lib/flowy-error-code/src/protobuf/model/code.rs @@ -67,7 +67,8 @@ pub enum ErrorCode { FieldNotExists = 443, FieldInvalidOperation = 444, TypeOptionDataIsEmpty = 450, - InvalidData = 500, + InvalidDateTimeFormat = 500, + InvalidData = 1000, } impl ::protobuf::ProtobufEnum for ErrorCode { @@ -119,7 +120,8 @@ impl ::protobuf::ProtobufEnum for ErrorCode { 443 => ::std::option::Option::Some(ErrorCode::FieldNotExists), 444 => ::std::option::Option::Some(ErrorCode::FieldInvalidOperation), 450 => ::std::option::Option::Some(ErrorCode::TypeOptionDataIsEmpty), - 500 => ::std::option::Option::Some(ErrorCode::InvalidData), + 500 => ::std::option::Option::Some(ErrorCode::InvalidDateTimeFormat), + 1000 => ::std::option::Option::Some(ErrorCode::InvalidData), _ => ::std::option::Option::None } } @@ -168,6 +170,7 @@ impl ::protobuf::ProtobufEnum for ErrorCode { ErrorCode::FieldNotExists, ErrorCode::FieldInvalidOperation, ErrorCode::TypeOptionDataIsEmpty, + ErrorCode::InvalidDateTimeFormat, ErrorCode::InvalidData, ]; values @@ -197,7 +200,7 @@ impl ::protobuf::reflect::ProtobufValue for ErrorCode { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\ncode.proto*\xe5\x07\n\tErrorCode\x12\x0c\n\x08Internal\x10\0\x12\x14\ + \n\ncode.proto*\x81\x08\n\tErrorCode\x12\x0c\n\x08Internal\x10\0\x12\x14\ \n\x10UserUnauthorized\x10\x02\x12\x12\n\x0eRecordNotFound\x10\x03\x12\ \x11\n\rUserIdIsEmpty\x10\x04\x12\x18\n\x14WorkspaceNameInvalid\x10d\x12\ \x16\n\x12WorkspaceIdInvalid\x10e\x12\x18\n\x14AppColorStyleInvalid\x10f\ @@ -220,8 +223,9 @@ static file_descriptor_proto_data: &'static [u8] = b"\ \x12\x13\n\x0eFieldIdIsEmpty\x10\xb8\x03\x12\x16\n\x11FieldDoesNotExist\ \x10\xb9\x03\x12\x1c\n\x17SelectOptionNameIsEmpty\x10\xba\x03\x12\x13\n\ \x0eFieldNotExists\x10\xbb\x03\x12\x1a\n\x15FieldInvalidOperation\x10\ - \xbc\x03\x12\x1a\n\x15TypeOptionDataIsEmpty\x10\xc2\x03\x12\x10\n\x0bInv\ - alidData\x10\xf4\x03b\x06proto3\ + \xbc\x03\x12\x1a\n\x15TypeOptionDataIsEmpty\x10\xc2\x03\x12\x1a\n\x15Inv\ + alidDateTimeFormat\x10\xf4\x03\x12\x10\n\x0bInvalidData\x10\xe8\x07b\x06\ + proto3\ "; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; diff --git a/shared-lib/flowy-error-code/src/protobuf/proto/code.proto b/shared-lib/flowy-error-code/src/protobuf/proto/code.proto index aca3309526..e49862205f 100644 --- a/shared-lib/flowy-error-code/src/protobuf/proto/code.proto +++ b/shared-lib/flowy-error-code/src/protobuf/proto/code.proto @@ -43,5 +43,6 @@ enum ErrorCode { FieldNotExists = 443; FieldInvalidOperation = 444; TypeOptionDataIsEmpty = 450; - InvalidData = 500; + InvalidDateTimeFormat = 500; + InvalidData = 1000; } From afc563d7815994b473ef658f02a9fbb3302af244 Mon Sep 17 00:00:00 2001 From: appflowy Date: Sat, 14 May 2022 10:50:11 +0800 Subject: [PATCH 14/14] chore: fix unit test --- .../cell/cell_service/context_builder.dart | 2 +- .../cell/cell_service/data_persistence.dart | 13 +++-- .../application/grid/cell/date_cal_bloc.dart | 58 ++++++++++++------- .../src/widgets/cell/date_cell/calendar.dart | 6 +- .../rust-lib/flowy-grid/src/event_handler.rs | 2 +- .../field/type_options/date_type_option.rs | 54 ++++++++--------- .../field/type_options/text_type_option.rs | 3 +- .../flowy-grid/tests/grid/grid_test.rs | 27 ++++++--- 8 files changed, 97 insertions(+), 68 deletions(-) diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart index 12ec88f219..c7faff5311 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/context_builder.dart @@ -2,7 +2,7 @@ part of 'cell_service.dart'; typedef GridCellContext = _GridCellContext; typedef GridSelectOptionCellContext = _GridCellContext; -typedef GridDateCellContext = _GridCellContext; +typedef GridDateCellContext = _GridCellContext; class GridCellContextBuilder { final GridCellCache _cellCache; diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart index 2b882fdcbf..e09a528e44 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/cell_service/data_persistence.dart @@ -31,23 +31,26 @@ class CellDataPersistence implements _GridCellDataPersistence { } @freezed -class DateCellPersistenceData with _$DateCellPersistenceData { - const factory DateCellPersistenceData({required DateTime date, String? time}) = _DateCellPersistenceData; +class DateCalData with _$DateCalData { + const factory DateCalData({required DateTime date, String? time}) = _DateCellPersistenceData; } -class DateCellDataPersistence implements _GridCellDataPersistence { +class DateCellDataPersistence implements _GridCellDataPersistence { final GridCell gridCell; DateCellDataPersistence({ required this.gridCell, }); @override - Future> save(DateCellPersistenceData data) { + Future> save(DateCalData data) { var payload = DateChangesetPayload.create()..cellIdentifier = _cellIdentifier(gridCell); final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString(); payload.date = date; - payload.time = data.time ?? ""; + + if (data.time != null) { + payload.time = data.time!; + } return GridEventUpdateDateCell(payload).send().then((result) { return result.fold( diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart index 0e9b4af554..a0ba35f9d6 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/date_cal_bloc.dart @@ -9,7 +9,7 @@ import 'dart:async'; import 'cell_service/cell_service.dart'; import 'package:dartz/dartz.dart'; import 'package:protobuf/protobuf.dart'; -// import 'package:fixnum/fixnum.dart' as $fixnum; +import 'package:fixnum/fixnum.dart' as $fixnum; part 'date_cal_bloc.freezed.dart'; class DateCalBloc extends Bloc { @@ -34,7 +34,11 @@ class DateCalBloc extends Bloc { setFocusedDay: (focusedDay) { emit(state.copyWith(focusedDay: focusedDay)); }, - didReceiveCellUpdate: (value) {}, + didReceiveCellUpdate: (DateCellData cellData) { + final dateData = dateDataFromCellData(cellData); + final time = dateData.foldRight("", (dateData, previous) => dateData.time); + emit(state.copyWith(dateData: dateData, time: time)); + }, setIncludeTime: (includeTime) async { await _updateTypeOption(emit, includeTime: includeTime); }, @@ -53,11 +57,8 @@ class DateCalBloc extends Bloc { } Future _updateDateData(Emitter emit, {DateTime? date, String? time}) { - final DateCellPersistenceData newDateData = state.dateData.fold( - () { - var newDateData = DateCellPersistenceData(date: date ?? DateTime.now()); - return newDateData.copyWith(time: time); - }, + final DateCalData newDateData = state.dateData.fold( + () => DateCalData(date: date ?? DateTime.now(), time: time), (dateData) { var newDateData = dateData; if (date != null && !isSameDay(newDateData.date, date)) { @@ -74,7 +75,7 @@ class DateCalBloc extends Bloc { return _saveDateData(emit, newDateData); } - Future _saveDateData(Emitter emit, DateCellPersistenceData newDateData) async { + Future _saveDateData(Emitter emit, DateCalData newDateData) async { if (state.dateData == Some(newDateData)) { return; } @@ -173,31 +174,48 @@ class DateCalState with _$DateCalState { required DateTypeOption dateTypeOption, required CalendarFormat format, required DateTime focusedDay, - required String time, required Option timeFormatError, - required Option dateData, + required Option dateData, + required String? time, }) = _DateCalState; factory DateCalState.initial( DateTypeOption dateTypeOption, DateCellData? cellData, ) { - Option dateData = none(); - final time = cellData?.time ?? ""; - if (cellData != null) { - // final timestamp = $fixnum.Int64.parseInt(cellData.timestamp).toInt(); - final timestamp = cellData.timestamp * 1000; - final selectedDay = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt()); - dateData = Some(DateCellPersistenceData(date: selectedDay, time: time)); - } - + Option dateData = dateDataFromCellData(cellData); + final time = dateData.foldRight("", (dateData, previous) => dateData.time); return DateCalState( dateTypeOption: dateTypeOption, format: CalendarFormat.month, focusedDay: DateTime.now(), - dateData: dateData, time: time, + dateData: dateData, timeFormatError: none(), ); } } + +Option dateDataFromCellData(DateCellData? cellData) { + String? time = timeFromCellData(cellData); + Option dateData = none(); + if (cellData != null) { + final timestamp = cellData.timestamp * 1000; + final date = DateTime.fromMillisecondsSinceEpoch(timestamp.toInt()); + dateData = Some(DateCalData(date: date, time: time)); + } + return dateData; +} + +$fixnum.Int64 timestampFromDateTime(DateTime dateTime) { + final timestamp = (dateTime.millisecondsSinceEpoch ~/ 1000); + return $fixnum.Int64(timestamp); +} + +String? timeFromCellData(DateCellData? cellData) { + String? time; + if (cellData?.hasTime() ?? false) { + time = cellData?.time; + } + return time; +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart index 6217eaa53d..c19e8c3001 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell/calendar.dart @@ -254,7 +254,11 @@ class _TimeTextFieldState extends State<_TimeTextField> { @override Widget build(BuildContext context) { final theme = context.watch(); - return BlocBuilder( + return BlocConsumer( + listener: (context, state) { + _controller.text = state.time ?? ""; + }, + listenWhen: (p, c) => p.time != c.time, builder: (context, state) { if (state.dateTypeOption.includeTime) { return Padding( diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 9f59899063..6e34361961 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -289,7 +289,7 @@ pub(crate) async fn get_date_cell_data_handler( Some(field_meta) => { let cell_meta = editor.get_cell_meta(¶ms.row_id, ¶ms.field_id).await?; let type_option = DateTypeOption::from(&field_meta); - let date_cell_data = type_option.date_cell_data(&cell_meta)?; + let date_cell_data = type_option.make_date_cell_data(&cell_meta)?; data_result(date_cell_data) } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs index 84bb5a517b..84cfe0e4bf 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option.rs @@ -5,14 +5,12 @@ use crate::services::row::{CellContentChangeset, CellDataOperation, DecodedCellD use bytes::Bytes; use chrono::format::strftime::StrftimeItems; use chrono::NaiveDateTime; -use diesel::types::Time; use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_error::{internal_error, ErrorCode, FlowyError, FlowyResult}; use flowy_grid_data_model::entities::{ CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, }; use serde::{Deserialize, Serialize}; -use std::ops::Add; use std::str::FromStr; use strum_macros::EnumIter; @@ -79,7 +77,7 @@ impl DateTypeOption { } } - pub fn date_cell_data(&self, cell_meta: &Option) -> FlowyResult { + pub fn make_date_cell_data(&self, cell_meta: &Option) -> FlowyResult { if cell_meta.is_none() { return Ok(DateCellData::default()); } @@ -112,27 +110,28 @@ impl DateTypeOption { utc: &chrono::DateTime, time: &Option, ) -> FlowyResult { - let mut date_str = format!( - "{}", - utc.format_with_items(StrftimeItems::new(self.date_format.format_str())) - ); - if let Some(time_str) = time.as_ref() { if !time_str.is_empty() { - date_str = date_str.add(&time_str); - } - } - let fmt = self.date_fmt(time); - match NaiveDateTime::parse_from_str(&date_str, &fmt) { - Ok(native) => { - let utc = self.utc_date_time_from_native(native); - Ok(utc.timestamp()) - } - Err(_e) => { - let msg = format!("Parse {} with format: {} failed", date_str, fmt); - Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg)) + let date_str = format!( + "{}{}", + utc.format_with_items(StrftimeItems::new(self.date_format.format_str())), + &time_str + ); + + return match NaiveDateTime::parse_from_str(&date_str, &self.date_fmt(time)) { + Ok(native) => { + let utc = self.utc_date_time_from_native(native); + Ok(utc.timestamp()) + } + Err(_e) => { + let msg = format!("Parse {} failed", date_str); + Err(FlowyError::new(ErrorCode::InvalidDateTimeFormat, &msg)) + } + }; } } + + return Ok(utc.timestamp()); } } @@ -170,7 +169,7 @@ impl CellDataOperation for DateTypeOption { let timestamp = self.timestamp_from_utc_with_time(&utc, &time)?; DateCellDataSerde::new(timestamp, time, &self.time_format) } - _ => DateCellDataSerde::from_timestamp(date_timestamp, &self.time_format), + _ => DateCellDataSerde::from_timestamp(date_timestamp, Some(default_time_str(&self.time_format))), }, }; @@ -312,11 +311,8 @@ impl DateCellDataSerde { } } - fn from_timestamp(timestamp: i64, time_format: &TimeFormat) -> Self { - Self { - timestamp, - time: Some(default_time_str(time_format)), - } + pub(crate) fn from_timestamp(timestamp: i64, time: Option) -> Self { + Self { timestamp, time } } fn to_string(self) -> String { @@ -614,11 +610,7 @@ mod tests { } fn data(s: i64) -> String { - let json = serde_json::to_string(&DateCellDataSerde { - timestamp: s, - time: None, - }) - .unwrap(); + let json = serde_json::to_string(&DateCellDataSerde::from_timestamp(s, None)).unwrap(); TypeOptionCellData::new(&json, FieldType::DateTime).json() } } diff --git a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs index cf1ca7380f..348114e122 100644 --- a/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs +++ b/frontend/rust-lib/flowy-grid/src/services/field/type_options/text_type_option.rs @@ -78,7 +78,8 @@ mod tests { // date let date_time_field_meta = FieldBuilder::from_field_type(&FieldType::DateTime).build(); - let data = TypeOptionCellData::new("1647251762", FieldType::DateTime).json(); + let json = serde_json::to_string(&DateCellDataSerde::from_timestamp(1647251762, None)).unwrap(); + let data = TypeOptionCellData::new(&json, FieldType::DateTime).json(); assert_eq!( type_option.decode_cell_data(data, &date_time_field_meta).content, "Mar 14,2022".to_owned() diff --git a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs index 9f8ee392d5..a954694a16 100644 --- a/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs +++ b/frontend/rust-lib/flowy-grid/tests/grid/grid_test.rs @@ -2,8 +2,8 @@ use crate::grid::script::EditorScript::*; use crate::grid::script::*; use chrono::NaiveDateTime; use flowy_grid::services::field::{ - MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset, SingleSelectTypeOption, - SELECTION_IDS_SEPARATOR, + DateCellContentChangeset, MultiSelectTypeOption, SelectOption, SelectOptionCellContentChangeset, + SingleSelectTypeOption, SELECTION_IDS_SEPARATOR, }; use flowy_grid::services::row::{decode_cell_data, CreateRowMetaBuilder}; use flowy_grid_data_model::entities::{ @@ -240,7 +240,9 @@ async fn grid_row_add_cells_test() { builder.add_cell(&field.id, "18,443".to_owned()).unwrap(); } FieldType::DateTime => { - builder.add_cell(&field.id, "1647251762".to_owned()).unwrap(); + builder + .add_cell(&field.id, make_date_cell_string("1647251762")) + .unwrap(); } FieldType::SingleSelect => { let type_option = SingleSelectTypeOption::from(field); @@ -278,10 +280,11 @@ async fn grid_row_add_date_cell_test() { date_field = Some(field.clone()); NaiveDateTime::from_timestamp(123, 0); // The data should not be empty - assert!(builder.add_cell(&field.id, "".to_owned()).is_err()); - - assert!(builder.add_cell(&field.id, "123".to_owned()).is_ok()); - assert!(builder.add_cell(&field.id, format!("{}", timestamp)).is_ok()); + assert!(builder.add_cell(&field.id, "".to_string()).is_err()); + assert!(builder.add_cell(&field.id, make_date_cell_string("123")).is_ok()); + assert!(builder + .add_cell(&field.id, make_date_cell_string(×tamp.to_string())) + .is_ok()); } } let context = builder.build(); @@ -315,7 +318,7 @@ async fn grid_cell_update() { let data = match field_meta.field_type { FieldType::RichText => "".to_string(), FieldType::Number => "123".to_string(), - FieldType::DateTime => "123".to_string(), + FieldType::DateTime => make_date_cell_string("123"), FieldType::SingleSelect => { let type_option = SingleSelectTypeOption::from(field_meta); SelectOptionCellContentChangeset::from_insert(&type_option.options.first().unwrap().id).to_str() @@ -363,3 +366,11 @@ async fn grid_cell_update() { test.run_scripts(scripts).await; } + +fn make_date_cell_string(s: &str) -> String { + serde_json::to_string(&DateCellContentChangeset { + date: Some(s.to_string()), + time: None, + }) + .unwrap() +}