From 065a72a8dad51cf58ea07e95562589042656897e Mon Sep 17 00:00:00 2001 From: appflowy Date: Tue, 29 Mar 2022 22:58:38 +0800 Subject: [PATCH] chore: add option & color selection --- .../app_flowy/assets/images/grid/details.svg | 4 + .../app_flowy/assets/translations/en.json | 11 ++ .../app_flowy/lib/startup/deps_resolver.dart | 10 +- .../application/grid/field/field_service.dart | 2 - .../field/type_option/multi_select_bloc.dart | 42 +++++ .../field/type_option/option_pannel_bloc.dart | 17 +- .../field/type_option/selection_bloc.dart | 39 ----- .../field/type_option/single_select_bloc.dart | 57 ++++++ .../type_option/type_option_service.dart | 17 ++ .../workspace/application/grid/prelude.dart | 2 +- .../plugins/doc/src/document_page.dart | 1 + .../widgets/header/create_field_pannel.dart | 2 +- .../widgets/header/field_tyep_switcher.dart | 31 ++-- .../type_option/edit_option_pannel.dart | 115 ++++++++++++ .../header/type_option/multi_select.dart | 48 ++++++ .../{selection.dart => option_pannel.dart} | 137 ++++++--------- .../header/type_option/single_select.dart | 55 ++++++ .../widgets/header/type_option/widget.dart | 47 +++-- .../lib/style_widget/button.dart | 5 +- .../lib/widget/rounded_input_field.dart | 6 + .../dart_event/flowy-grid/dart_event.dart | 17 ++ .../flowy_sdk/lib/dispatch/dispatch.dart | 1 + .../flowy-error-code/code.pbenum.dart | 2 + .../flowy-error-code/code.pbjson.dart | 3 +- .../flowy-grid-data-model/grid.pb.dart | 47 +++++ .../flowy-grid-data-model/grid.pbjson.dart | 10 ++ .../protobuf/flowy-grid/event_map.pbenum.dart | 8 +- .../protobuf/flowy-grid/event_map.pbjson.dart | 9 +- .../rust-lib/flowy-grid/src/event_handler.rs | 10 +- frontend/rust-lib/flowy-grid/src/event_map.rs | 10 +- .../src/protobuf/model/event_map.rs | 22 ++- .../src/protobuf/proto/event_map.proto | 7 +- shared-lib/flowy-error-code/src/code.rs | 2 + .../src/protobuf/model/code.rs | 10 +- .../src/protobuf/proto/code.proto | 1 + .../src/entities/grid.rs | 23 ++- .../flowy-grid-data-model/src/parser/mod.rs | 4 +- .../parser/{id_parser.rs => str_parser.rs} | 18 ++ .../src/protobuf/model/grid.rs | 163 +++++++++++++++++- .../src/protobuf/proto/grid.proto | 3 + 40 files changed, 828 insertions(+), 190 deletions(-) create mode 100644 frontend/app_flowy/assets/images/grid/details.svg create mode 100644 frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart delete mode 100644 frontend/app_flowy/lib/workspace/application/grid/field/type_option/selection_bloc.dart create mode 100644 frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_bloc.dart create mode 100644 frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart rename frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/{selection.dart => option_pannel.dart} (55%) create mode 100644 frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart rename shared-lib/flowy-grid-data-model/src/parser/{id_parser.rs => str_parser.rs} (54%) diff --git a/frontend/app_flowy/assets/images/grid/details.svg b/frontend/app_flowy/assets/images/grid/details.svg new file mode 100644 index 0000000000..e4c9f58f27 --- /dev/null +++ b/frontend/app_flowy/assets/images/grid/details.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/app_flowy/assets/translations/en.json b/frontend/app_flowy/assets/translations/en.json index fbd672c04f..b751bb6d3e 100644 --- a/frontend/app_flowy/assets/translations/en.json +++ b/frontend/app_flowy/assets/translations/en.json @@ -167,6 +167,17 @@ "addSelectOption": "Add an option", "optionTitle": "Options", "addOption": "Add option" + }, + "selectOption": { + "purpleColor": "Purple", + "pinkColor": "Pink", + "lightPinkColor": "Light Pink", + "orangeColor": "Orange", + "yellowColor": "Yellow", + "limeColor": "Lime", + "greenColor": "Green", + "aquaColor": "Aqua", + "blueColor": "Blue" } } } diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 5d78cbdf2a..8bab77150a 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -3,6 +3,7 @@ import 'package:app_flowy/user/application/user_listener.dart'; import 'package:app_flowy/user/application/user_service.dart'; import 'package:app_flowy/workspace/application/app/prelude.dart'; import 'package:app_flowy/workspace/application/doc/prelude.dart'; +import 'package:app_flowy/workspace/application/grid/field/type_option/multi_select_bloc.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/application/grid/row/row_listener.dart'; import 'package:app_flowy/workspace/application/trash/prelude.dart'; @@ -20,6 +21,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/number_type_option.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart'; import 'package:get_it/get_it.dart'; @@ -215,8 +217,12 @@ void _resolveGridDeps(GetIt getIt) { (context, _) => FieldTypeSwitchBloc(context), ); - getIt.registerFactory( - () => SelectionTypeOptionBloc(), + getIt.registerFactoryParam( + (typeOption, fieldId) => SingleSelectTypeOptionBloc(typeOption, fieldId), + ); + + getIt.registerFactoryParam( + (typeOption, _) => MultiSelectTypeOptionBloc(typeOption), ); getIt.registerFactoryParam( 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 6824ce0b1b..24644f0fae 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -1,5 +1,3 @@ -import 'dart:typed_data'; - import 'package:dartz/dartz.dart'; import 'package:equatable/equatable.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart new file mode 100644 index 0000000000..75ac80c47c --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart @@ -0,0 +1,42 @@ +import 'dart:typed_data'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; + +part 'multi_select_bloc.freezed.dart'; + +class MultiSelectTypeOptionBloc extends Bloc { + MultiSelectTypeOptionBloc(MultiSelectTypeOption typeOption) : super(MultiSelectTypeOptionState.initial(typeOption)) { + on( + (event, emit) async { + await event.map( + createOption: (_CreateOption value) {}, + updateOptions: (_UpdateOptions value) async {}, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class MultiSelectTypeOptionEvent with _$MultiSelectTypeOptionEvent { + const factory MultiSelectTypeOptionEvent.createOption(String optionName) = _CreateOption; + const factory MultiSelectTypeOptionEvent.updateOptions(List options) = _UpdateOptions; +} + +@freezed +class MultiSelectTypeOptionState with _$MultiSelectTypeOptionState { + const factory MultiSelectTypeOptionState({ + required MultiSelectTypeOption typeOption, + }) = _MultiSelectTypeOptionState; + + factory MultiSelectTypeOptionState.initial(MultiSelectTypeOption typeOption) => MultiSelectTypeOptionState( + typeOption: typeOption, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/option_pannel_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/option_pannel_bloc.dart index aacf06c98d..445db413c0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/option_pannel_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/option_pannel_bloc.dart @@ -1,13 +1,8 @@ -import 'dart:typed_data'; - -import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; import 'package:dartz/dartz.dart'; - part 'option_pannel_bloc.freezed.dart'; class OptionPannelBloc extends Bloc { @@ -16,13 +11,13 @@ class OptionPannelBloc extends Bloc { (event, emit) async { await event.map( createOption: (_CreateOption value) async { - emit(state.copyWith(isAddingOption: false)); + emit(state.copyWith(isEditingOption: false, newOptionName: Some(value.optionName))); }, beginAddingOption: (_BeginAddingOption value) { - emit(state.copyWith(isAddingOption: true)); + emit(state.copyWith(isEditingOption: true, newOptionName: none())); }, endAddingOption: (_EndAddingOption value) { - emit(state.copyWith(isAddingOption: false)); + emit(state.copyWith(isEditingOption: false, newOptionName: none())); }, ); }, @@ -46,11 +41,13 @@ class OptionPannelEvent with _$OptionPannelEvent { class OptionPannelState with _$OptionPannelState { const factory OptionPannelState({ required List options, - required bool isAddingOption, + required bool isEditingOption, + required Option newOptionName, }) = _OptionPannelState; factory OptionPannelState.initial(List options) => OptionPannelState( options: options, - isAddingOption: false, + isEditingOption: false, + newOptionName: none(), ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/selection_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/selection_bloc.dart deleted file mode 100644 index ac6d3fb6d4..0000000000 --- a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/selection_bloc.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'dart:typed_data'; - -import 'package:flowy_sdk/log.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:freezed_annotation/freezed_annotation.dart'; -import 'dart:async'; -import 'package:dartz/dartz.dart'; - -part 'selection_bloc.freezed.dart'; - -class SelectionTypeOptionBloc extends Bloc { - SelectionTypeOptionBloc() : super(SelectionTypeOptionState.initial()) { - on( - (event, emit) async { - await event.map( - initial: (_InitialField value) async {}, - ); - }, - ); - } - - @override - Future close() async { - return super.close(); - } -} - -@freezed -class SelectionTypeOptionEvent with _$SelectionTypeOptionEvent { - const factory SelectionTypeOptionEvent.initial(Uint8List? typeOptionData) = _InitialField; -} - -@freezed -class SelectionTypeOptionState with _$SelectionTypeOptionState { - const factory SelectionTypeOptionState() = _SelectionTypeOptionState; - - factory SelectionTypeOptionState.initial() => SelectionTypeOptionState(); -} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_bloc.dart new file mode 100644 index 0000000000..07a26439f3 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_bloc.dart @@ -0,0 +1,57 @@ +import 'package:flowy_sdk/log.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'dart:async'; + +import 'type_option_service.dart'; + +part 'single_select_bloc.freezed.dart'; + +class SingleSelectTypeOptionBloc extends Bloc { + final TypeOptionService service; + + SingleSelectTypeOptionBloc(SingleSelectTypeOption typeOption, String fieldId) + : service = TypeOptionService(fieldId: fieldId), + super(SingleSelectTypeOptionState.initial(typeOption)) { + on( + (event, emit) async { + await event.map( + createOption: (_CreateOption value) async { + final result = await service.createOption(value.optionName); + result.fold( + (option) { + state.typeOption.options.insert(0, option); + emit(state); + }, + (err) => Log.error(err), + ); + }, + updateOptions: (_UpdateOptions value) async {}, + ); + }, + ); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class SingleSelectTypeOptionEvent with _$SingleSelectTypeOptionEvent { + const factory SingleSelectTypeOptionEvent.createOption(String optionName) = _CreateOption; + const factory SingleSelectTypeOptionEvent.updateOptions(List options) = _UpdateOptions; +} + +@freezed +class SingleSelectTypeOptionState with _$SingleSelectTypeOptionState { + const factory SingleSelectTypeOptionState({ + required SingleSelectTypeOption typeOption, + }) = _SingleSelectTypeOptionState; + + factory SingleSelectTypeOptionState.initial(SingleSelectTypeOption typeOption) => SingleSelectTypeOptionState( + typeOption: typeOption, + ); +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart new file mode 100644 index 0000000000..8ab3460b82 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart @@ -0,0 +1,17 @@ +import 'package:dartz/dartz.dart'; +import 'package:flowy_sdk/dispatch/dispatch.dart'; +import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; + +class TypeOptionService { + String fieldId; + TypeOptionService({ + required this.fieldId, + }); + + Future> createOption(String name) { + final payload = CreateSelectOptionPayload.create()..optionName = name; + return GridEventCreateSelectOption(payload).send(); + } +} diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 38135f75f6..e1d3020ae0 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -14,7 +14,7 @@ export 'field/switch_field_type_bloc.dart'; // Field Type Option export 'field/type_option/date_bloc.dart'; export 'field/type_option/number_bloc.dart'; -export 'field/type_option/selection_bloc.dart'; +export 'field/type_option/single_select_bloc.dart'; // Cell export 'cell_bloc/text_cell_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart index 031edb93fd..5983102047 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/doc/src/document_page.dart @@ -61,6 +61,7 @@ class _DocumentPageState extends State { @override Future dispose() async { documentBloc.close(); + _focusNode.dispose(); super.dispose(); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/create_field_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/create_field_pannel.dart index c282f10b40..8b2b74d9ae 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/create_field_pannel.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/create_field_pannel.dart @@ -20,7 +20,7 @@ class CreateFieldPannel extends FlowyOverlayDelegate { FlowyOverlay.of(context).insertWithAnchor( widget: OverlayContainer( child: _CreateFieldPannelWidget(_createFieldBloc), - constraints: BoxConstraints.loose(const Size(220, 500)), + constraints: BoxConstraints.loose(const Size(220, 400)), ), identifier: identifier(), anchorContext: context, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart index 6e03b4243d..1a418cf543 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart @@ -2,7 +2,6 @@ import 'dart:typed_data'; 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:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/selection.dart'; import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; @@ -14,12 +13,13 @@ import 'package:flowy_sdk/protobuf/flowy-grid/checkbox_type_option.pbserver.dart import 'package:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart'; import 'package:flutter/material.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 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart'; +import 'type_option/multi_select.dart'; import 'type_option/number.dart'; +import 'type_option/single_select.dart'; typedef SelectFieldCallback = void Function(Field, Uint8List); @@ -50,7 +50,7 @@ class _FieldTypeSwitcherState extends State { final typeOptionWidget = _typeOptionWidget( context: context, - fieldType: state.field.fieldType, + field: state.field, data: state.typeOptionData, ); @@ -89,7 +89,7 @@ class _FieldTypeSwitcherState extends State { Widget? _typeOptionWidget({ required BuildContext context, - required FieldType fieldType, + required Field field, required TypeOptionData data, }) { final delegate = TypeOptionOperationDelegate( @@ -97,8 +97,9 @@ class _FieldTypeSwitcherState extends State { context.read().add(FieldTypeSwitchEvent.didUpdateTypeOptionData(data)); }, requireToShowOverlay: _showOverlay, + hideOverlay: _hideOverlay, ); - final builder = _makeTypeOptionBuild(fieldType: fieldType, data: data, delegate: delegate); + final builder = _makeTypeOptionBuild(field: field, data: data, delegate: delegate); return builder.customWidget; } @@ -120,6 +121,12 @@ class _FieldTypeSwitcherState extends State { anchorOffset: const Offset(-20, 0), ); } + + void _hideOverlay(BuildContext context) { + if (currentOverlayIdentifier != null) { + FlowyOverlay.of(context).remove(currentOverlayIdentifier!); + } + } } abstract class TypeOptionBuilder { @@ -127,23 +134,24 @@ abstract class TypeOptionBuilder { } TypeOptionBuilder _makeTypeOptionBuild({ - required FieldType fieldType, + required Field field, required TypeOptionData data, required TypeOptionOperationDelegate delegate, }) { - switch (fieldType) { + switch (field.fieldType) { case FieldType.Checkbox: return CheckboxTypeOptionBuilder(data); case FieldType.DateTime: return DateTypeOptionBuilder(data, delegate); + case FieldType.SingleSelect: + return SingleSelectTypeOptionBuilder(field.id, data, delegate); case FieldType.MultiSelect: - return MultiSelectTypeOptionBuilder(data); + return MultiSelectTypeOptionBuilder(data, delegate); case FieldType.Number: return NumberTypeOptionBuilder(data, delegate); case FieldType.RichText: return RichTextTypeOptionBuilder(data); - case FieldType.SingleSelect: - return SingleSelectTypeOptionBuilder(data); + default: throw UnimplementedError; } @@ -156,13 +164,16 @@ abstract class TypeOptionWidget extends StatelessWidget { typedef TypeOptionData = Uint8List; typedef TypeOptionDataCallback = void Function(TypeOptionData typeOptionData); typedef ShowOverlayCallback = void Function(BuildContext anchorContext, String overlayIdentifier, Widget child); +typedef HideOverlayCallback = void Function(BuildContext anchorContext); class TypeOptionOperationDelegate { TypeOptionDataCallback didUpdateTypeOptionData; ShowOverlayCallback requireToShowOverlay; + HideOverlayCallback hideOverlay; TypeOptionOperationDelegate({ required this.didUpdateTypeOptionData, required this.requireToShowOverlay, + required this.hideOverlay, }); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart new file mode 100644 index 0000000000..31f9570602 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/edit_option_pannel.dart @@ -0,0 +1,115 @@ +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; + +class SelectOptionColorList extends StatelessWidget { + const SelectOptionColorList({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container(); + } +} + +class _SelectOptionColorItem extends StatelessWidget { + final SelectOptionColor option; + final bool isSelected; + const _SelectOptionColorItem({required this.option, required this.isSelected, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + + Widget? checkmark; + if (isSelected) { + checkmark = svg("grid/details", color: theme.iconColor); + } + + final colorIcon = SizedBox.square( + dimension: 16, + child: Container( + decoration: BoxDecoration( + color: option.color(context), + shape: BoxShape.circle, + ), + ), + ); + + return FlowyButton( + text: FlowyText.medium( + option.name(), + fontSize: 12, + ), + hoverColor: theme.hover, + leftIcon: colorIcon, + rightIcon: checkmark, + onTap: () {}, + ); + } +} + +enum SelectOptionColor { + purple, + pink, + lightPink, + orange, + yellow, + lime, + green, + aqua, + blue, +} + +extension SelectOptionColorExtension on SelectOptionColor { + Color color(BuildContext context) { + final theme = context.watch(); + switch (this) { + case SelectOptionColor.purple: + return theme.tint1; + case SelectOptionColor.pink: + return theme.tint2; + case SelectOptionColor.lightPink: + return theme.tint3; + case SelectOptionColor.orange: + return theme.tint4; + case SelectOptionColor.yellow: + return theme.tint5; + case SelectOptionColor.lime: + return theme.tint6; + case SelectOptionColor.green: + return theme.tint7; + case SelectOptionColor.aqua: + return theme.tint8; + case SelectOptionColor.blue: + return theme.tint9; + } + } + + String name() { + switch (this) { + case SelectOptionColor.purple: + return LocaleKeys.grid_selectOption_purpleColor.tr(); + case SelectOptionColor.pink: + return LocaleKeys.grid_selectOption_pinkColor.tr(); + case SelectOptionColor.lightPink: + return LocaleKeys.grid_selectOption_lightPinkColor.tr(); + case SelectOptionColor.orange: + return LocaleKeys.grid_selectOption_orangeColor.tr(); + case SelectOptionColor.yellow: + return LocaleKeys.grid_selectOption_yellowColor.tr(); + case SelectOptionColor.lime: + return LocaleKeys.grid_selectOption_limeColor.tr(); + case SelectOptionColor.green: + return LocaleKeys.grid_selectOption_greenColor.tr(); + case SelectOptionColor.aqua: + return LocaleKeys.grid_selectOption_aquaColor.tr(); + case SelectOptionColor.blue: + return LocaleKeys.grid_selectOption_blueColor.tr(); + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart new file mode 100644 index 0000000000..4a3694b5fc --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart @@ -0,0 +1,48 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/field/type_option/multi_select_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'option_pannel.dart'; + +class MultiSelectTypeOptionBuilder extends TypeOptionBuilder { + MultiSelectTypeOption typeOption; + TypeOptionOperationDelegate delegate; + + MultiSelectTypeOptionBuilder(TypeOptionData typeOptionData, this.delegate) + : typeOption = MultiSelectTypeOption.fromBuffer(typeOptionData); + + @override + Widget? get customWidget => MultiSelectTypeOptionWidget(typeOption, delegate); +} + +class MultiSelectTypeOptionWidget extends TypeOptionWidget { + final MultiSelectTypeOption typeOption; + final TypeOptionOperationDelegate delegate; + const MultiSelectTypeOptionWidget(this.typeOption, this.delegate, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(param1: typeOption), + child: BlocBuilder( + builder: (context, state) { + return OptionPannel( + options: state.typeOption.options, + beginEdit: () { + delegate.hideOverlay(context); + }, + createOptionCallback: (name) { + context.read().add(MultiSelectTypeOptionEvent.createOption(name)); + }, + updateOptionsCallback: (options) { + context.read().add(MultiSelectTypeOptionEvent.updateOptions(options)); + }, + ); + }, + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/selection.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/option_pannel.dart similarity index 55% rename from frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/selection.dart rename to frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/option_pannel.dart index 2d5c963fc5..736d03d96d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/selection.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/option_pannel.dart @@ -1,8 +1,5 @@ -import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/field/type_option/option_pannel_bloc.dart'; -import 'package:app_flowy/workspace/application/grid/field/type_option/selection_bloc.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart'; import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/style_widget/button.dart'; @@ -16,73 +13,48 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; import 'widget.dart'; -class SingleSelectTypeOptionBuilder extends TypeOptionBuilder { - SingleSelectTypeOption typeOption; - - SingleSelectTypeOptionBuilder(TypeOptionData typeOptionData) - : typeOption = SingleSelectTypeOption.fromBuffer(typeOptionData); - - @override - Widget? get customWidget => SingleSelectTypeOptionWidget(typeOption); -} - -class SingleSelectTypeOptionWidget extends TypeOptionWidget { - final SingleSelectTypeOption typeOption; - const SingleSelectTypeOptionWidget(this.typeOption, {Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => getIt(), - child: OptionPannel(options: typeOption.options), - ); - } -} - -class MultiSelectTypeOptionBuilder extends TypeOptionBuilder { - MultiSelectTypeOption typeOption; - - MultiSelectTypeOptionBuilder(TypeOptionData typeOptionData) - : typeOption = MultiSelectTypeOption.fromBuffer(typeOptionData); - - @override - Widget? get customWidget => MultiSelectTypeOptionWidget(typeOption); -} - -class MultiSelectTypeOptionWidget extends TypeOptionWidget { - final MultiSelectTypeOption typeOption; - const MultiSelectTypeOptionWidget(this.typeOption, {Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => getIt(), - child: OptionPannel(options: typeOption.options), - ); - } -} - class OptionPannel extends StatelessWidget { final List options; - const OptionPannel({required this.options, Key? key}) : super(key: key); + final VoidCallback beginEdit; + final Function(String optionName) createOptionCallback; + final Function(List) updateOptionsCallback; + const OptionPannel({ + required this.options, + required this.beginEdit, + required this.createOptionCallback, + required this.updateOptionsCallback, + Key? key, + }) : super(key: key); @override Widget build(BuildContext context) { return BlocProvider( create: (context) => OptionPannelBloc(options: options), - child: BlocBuilder( + child: BlocConsumer( + listener: (context, state) { + if (state.isEditingOption) { + beginEdit(); + } + state.newOptionName.fold( + () => null, + (optionName) => createOptionCallback(optionName), + ); + }, builder: (context, state) { - List children = [const OptionTitle()]; - if (state.isAddingOption) { + List children = [ + const TypeOptionSeparator(), + const OptionTitle(), + ]; + if (state.isEditingOption) { children.add(const _AddOptionTextField()); } - if (state.options.isEmpty && !state.isAddingOption) { + if (state.options.isEmpty && !state.isEditingOption) { children.add(const _AddOptionButton()); } if (state.options.isNotEmpty) { - children.add(const _OptionList()); + children.add(_OptionList(key: ObjectKey(state.options))); } return Column(children: children); @@ -100,19 +72,27 @@ class OptionTitle extends StatelessWidget { final theme = context.watch(); return BlocBuilder( - buildWhen: (previous, current) => previous.options.length != current.options.length, builder: (context, state) { List children = [FlowyText.medium(LocaleKeys.grid_field_optionTitle.tr(), fontSize: 12)]; - - if (state.options.isNotEmpty && state.isAddingOption == false) { - children.add(FlowyButton( - text: FlowyText.medium(LocaleKeys.grid_field_addOption.tr(), fontSize: 12), - hoverColor: theme.hover, - onTap: () { - context.read().add(const OptionPannelEvent.beginAddingOption()); - }, - rightIcon: svg("grid/more", color: theme.iconColor), - )); + if (state.options.isNotEmpty) { + children.add(const Spacer()); + children.add( + SizedBox( + width: 100, + height: 26, + child: FlowyButton( + text: FlowyText.medium( + LocaleKeys.grid_field_addOption.tr(), + fontSize: 12, + textAlign: TextAlign.center, + ), + hoverColor: theme.hover, + onTap: () { + context.read().add(const OptionPannelEvent.beginAddingOption()); + }, + ), + ), + ); } return SizedBox( @@ -135,19 +115,16 @@ class _OptionList extends StatelessWidget { return _OptionItem(option: option); }).toList(); - return SizedBox( - width: 120, - child: ListView.separated( - shrinkWrap: true, - controller: ScrollController(), - separatorBuilder: (context, index) { - return VSpace(GridSize.typeOptionSeparatorHeight); - }, - itemCount: optionItems.length, - itemBuilder: (BuildContext context, int index) { - return optionItems[index]; - }, - ), + return ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: optionItems.length, + itemBuilder: (BuildContext context, int index) { + return optionItems[index]; + }, ); }, ); @@ -167,7 +144,7 @@ class _OptionItem extends StatelessWidget { text: FlowyText.medium(option.name, fontSize: 12), hoverColor: theme.hover, onTap: () {}, - rightIcon: svg("grid/more", color: theme.iconColor), + rightIcon: svg("grid/details", color: theme.iconColor), ), ); } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart new file mode 100644 index 0000000000..6690729ff0 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart @@ -0,0 +1,55 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/field/type_option/single_select_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'option_pannel.dart'; + +class SingleSelectTypeOptionBuilder extends TypeOptionBuilder { + final SingleSelectTypeOptionWidget _widget; + + SingleSelectTypeOptionBuilder( + String fieldId, + TypeOptionData typeOptionData, + TypeOptionOperationDelegate delegate, + ) : _widget = SingleSelectTypeOptionWidget( + fieldId, + SingleSelectTypeOption.fromBuffer(typeOptionData), + delegate, + ); + + @override + Widget? get customWidget => _widget; +} + +class SingleSelectTypeOptionWidget extends TypeOptionWidget { + final String fieldId; + final SingleSelectTypeOption typeOption; + final TypeOptionOperationDelegate delegate; + const SingleSelectTypeOptionWidget(this.fieldId, this.typeOption, this.delegate, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(param1: typeOption, param2: fieldId), + child: BlocConsumer( + listener: (context, state) => delegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()), + builder: (context, state) { + return OptionPannel( + options: state.typeOption.options, + beginEdit: () { + delegate.hideOverlay(context); + }, + createOptionCallback: (name) { + context.read().add(SingleSelectTypeOptionEvent.createOption(name)); + }, + updateOptionsCallback: (options) { + context.read().add(SingleSelectTypeOptionEvent.updateOptions(options)); + }, + ); + }, + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart index f357c9afea..6f4e86a4e1 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/widget.dart @@ -21,6 +21,7 @@ class NameTextField extends StatefulWidget { class _NameTextFieldState extends State { late FocusNode _focusNode; + var isEdited = false; late TextEditingController _controller; @override @@ -35,31 +36,53 @@ class _NameTextFieldState extends State { @override Widget build(BuildContext context) { final theme = context.watch(); + return RoundedInputField( - controller: _controller, - focusNode: _focusNode, - height: 36, - style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500), - normalBorderColor: theme.shader4, - errorBorderColor: theme.red, - focusBorderColor: theme.main1, - cursorColor: theme.main1, - onChanged: (text) { - print(text); - }); + controller: _controller, + focusNode: _focusNode, + autoFocus: true, + height: 36, + style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w500), + normalBorderColor: theme.shader4, + focusBorderColor: theme.main1, + cursorColor: theme.main1, + onEditingComplete: () { + widget.onDone(_controller.text); + }, + ); } @override void dispose() { _focusNode.removeListener(notifyDidEndEditing); + _focusNode.dispose(); super.dispose(); } void notifyDidEndEditing() { if (_controller.text.isEmpty) { - // widget.onCanceled(); + if (isEdited) { + widget.onCanceled(); + } + isEdited = true; } else { widget.onDone(_controller.text); } } } + +class TypeOptionSeparator extends StatelessWidget { + const TypeOptionSeparator({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Container( + color: theme.shader4, + height: 0.25, + ), + ); + } +} 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 0bcd05f56e..13d02a0ea8 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 @@ -15,7 +15,7 @@ class FlowyButton extends StatelessWidget { Key? key, required this.text, this.onTap, - this.padding = const EdgeInsets.symmetric(horizontal: 3, vertical: 2), + this.padding = const EdgeInsets.symmetric(horizontal: 6, vertical: 2), this.leftIcon, this.rightIcon, this.hoverColor = Colors.transparent, @@ -44,12 +44,13 @@ class FlowyButton extends StatelessWidget { if (rightIcon != null) { children.add(SizedBox.fromSize(size: const Size.square(16), child: rightIcon!)); - children.add(const HSpace(6)); } return Padding( padding: padding, child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, children: children, ), ); 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 b6bf1daf4b..0af5e4ec89 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,6 +15,7 @@ class RoundedInputField extends StatefulWidget { final String errorText; final TextStyle style; final ValueChanged? onChanged; + final VoidCallback? onEditingComplete; final String? initialValue; final EdgeInsets margin; final EdgeInsets padding; @@ -22,6 +23,7 @@ class RoundedInputField extends StatefulWidget { final double height; final FocusNode? focusNode; final TextEditingController? controller; + final bool autoFocus; const RoundedInputField({ Key? key, @@ -32,6 +34,7 @@ class RoundedInputField extends StatefulWidget { this.obscureIcon, this.obscureHideIcon, this.onChanged, + this.onEditingComplete, this.normalBorderColor = Colors.transparent, this.errorBorderColor = Colors.transparent, this.focusBorderColor, @@ -43,6 +46,7 @@ class RoundedInputField extends StatefulWidget { this.height = 48, this.focusNode, this.controller, + this.autoFocus = false, }) : super(key: key); @override @@ -78,6 +82,7 @@ class _RoundedInputFieldState extends State { controller: widget.controller, initialValue: widget.initialValue, focusNode: widget.focusNode, + autofocus: widget.autoFocus, onChanged: (value) { inputText = value; if (widget.onChanged != null) { @@ -85,6 +90,7 @@ class _RoundedInputFieldState extends State { } setState(() {}); }, + onEditingComplete: widget.onEditingComplete, cursorColor: widget.cursorColor, obscureText: obscuteText, style: widget.style, 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 7f25329284..04098b288e 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 @@ -137,6 +137,23 @@ class GridEventCreateEditFieldContext { } } +class GridEventCreateSelectOption { + CreateSelectOptionPayload request; + GridEventCreateSelectOption(this.request); + + Future> send() { + final request = FFIRequest.create() + ..event = GridEvent.CreateSelectOption.toString() + ..payload = requestToBytes(this.request); + + return Dispatch.asyncRequest(request) + .then((bytesResult) => bytesResult.fold( + (okBytes) => left(SelectOption.fromBuffer(okBytes)), + (errBytes) => right(FlowyError.fromBuffer(errBytes)), + )); + } +} + class GridEventCreateRow { CreateRowPayload request; GridEventCreateRow(this.request); 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 b068956465..e2be9f11a2 100644 --- a/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart +++ b/frontend/app_flowy/packages/flowy_sdk/lib/dispatch/dispatch.dart @@ -4,6 +4,7 @@ import 'package:flowy_sdk/log.dart'; // ignore: unnecessary_import 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/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-net/event.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-net/network_state.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/event_map.pb.dart'; 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 307b9f86f2..9c4e31eeea 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 @@ -47,6 +47,7 @@ class ErrorCode extends $pb.ProtobufEnum { static const ErrorCode RowIdIsEmpty = ErrorCode._(430, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'RowIdIsEmpty'); static const ErrorCode FieldIdIsEmpty = ErrorCode._(440, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FieldIdIsEmpty'); static const ErrorCode FieldDoesNotExist = ErrorCode._(441, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'FieldDoesNotExist'); + static const ErrorCode SelectOptionNameIsEmpty = ErrorCode._(442, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SelectOptionNameIsEmpty'); 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'); @@ -88,6 +89,7 @@ class ErrorCode extends $pb.ProtobufEnum { RowIdIsEmpty, FieldIdIsEmpty, FieldDoesNotExist, + SelectOptionNameIsEmpty, TypeOptionDataIsEmpty, 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 9345118baa..b3efa2c0ad 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 @@ -49,10 +49,11 @@ const ErrorCode$json = const { const {'1': 'RowIdIsEmpty', '2': 430}, const {'1': 'FieldIdIsEmpty', '2': 440}, const {'1': 'FieldDoesNotExist', '2': 441}, + const {'1': 'SelectOptionNameIsEmpty', '2': 442}, const {'1': 'TypeOptionDataIsEmpty', '2': 450}, const {'1': 'InvalidData', '2': 500}, ], }; /// Descriptor for `ErrorCode`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSDAoISW50ZXJuYWwQABIUChBVc2VyVW5hdXRob3JpemVkEAISEgoOUmVjb3JkTm90Rm91bmQQAxIRCg1Vc2VySWRJc0VtcHR5EAQSGAoUV29ya3NwYWNlTmFtZUludmFsaWQQZBIWChJXb3Jrc3BhY2VJZEludmFsaWQQZRIYChRBcHBDb2xvclN0eWxlSW52YWxpZBBmEhgKFFdvcmtzcGFjZURlc2NUb29Mb25nEGcSGAoUV29ya3NwYWNlTmFtZVRvb0xvbmcQaBIQCgxBcHBJZEludmFsaWQQbhISCg5BcHBOYW1lSW52YWxpZBBvEhMKD1ZpZXdOYW1lSW52YWxpZBB4EhgKFFZpZXdUaHVtYm5haWxJbnZhbGlkEHkSEQoNVmlld0lkSW52YWxpZBB6EhMKD1ZpZXdEZXNjVG9vTG9uZxB7EhMKD1ZpZXdEYXRhSW52YWxpZBB8EhMKD1ZpZXdOYW1lVG9vTG9uZxB9EhEKDENvbm5lY3RFcnJvchDIARIRCgxFbWFpbElzRW1wdHkQrAISFwoSRW1haWxGb3JtYXRJbnZhbGlkEK0CEhcKEkVtYWlsQWxyZWFkeUV4aXN0cxCuAhIUCg9QYXNzd29yZElzRW1wdHkQrwISFAoPUGFzc3dvcmRUb29Mb25nELACEiUKIFBhc3N3b3JkQ29udGFpbnNGb3JiaWRDaGFyYWN0ZXJzELECEhoKFVBhc3N3b3JkRm9ybWF0SW52YWxpZBCyAhIVChBQYXNzd29yZE5vdE1hdGNoELMCEhQKD1VzZXJOYW1lVG9vTG9uZxC0AhInCiJVc2VyTmFtZUNvbnRhaW5Gb3JiaWRkZW5DaGFyYWN0ZXJzELUCEhQKD1VzZXJOYW1lSXNFbXB0eRC2AhISCg1Vc2VySWRJbnZhbGlkELcCEhEKDFVzZXJOb3RFeGlzdBC4AhIQCgtUZXh0VG9vTG9uZxCQAxISCg1HcmlkSWRJc0VtcHR5EJoDEhMKDkJsb2NrSWRJc0VtcHR5EKQDEhEKDFJvd0lkSXNFbXB0eRCuAxITCg5GaWVsZElkSXNFbXB0eRC4AxIWChFGaWVsZERvZXNOb3RFeGlzdBC5AxIaChVUeXBlT3B0aW9uRGF0YUlzRW1wdHkQwgMSEAoLSW52YWxpZERhdGEQ9AM='); +final $typed_data.Uint8List errorCodeDescriptor = $convert.base64Decode('CglFcnJvckNvZGUSDAoISW50ZXJuYWwQABIUChBVc2VyVW5hdXRob3JpemVkEAISEgoOUmVjb3JkTm90Rm91bmQQAxIRCg1Vc2VySWRJc0VtcHR5EAQSGAoUV29ya3NwYWNlTmFtZUludmFsaWQQZBIWChJXb3Jrc3BhY2VJZEludmFsaWQQZRIYChRBcHBDb2xvclN0eWxlSW52YWxpZBBmEhgKFFdvcmtzcGFjZURlc2NUb29Mb25nEGcSGAoUV29ya3NwYWNlTmFtZVRvb0xvbmcQaBIQCgxBcHBJZEludmFsaWQQbhISCg5BcHBOYW1lSW52YWxpZBBvEhMKD1ZpZXdOYW1lSW52YWxpZBB4EhgKFFZpZXdUaHVtYm5haWxJbnZhbGlkEHkSEQoNVmlld0lkSW52YWxpZBB6EhMKD1ZpZXdEZXNjVG9vTG9uZxB7EhMKD1ZpZXdEYXRhSW52YWxpZBB8EhMKD1ZpZXdOYW1lVG9vTG9uZxB9EhEKDENvbm5lY3RFcnJvchDIARIRCgxFbWFpbElzRW1wdHkQrAISFwoSRW1haWxGb3JtYXRJbnZhbGlkEK0CEhcKEkVtYWlsQWxyZWFkeUV4aXN0cxCuAhIUCg9QYXNzd29yZElzRW1wdHkQrwISFAoPUGFzc3dvcmRUb29Mb25nELACEiUKIFBhc3N3b3JkQ29udGFpbnNGb3JiaWRDaGFyYWN0ZXJzELECEhoKFVBhc3N3b3JkRm9ybWF0SW52YWxpZBCyAhIVChBQYXNzd29yZE5vdE1hdGNoELMCEhQKD1VzZXJOYW1lVG9vTG9uZxC0AhInCiJVc2VyTmFtZUNvbnRhaW5Gb3JiaWRkZW5DaGFyYWN0ZXJzELUCEhQKD1VzZXJOYW1lSXNFbXB0eRC2AhISCg1Vc2VySWRJbnZhbGlkELcCEhEKDFVzZXJOb3RFeGlzdBC4AhIQCgtUZXh0VG9vTG9uZxCQAxISCg1HcmlkSWRJc0VtcHR5EJoDEhMKDkJsb2NrSWRJc0VtcHR5EKQDEhEKDFJvd0lkSXNFbXB0eRCuAxITCg5GaWVsZElkSXNFbXB0eRC4AxIWChFGaWVsZERvZXNOb3RFeGlzdBC5AxIcChdTZWxlY3RPcHRpb25OYW1lSXNFbXB0eRC6AxIaChVUeXBlT3B0aW9uRGF0YUlzRW1wdHkQwgMSEAoLSW52YWxpZERhdGEQ9AM='); 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 bd9afe2243..3dafd193b3 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 @@ -1536,3 +1536,50 @@ class QueryRowPayload extends $pb.GeneratedMessage { void clearRowId() => clearField(3); } +class CreateSelectOptionPayload extends $pb.GeneratedMessage { + static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateSelectOptionPayload', createEmptyInstance: create) + ..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'optionName') + ..hasRequiredFields = false + ; + + CreateSelectOptionPayload._() : super(); + factory CreateSelectOptionPayload({ + $core.String? optionName, + }) { + final _result = create(); + if (optionName != null) { + _result.optionName = optionName; + } + return _result; + } + factory CreateSelectOptionPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); + factory CreateSelectOptionPayload.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') + CreateSelectOptionPayload clone() => CreateSelectOptionPayload()..mergeFromMessage(this); + @$core.Deprecated( + 'Using this can add significant overhead to your binary. ' + 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' + 'Will be removed in next major version') + CreateSelectOptionPayload copyWith(void Function(CreateSelectOptionPayload) updates) => super.copyWith((message) => updates(message as CreateSelectOptionPayload)) as CreateSelectOptionPayload; // ignore: deprecated_member_use + $pb.BuilderInfo get info_ => _i; + @$core.pragma('dart2js:noInline') + static CreateSelectOptionPayload create() => CreateSelectOptionPayload._(); + CreateSelectOptionPayload createEmptyInstance() => create(); + static $pb.PbList createRepeated() => $pb.PbList(); + @$core.pragma('dart2js:noInline') + static CreateSelectOptionPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); + static CreateSelectOptionPayload? _defaultInstance; + + @$pb.TagNumber(1) + $core.String get optionName => $_getSZ(0); + @$pb.TagNumber(1) + set optionName($core.String v) { $_setString(0, v); } + @$pb.TagNumber(1) + $core.bool hasOptionName() => $_has(0); + @$pb.TagNumber(1) + void clearOptionName() => clearField(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 0b900d46f9..3b7c58924e 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 @@ -302,3 +302,13 @@ const QueryRowPayload$json = const { /// Descriptor for `QueryRowPayload`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List queryRowPayloadDescriptor = $convert.base64Decode('Cg9RdWVyeVJvd1BheWxvYWQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEhkKCGJsb2NrX2lkGAIgASgJUgdibG9ja0lkEhUKBnJvd19pZBgDIAEoCVIFcm93SWQ='); +@$core.Deprecated('Use createSelectOptionPayloadDescriptor instead') +const CreateSelectOptionPayload$json = const { + '1': 'CreateSelectOptionPayload', + '2': const [ + const {'1': 'option_name', '3': 1, '4': 1, '5': 9, '10': 'optionName'}, + ], +}; + +/// Descriptor for `CreateSelectOptionPayload`. Decode as a `google.protobuf.DescriptorProto`. +final $typed_data.Uint8List createSelectOptionPayloadDescriptor = $convert.base64Decode('ChlDcmVhdGVTZWxlY3RPcHRpb25QYXlsb2FkEh8KC29wdGlvbl9uYW1lGAEgASgJUgpvcHRpb25OYW1l'); 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 46291923e0..25319128d8 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 @@ -18,9 +18,10 @@ class GridEvent extends $pb.ProtobufEnum { static const GridEvent DeleteField = GridEvent._(13, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteField'); static const GridEvent DuplicateField = GridEvent._(15, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DuplicateField'); static const GridEvent CreateEditFieldContext = GridEvent._(16, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateEditFieldContext'); - static const GridEvent CreateRow = GridEvent._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateRow'); - static const GridEvent GetRow = GridEvent._(22, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetRow'); - static const GridEvent UpdateCell = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCell'); + static const GridEvent CreateSelectOption = GridEvent._(30, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateSelectOption'); + static const GridEvent CreateRow = GridEvent._(50, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CreateRow'); + static const GridEvent GetRow = GridEvent._(51, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'GetRow'); + static const GridEvent UpdateCell = GridEvent._(70, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UpdateCell'); static const $core.List values = [ GetGridData, @@ -31,6 +32,7 @@ class GridEvent extends $pb.ProtobufEnum { DeleteField, DuplicateField, CreateEditFieldContext, + CreateSelectOption, CreateRow, GetRow, UpdateCell, 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 278e0b14c3..747a591a02 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 @@ -20,11 +20,12 @@ const GridEvent$json = const { const {'1': 'DeleteField', '2': 13}, const {'1': 'DuplicateField', '2': 15}, const {'1': 'CreateEditFieldContext', '2': 16}, - const {'1': 'CreateRow', '2': 21}, - const {'1': 'GetRow', '2': 22}, - const {'1': 'UpdateCell', '2': 30}, + const {'1': 'CreateSelectOption', '2': 30}, + const {'1': 'CreateRow', '2': 50}, + const {'1': 'GetRow', '2': 51}, + const {'1': 'UpdateCell', '2': 70}, ], }; /// Descriptor for `GridEvent`. Decode as a `google.protobuf.EnumDescriptorProto`. -final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtDcmVhdGVGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEgoORHVwbGljYXRlRmllbGQQDxIaChZDcmVhdGVFZGl0RmllbGRDb250ZXh0EBASDQoJQ3JlYXRlUm93EBUSCgoGR2V0Um93EBYSDgoKVXBkYXRlQ2VsbBAe'); +final $typed_data.Uint8List gridEventDescriptor = $convert.base64Decode('CglHcmlkRXZlbnQSDwoLR2V0R3JpZERhdGEQABIRCg1HZXRHcmlkQmxvY2tzEAESDQoJR2V0RmllbGRzEAoSDwoLVXBkYXRlRmllbGQQCxIPCgtDcmVhdGVGaWVsZBAMEg8KC0RlbGV0ZUZpZWxkEA0SEgoORHVwbGljYXRlRmllbGQQDxIaChZDcmVhdGVFZGl0RmllbGRDb250ZXh0EBASFgoSQ3JlYXRlU2VsZWN0T3B0aW9uEB4SDQoJQ3JlYXRlUm93EDISCgoGR2V0Um93EDMSDgoKVXBkYXRlQ2VsbBBG'); diff --git a/frontend/rust-lib/flowy-grid/src/event_handler.rs b/frontend/rust-lib/flowy-grid/src/event_handler.rs index 97b91e5557..d29c2aec48 100644 --- a/frontend/rust-lib/flowy-grid/src/event_handler.rs +++ b/frontend/rust-lib/flowy-grid/src/event_handler.rs @@ -1,5 +1,5 @@ use crate::manager::GridManager; -use crate::services::field::type_option_data_from_str; +use crate::services::field::{type_option_data_from_str, SelectOption}; use flowy_error::FlowyError; use flowy_grid_data_model::entities::*; use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; @@ -88,6 +88,14 @@ pub(crate) async fn duplicate_field_handler( Ok(()) } +#[tracing::instrument(level = "debug", skip(data), err)] +pub(crate) async fn create_select_option_handler( + data: Data, +) -> DataResult { + let params: CreateSelectOptionParams = data.into_inner().try_into()?; + data_result(SelectOption::new(¶ms.option_name)) +} + #[tracing::instrument(level = "debug", skip(data, manager), err)] pub(crate) async fn create_edit_field_context_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 efe5ddc094..966423c7c7 100644 --- a/frontend/rust-lib/flowy-grid/src/event_map.rs +++ b/frontend/rust-lib/flowy-grid/src/event_map.rs @@ -16,6 +16,7 @@ pub fn create(grid_manager: Arc) -> Module { .event(GridEvent::DeleteField, delete_field_handler) .event(GridEvent::DuplicateField, duplicate_field_handler) .event(GridEvent::CreateEditFieldContext, create_edit_field_context_handler) + .event(GridEvent::CreateSelectOption, create_select_option_handler) .event(GridEvent::CreateRow, create_row_handler) .event(GridEvent::GetRow, get_row_handler) .event(GridEvent::UpdateCell, update_cell_handler); @@ -50,12 +51,15 @@ pub enum GridEvent { #[event(input = "CreateEditFieldContextParams", output = "EditFieldContext")] CreateEditFieldContext = 16, + #[event(input = "CreateSelectOptionPayload", output = "SelectOption")] + CreateSelectOption = 30, + #[event(input = "CreateRowPayload", output = "Row")] - CreateRow = 21, + CreateRow = 50, #[event(input = "QueryRowPayload", output = "Row")] - GetRow = 22, + GetRow = 51, #[event(input = "CellMetaChangeset")] - UpdateCell = 30, + UpdateCell = 70, } 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 13ee0705cc..2eab7357c5 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 @@ -33,9 +33,10 @@ pub enum GridEvent { DeleteField = 13, DuplicateField = 15, CreateEditFieldContext = 16, - CreateRow = 21, - GetRow = 22, - UpdateCell = 30, + CreateSelectOption = 30, + CreateRow = 50, + GetRow = 51, + UpdateCell = 70, } impl ::protobuf::ProtobufEnum for GridEvent { @@ -53,9 +54,10 @@ impl ::protobuf::ProtobufEnum for GridEvent { 13 => ::std::option::Option::Some(GridEvent::DeleteField), 15 => ::std::option::Option::Some(GridEvent::DuplicateField), 16 => ::std::option::Option::Some(GridEvent::CreateEditFieldContext), - 21 => ::std::option::Option::Some(GridEvent::CreateRow), - 22 => ::std::option::Option::Some(GridEvent::GetRow), - 30 => ::std::option::Option::Some(GridEvent::UpdateCell), + 30 => ::std::option::Option::Some(GridEvent::CreateSelectOption), + 50 => ::std::option::Option::Some(GridEvent::CreateRow), + 51 => ::std::option::Option::Some(GridEvent::GetRow), + 70 => ::std::option::Option::Some(GridEvent::UpdateCell), _ => ::std::option::Option::None } } @@ -70,6 +72,7 @@ impl ::protobuf::ProtobufEnum for GridEvent { GridEvent::DeleteField, GridEvent::DuplicateField, GridEvent::CreateEditFieldContext, + GridEvent::CreateSelectOption, GridEvent::CreateRow, GridEvent::GetRow, GridEvent::UpdateCell, @@ -101,12 +104,13 @@ impl ::protobuf::reflect::ProtobufValue for GridEvent { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\x0fevent_map.proto*\xcc\x01\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ + \n\x0fevent_map.proto*\xe4\x01\n\tGridEvent\x12\x0f\n\x0bGetGridData\x10\ \0\x12\x11\n\rGetGridBlocks\x10\x01\x12\r\n\tGetFields\x10\n\x12\x0f\n\ \x0bUpdateField\x10\x0b\x12\x0f\n\x0bCreateField\x10\x0c\x12\x0f\n\x0bDe\ leteField\x10\r\x12\x12\n\x0eDuplicateField\x10\x0f\x12\x1a\n\x16CreateE\ - ditFieldContext\x10\x10\x12\r\n\tCreateRow\x10\x15\x12\n\n\x06GetRow\x10\ - \x16\x12\x0e\n\nUpdateCell\x10\x1eb\x06proto3\ + ditFieldContext\x10\x10\x12\x16\n\x12CreateSelectOption\x10\x1e\x12\r\n\ + \tCreateRow\x102\x12\n\n\x06GetRow\x103\x12\x0e\n\nUpdateCell\x10Fb\x06p\ + roto3\ "; 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 327a1e3aee..ebc7ae6782 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 @@ -9,7 +9,8 @@ enum GridEvent { DeleteField = 13; DuplicateField = 15; CreateEditFieldContext = 16; - CreateRow = 21; - GetRow = 22; - UpdateCell = 30; + CreateSelectOption = 30; + CreateRow = 50; + GetRow = 51; + UpdateCell = 70; } diff --git a/shared-lib/flowy-error-code/src/code.rs b/shared-lib/flowy-error-code/src/code.rs index 7c813bd1e0..3b0cf331ee 100644 --- a/shared-lib/flowy-error-code/src/code.rs +++ b/shared-lib/flowy-error-code/src/code.rs @@ -99,6 +99,8 @@ pub enum ErrorCode { FieldIdIsEmpty = 440, #[display(fmt = "Field doesn't exist")] FieldDoesNotExist = 441, + #[display(fmt = "The name of the option should not be empty")] + SelectOptionNameIsEmpty = 442, #[display(fmt = "Field's type option data should not be empty")] TypeOptionDataIsEmpty = 450, 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 8e6e1b9621..6e6db9139b 100644 --- a/shared-lib/flowy-error-code/src/protobuf/model/code.rs +++ b/shared-lib/flowy-error-code/src/protobuf/model/code.rs @@ -62,6 +62,7 @@ pub enum ErrorCode { RowIdIsEmpty = 430, FieldIdIsEmpty = 440, FieldDoesNotExist = 441, + SelectOptionNameIsEmpty = 442, TypeOptionDataIsEmpty = 450, InvalidData = 500, } @@ -110,6 +111,7 @@ impl ::protobuf::ProtobufEnum for ErrorCode { 430 => ::std::option::Option::Some(ErrorCode::RowIdIsEmpty), 440 => ::std::option::Option::Some(ErrorCode::FieldIdIsEmpty), 441 => ::std::option::Option::Some(ErrorCode::FieldDoesNotExist), + 442 => ::std::option::Option::Some(ErrorCode::SelectOptionNameIsEmpty), 450 => ::std::option::Option::Some(ErrorCode::TypeOptionDataIsEmpty), 500 => ::std::option::Option::Some(ErrorCode::InvalidData), _ => ::std::option::Option::None @@ -155,6 +157,7 @@ impl ::protobuf::ProtobufEnum for ErrorCode { ErrorCode::RowIdIsEmpty, ErrorCode::FieldIdIsEmpty, ErrorCode::FieldDoesNotExist, + ErrorCode::SelectOptionNameIsEmpty, ErrorCode::TypeOptionDataIsEmpty, ErrorCode::InvalidData, ]; @@ -185,7 +188,7 @@ impl ::protobuf::reflect::ProtobufValue for ErrorCode { } static file_descriptor_proto_data: &'static [u8] = b"\ - \n\ncode.proto*\x80\x07\n\tErrorCode\x12\x0c\n\x08Internal\x10\0\x12\x14\ + \n\ncode.proto*\x9e\x07\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\ @@ -205,8 +208,9 @@ static file_descriptor_proto_data: &'static [u8] = b"\ erNotExist\x10\xb8\x02\x12\x10\n\x0bTextTooLong\x10\x90\x03\x12\x12\n\rG\ ridIdIsEmpty\x10\x9a\x03\x12\x13\n\x0eBlockIdIsEmpty\x10\xa4\x03\x12\x11\ \n\x0cRowIdIsEmpty\x10\xae\x03\x12\x13\n\x0eFieldIdIsEmpty\x10\xb8\x03\ - \x12\x16\n\x11FieldDoesNotExist\x10\xb9\x03\x12\x1a\n\x15TypeOptionDataI\ - sEmpty\x10\xc2\x03\x12\x10\n\x0bInvalidData\x10\xf4\x03b\x06proto3\ + \x12\x16\n\x11FieldDoesNotExist\x10\xb9\x03\x12\x1c\n\x17SelectOptionNam\ + eIsEmpty\x10\xba\x03\x12\x1a\n\x15TypeOptionDataIsEmpty\x10\xc2\x03\x12\ + \x10\n\x0bInvalidData\x10\xf4\x03b\x06proto3\ "; 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 e01c42aa8b..d435d558dc 100644 --- a/shared-lib/flowy-error-code/src/protobuf/proto/code.proto +++ b/shared-lib/flowy-error-code/src/protobuf/proto/code.proto @@ -38,6 +38,7 @@ enum ErrorCode { RowIdIsEmpty = 430; FieldIdIsEmpty = 440; FieldDoesNotExist = 441; + SelectOptionNameIsEmpty = 442; TypeOptionDataIsEmpty = 450; InvalidData = 500; } 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 dfd5dc397f..a85b8d382a 100644 --- a/shared-lib/flowy-grid-data-model/src/entities/grid.rs +++ b/shared-lib/flowy-grid-data-model/src/entities/grid.rs @@ -1,5 +1,5 @@ use crate::entities::{FieldMeta, FieldType, RowMeta}; -use crate::parser::NotEmptyUuid; +use crate::parser::{NotEmptyStr, NotEmptyUuid}; use flowy_derive::ProtoBuf; use flowy_error_code::ErrorCode; use std::collections::HashMap; @@ -494,3 +494,24 @@ impl TryInto for QueryRowPayload { }) } } + +#[derive(ProtoBuf, Default)] +pub struct CreateSelectOptionPayload { + #[pb(index = 1)] + pub option_name: String, +} + +pub struct CreateSelectOptionParams { + pub option_name: String, +} + +impl TryInto for CreateSelectOptionPayload { + type Error = ErrorCode; + + fn try_into(self) -> Result { + let option_name = NotEmptyStr::parse(self.option_name).map_err(|_| ErrorCode::SelectOptionNameIsEmpty)?; + Ok(CreateSelectOptionParams { + option_name: option_name.0, + }) + } +} diff --git a/shared-lib/flowy-grid-data-model/src/parser/mod.rs b/shared-lib/flowy-grid-data-model/src/parser/mod.rs index 7cb72eb859..3c43c76f39 100644 --- a/shared-lib/flowy-grid-data-model/src/parser/mod.rs +++ b/shared-lib/flowy-grid-data-model/src/parser/mod.rs @@ -1,3 +1,3 @@ -mod id_parser; +mod str_parser; -pub use id_parser::*; +pub use str_parser::*; diff --git a/shared-lib/flowy-grid-data-model/src/parser/id_parser.rs b/shared-lib/flowy-grid-data-model/src/parser/str_parser.rs similarity index 54% rename from shared-lib/flowy-grid-data-model/src/parser/id_parser.rs rename to shared-lib/flowy-grid-data-model/src/parser/str_parser.rs index 5003ab2ce4..3e5e3c622b 100644 --- a/shared-lib/flowy-grid-data-model/src/parser/id_parser.rs +++ b/shared-lib/flowy-grid-data-model/src/parser/str_parser.rs @@ -19,3 +19,21 @@ impl AsRef for NotEmptyUuid { &self.0 } } + +#[derive(Debug)] +pub struct NotEmptyStr(pub String); + +impl NotEmptyStr { + pub fn parse(s: String) -> Result { + if s.trim().is_empty() { + return Err("Input string is empty".to_owned()); + } + Ok(Self(s)) + } +} + +impl AsRef for NotEmptyStr { + fn as_ref(&self) -> &str { + &self.0 + } +} 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 c18043184f..d55c5dac10 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 @@ -5258,6 +5258,165 @@ impl ::protobuf::reflect::ProtobufValue for QueryRowPayload { } } +#[derive(PartialEq,Clone,Default)] +pub struct CreateSelectOptionPayload { + // message fields + pub option_name: ::std::string::String, + // special fields + pub unknown_fields: ::protobuf::UnknownFields, + pub cached_size: ::protobuf::CachedSize, +} + +impl<'a> ::std::default::Default for &'a CreateSelectOptionPayload { + fn default() -> &'a CreateSelectOptionPayload { + ::default_instance() + } +} + +impl CreateSelectOptionPayload { + pub fn new() -> CreateSelectOptionPayload { + ::std::default::Default::default() + } + + // string option_name = 1; + + + pub fn get_option_name(&self) -> &str { + &self.option_name + } + pub fn clear_option_name(&mut self) { + self.option_name.clear(); + } + + // Param is passed by value, moved + pub fn set_option_name(&mut self, v: ::std::string::String) { + self.option_name = v; + } + + // Mutable pointer to the field. + // If field is not initialized, it is initialized with default value first. + pub fn mut_option_name(&mut self) -> &mut ::std::string::String { + &mut self.option_name + } + + // Take field + pub fn take_option_name(&mut self) -> ::std::string::String { + ::std::mem::replace(&mut self.option_name, ::std::string::String::new()) + } +} + +impl ::protobuf::Message for CreateSelectOptionPayload { + 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.option_name)?; + }, + _ => { + ::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.option_name.is_empty() { + my_size += ::protobuf::rt::string_size(1, &self.option_name); + } + 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.option_name.is_empty() { + os.write_string(1, &self.option_name)?; + } + 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() -> CreateSelectOptionPayload { + CreateSelectOptionPayload::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>( + "option_name", + |m: &CreateSelectOptionPayload| { &m.option_name }, + |m: &mut CreateSelectOptionPayload| { &mut m.option_name }, + )); + ::protobuf::reflect::MessageDescriptor::new_pb_name::( + "CreateSelectOptionPayload", + fields, + file_descriptor_proto() + ) + }) + } + + fn default_instance() -> &'static CreateSelectOptionPayload { + static instance: ::protobuf::rt::LazyV2 = ::protobuf::rt::LazyV2::INIT; + instance.get(CreateSelectOptionPayload::new) + } +} + +impl ::protobuf::Clear for CreateSelectOptionPayload { + fn clear(&mut self) { + self.option_name.clear(); + self.unknown_fields.clear(); + } +} + +impl ::std::fmt::Debug for CreateSelectOptionPayload { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for CreateSelectOptionPayload { + fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef { + ::protobuf::reflect::ReflectValueRef::Message(self) + } +} + static file_descriptor_proto_data: &'static [u8] = b"\ \n\ngrid.proto\x1a\nmeta.proto\"z\n\x04Grid\x12\x0e\n\x02id\x18\x01\x20\ \x01(\tR\x02id\x12.\n\x0cfield_orders\x18\x02\x20\x03(\x0b2\x0b.FieldOrd\ @@ -5311,7 +5470,9 @@ static file_descriptor_proto_data: &'static [u8] = b"\ ridId\x122\n\x0cblock_orders\x18\x02\x20\x03(\x0b2\x0f.GridBlockOrderR\ \x0bblockOrders\"\\\n\x0fQueryRowPayload\x12\x17\n\x07grid_id\x18\x01\ \x20\x01(\tR\x06gridId\x12\x19\n\x08block_id\x18\x02\x20\x01(\tR\x07bloc\ - kId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowIdb\x06proto3\ + kId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowId\"<\n\x19CreateSelec\ + tOptionPayload\x12\x1f\n\x0boption_name\x18\x01\x20\x01(\tR\noptionNameb\ + \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 3a74e23026..5c07b98d30 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 @@ -103,3 +103,6 @@ message QueryRowPayload { string block_id = 2; string row_id = 3; } +message CreateSelectOptionPayload { + string option_name = 1; +}