chore: different color when create option for single-select or multi-select

This commit is contained in:
appflowy 2022-04-18 17:17:42 +08:00
parent 3af558fd94
commit 5ee4b8a2bc
25 changed files with 281 additions and 400 deletions

View File

@ -3,7 +3,6 @@ import 'package:app_flowy/user/application/user_listener.dart';
import 'package:app_flowy/user/application/user_service.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/app/prelude.dart';
import 'package:app_flowy/workspace/application/doc/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/prelude.dart';
import 'package:app_flowy/workspace/application/trash/prelude.dart'; import 'package:app_flowy/workspace/application/trash/prelude.dart';
import 'package:app_flowy/workspace/application/workspace/prelude.dart'; import 'package:app_flowy/workspace/application/workspace/prelude.dart';
@ -19,7 +18,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option.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/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:flowy_sdk/protobuf/flowy-user-data-model/user_profile.pb.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
@ -206,14 +204,6 @@ void _resolveGridDeps(GetIt getIt) {
(context, _) => FieldSwitcherBloc(context), (context, _) => FieldSwitcherBloc(context),
); );
getIt.registerFactoryParam<SingleSelectTypeOptionBloc, SingleSelectTypeOption, String>(
(typeOption, fieldId) => SingleSelectTypeOptionBloc(typeOption, fieldId),
);
getIt.registerFactoryParam<MultiSelectTypeOptionBloc, MultiSelectTypeOption, String>(
(typeOption, fieldId) => MultiSelectTypeOptionBloc(typeOption, fieldId),
);
getIt.registerFactoryParam<DateTypeOptionBloc, DateTypeOption, void>( getIt.registerFactoryParam<DateTypeOptionBloc, DateTypeOption, void>(
(typeOption, _) => DateTypeOptionBloc(typeOption: typeOption), (typeOption, _) => DateTypeOptionBloc(typeOption: typeOption),
); );

View File

@ -1,3 +1,4 @@
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
@ -13,7 +14,7 @@ class SelectOptionService {
required String rowId, required String rowId,
required String name, required String name,
}) { }) {
return GridEventNewSelectOption(SelectOptionName.create()..name = name).send().then( return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then(
(result) { (result) {
return result.fold( return result.fold(
(option) { (option) {

View File

@ -11,14 +11,14 @@ part 'multi_select_bloc.freezed.dart';
class MultiSelectTypeOptionBloc extends Bloc<MultiSelectTypeOptionEvent, MultiSelectTypeOptionState> { class MultiSelectTypeOptionBloc extends Bloc<MultiSelectTypeOptionEvent, MultiSelectTypeOptionState> {
final TypeOptionService service; final TypeOptionService service;
MultiSelectTypeOptionBloc(MultiSelectTypeOption typeOption, String fieldId) MultiSelectTypeOptionBloc(TypeOptionContext typeOptionContext)
: service = TypeOptionService(fieldId: fieldId), : service = TypeOptionService(gridId: typeOptionContext.gridId, fieldId: typeOptionContext.field.id),
super(MultiSelectTypeOptionState.initial(typeOption)) { super(MultiSelectTypeOptionState.initial(MultiSelectTypeOption.fromBuffer(typeOptionContext.data))) {
on<MultiSelectTypeOptionEvent>( on<MultiSelectTypeOptionEvent>(
(event, emit) async { (event, emit) async {
await event.map( await event.map(
createOption: (_CreateOption value) async { createOption: (_CreateOption value) async {
final result = await service.newOption(value.optionName); final result = await service.newOption(name: value.optionName);
result.fold( result.fold(
(option) { (option) {
emit(state.copyWith(typeOption: _insertOption(option))); emit(state.copyWith(typeOption: _insertOption(option)));

View File

@ -12,17 +12,16 @@ class SingleSelectTypeOptionBloc extends Bloc<SingleSelectTypeOptionEvent, Singl
final TypeOptionService service; final TypeOptionService service;
SingleSelectTypeOptionBloc( SingleSelectTypeOptionBloc(
SingleSelectTypeOption typeOption, TypeOptionContext typeOptionContext,
String fieldId, ) : service = TypeOptionService(gridId: typeOptionContext.gridId, fieldId: typeOptionContext.field.id),
) : service = TypeOptionService(fieldId: fieldId),
super( super(
SingleSelectTypeOptionState.initial(typeOption), SingleSelectTypeOptionState.initial(SingleSelectTypeOption.fromBuffer(typeOptionContext.data)),
) { ) {
on<SingleSelectTypeOptionEvent>( on<SingleSelectTypeOptionEvent>(
(event, emit) async { (event, emit) async {
await event.map( await event.map(
createOption: (_CreateOption value) async { createOption: (_CreateOption value) async {
final result = await service.newOption(value.optionName); final result = await service.newOption(name: value.optionName);
result.fold( result.fold(
(option) { (option) {
emit(state.copyWith(typeOption: _insertOption(option))); emit(state.copyWith(typeOption: _insertOption(option)));

View File

@ -1,17 +1,44 @@
import 'dart:typed_data';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.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/cell_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
class TypeOptionService { class TypeOptionService {
final String gridId;
final String fieldId; final String fieldId;
TypeOptionService({ TypeOptionService({
required this.gridId,
required this.fieldId, required this.fieldId,
}); });
Future<Either<SelectOption, FlowyError>> newOption(String name, {bool selected = false}) { Future<Either<SelectOption, FlowyError>> newOption({
final payload = SelectOptionName.create()..name = name; required String name,
}) {
final fieldIdentifier = FieldIdentifierPayload.create()
..gridId = gridId
..fieldId = fieldId;
final payload = CreateSelectOptionPayload.create()
..optionName = name
..fieldIdentifier = fieldIdentifier;
return GridEventNewSelectOption(payload).send(); return GridEventNewSelectOption(payload).send();
} }
} }
class TypeOptionContext {
final String gridId;
final Field field;
final Uint8List data;
const TypeOptionContext({
required this.gridId,
required this.field,
required this.data,
});
}

View File

@ -1,7 +1,7 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart'; import 'package:dartz/dartz.dart' show Either;
import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@ -14,11 +14,14 @@ 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:flowy_sdk/protobuf/flowy-grid/text_type_option.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/prelude.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart';
import 'field_type_extension.dart'; import 'field_type_extension.dart';
import 'package:dartz/dartz.dart' show Either;
import 'type_option/multi_select.dart'; import 'type_option/multi_select.dart';
import 'type_option/number.dart'; import 'type_option/number.dart';
import 'type_option/single_select.dart'; import 'type_option/single_select.dart';
@ -58,11 +61,7 @@ class _FieldSwitcherState extends State<FieldSwitcher> {
}, },
builder: (context, state) { builder: (context, state) {
List<Widget> children = [_switchFieldTypeButton(context, state.field)]; List<Widget> children = [_switchFieldTypeButton(context, state.field)];
final typeOptionWidget = _typeOptionWidget( final typeOptionWidget = _typeOptionWidget(context: context, state: state);
context: context,
field: state.field,
data: state.typeOptionData,
);
if (typeOptionWidget != null) { if (typeOptionWidget != null) {
children.add(typeOptionWidget); children.add(typeOptionWidget);
@ -111,8 +110,7 @@ class _FieldSwitcherState extends State<FieldSwitcher> {
Widget? _typeOptionWidget({ Widget? _typeOptionWidget({
required BuildContext context, required BuildContext context,
required Field field, required FieldSwitchState state,
required TypeOptionData data,
}) { }) {
final overlayDelegate = TypeOptionOverlayDelegate( final overlayDelegate = TypeOptionOverlayDelegate(
showOverlay: _showOverlay, showOverlay: _showOverlay,
@ -123,9 +121,14 @@ class _FieldSwitcherState extends State<FieldSwitcher> {
context.read<FieldSwitcherBloc>().add(FieldSwitchEvent.didUpdateTypeOptionData(data)); context.read<FieldSwitcherBloc>().add(FieldSwitchEvent.didUpdateTypeOptionData(data));
}); });
final typeOptionContext = TypeOptionContext(
gridId: state.gridId,
field: state.field,
data: state.typeOptionData,
);
final builder = _makeTypeOptionBuild( final builder = _makeTypeOptionBuild(
field: field, typeOptionContext: typeOptionContext,
data: data,
overlayDelegate: overlayDelegate, overlayDelegate: overlayDelegate,
dataDelegate: dataDelegate, dataDelegate: dataDelegate,
); );
@ -165,24 +168,23 @@ abstract class TypeOptionBuilder {
} }
TypeOptionBuilder _makeTypeOptionBuild({ TypeOptionBuilder _makeTypeOptionBuild({
required Field field, required TypeOptionContext typeOptionContext,
required TypeOptionData data,
required TypeOptionOverlayDelegate overlayDelegate, required TypeOptionOverlayDelegate overlayDelegate,
required TypeOptionDataDelegate dataDelegate, required TypeOptionDataDelegate dataDelegate,
}) { }) {
switch (field.fieldType) { switch (typeOptionContext.field.fieldType) {
case FieldType.Checkbox: case FieldType.Checkbox:
return CheckboxTypeOptionBuilder(data); return CheckboxTypeOptionBuilder(typeOptionContext.data);
case FieldType.DateTime: case FieldType.DateTime:
return DateTypeOptionBuilder(data, overlayDelegate, dataDelegate); return DateTypeOptionBuilder(typeOptionContext.data, overlayDelegate, dataDelegate);
case FieldType.SingleSelect: case FieldType.SingleSelect:
return SingleSelectTypeOptionBuilder(field.id, data, overlayDelegate, dataDelegate); return SingleSelectTypeOptionBuilder(typeOptionContext, overlayDelegate, dataDelegate);
case FieldType.MultiSelect: case FieldType.MultiSelect:
return MultiSelectTypeOptionBuilder(field.id, data, overlayDelegate, dataDelegate); return MultiSelectTypeOptionBuilder(typeOptionContext, overlayDelegate, dataDelegate);
case FieldType.Number: case FieldType.Number:
return NumberTypeOptionBuilder(data, overlayDelegate, dataDelegate); return NumberTypeOptionBuilder(typeOptionContext.data, overlayDelegate, dataDelegate);
case FieldType.RichText: case FieldType.RichText:
return RichTextTypeOptionBuilder(data); return RichTextTypeOptionBuilder(typeOptionContext.data);
default: default:
throw UnimplementedError; throw UnimplementedError;

View File

@ -1,7 +1,6 @@
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/application/grid/field/type_option/multi_select_bloc.dart';
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -11,13 +10,11 @@ class MultiSelectTypeOptionBuilder extends TypeOptionBuilder {
final MultiSelectTypeOptionWidget _widget; final MultiSelectTypeOptionWidget _widget;
MultiSelectTypeOptionBuilder( MultiSelectTypeOptionBuilder(
String fieldId, TypeOptionContext typeOptionContext,
TypeOptionData typeOptionData,
TypeOptionOverlayDelegate overlayDelegate, TypeOptionOverlayDelegate overlayDelegate,
TypeOptionDataDelegate dataDelegate, TypeOptionDataDelegate dataDelegate,
) : _widget = MultiSelectTypeOptionWidget( ) : _widget = MultiSelectTypeOptionWidget(
fieldId: fieldId, typeOptionContext: typeOptionContext,
typeOption: MultiSelectTypeOption.fromBuffer(typeOptionData),
overlayDelegate: overlayDelegate, overlayDelegate: overlayDelegate,
dataDelegate: dataDelegate, dataDelegate: dataDelegate,
); );
@ -27,13 +24,11 @@ class MultiSelectTypeOptionBuilder extends TypeOptionBuilder {
} }
class MultiSelectTypeOptionWidget extends TypeOptionWidget { class MultiSelectTypeOptionWidget extends TypeOptionWidget {
final String fieldId; final TypeOptionContext typeOptionContext;
final MultiSelectTypeOption typeOption;
final TypeOptionOverlayDelegate overlayDelegate; final TypeOptionOverlayDelegate overlayDelegate;
final TypeOptionDataDelegate dataDelegate; final TypeOptionDataDelegate dataDelegate;
const MultiSelectTypeOptionWidget({ const MultiSelectTypeOptionWidget({
required this.fieldId, required this.typeOptionContext,
required this.typeOption,
required this.overlayDelegate, required this.overlayDelegate,
required this.dataDelegate, required this.dataDelegate,
Key? key, Key? key,
@ -42,7 +37,7 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => getIt<MultiSelectTypeOptionBloc>(param1: typeOption, param2: fieldId), create: (context) => MultiSelectTypeOptionBloc(typeOptionContext),
child: BlocConsumer<MultiSelectTypeOptionBloc, MultiSelectTypeOptionState>( child: BlocConsumer<MultiSelectTypeOptionBloc, MultiSelectTypeOptionState>(
listener: (context, state) { listener: (context, state) {
dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()); dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer());

View File

@ -1,7 +1,6 @@
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/application/grid/field/type_option/single_select_bloc.dart';
import 'package:app_flowy/workspace/application/grid/field/type_option/type_option_service.dart';
import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'field_option_pannel.dart'; import 'field_option_pannel.dart';
@ -10,13 +9,11 @@ class SingleSelectTypeOptionBuilder extends TypeOptionBuilder {
final SingleSelectTypeOptionWidget _widget; final SingleSelectTypeOptionWidget _widget;
SingleSelectTypeOptionBuilder( SingleSelectTypeOptionBuilder(
String fieldId, TypeOptionContext typeOptionContext,
TypeOptionData typeOptionData,
TypeOptionOverlayDelegate overlayDelegate, TypeOptionOverlayDelegate overlayDelegate,
TypeOptionDataDelegate dataDelegate, TypeOptionDataDelegate dataDelegate,
) : _widget = SingleSelectTypeOptionWidget( ) : _widget = SingleSelectTypeOptionWidget(
fieldId: fieldId, typeOptionContext: typeOptionContext,
typeOption: SingleSelectTypeOption.fromBuffer(typeOptionData),
dataDelegate: dataDelegate, dataDelegate: dataDelegate,
overlayDelegate: overlayDelegate, overlayDelegate: overlayDelegate,
); );
@ -26,13 +23,11 @@ class SingleSelectTypeOptionBuilder extends TypeOptionBuilder {
} }
class SingleSelectTypeOptionWidget extends TypeOptionWidget { class SingleSelectTypeOptionWidget extends TypeOptionWidget {
final String fieldId; final TypeOptionContext typeOptionContext;
final SingleSelectTypeOption typeOption;
final TypeOptionOverlayDelegate overlayDelegate; final TypeOptionOverlayDelegate overlayDelegate;
final TypeOptionDataDelegate dataDelegate; final TypeOptionDataDelegate dataDelegate;
const SingleSelectTypeOptionWidget({ const SingleSelectTypeOptionWidget({
required this.fieldId, required this.typeOptionContext,
required this.typeOption,
required this.dataDelegate, required this.dataDelegate,
required this.overlayDelegate, required this.overlayDelegate,
Key? key, Key? key,
@ -41,7 +36,7 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => getIt<SingleSelectTypeOptionBloc>(param1: typeOption, param2: fieldId), create: (context) => SingleSelectTypeOptionBloc(typeOptionContext),
child: BlocConsumer<SingleSelectTypeOptionBloc, SingleSelectTypeOptionState>( child: BlocConsumer<SingleSelectTypeOptionBloc, SingleSelectTypeOptionState>(
listener: (context, state) { listener: (context, state) {
dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer()); dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer());

View File

@ -172,7 +172,7 @@ class GridEventMoveItem {
} }
class GridEventNewSelectOption { class GridEventNewSelectOption {
SelectOptionName request; CreateSelectOptionPayload request;
GridEventNewSelectOption(this.request); GridEventNewSelectOption(this.request);
Future<Either<SelectOption, FlowyError>> send() { Future<Either<SelectOption, FlowyError>> send() {

View File

@ -9,21 +9,23 @@ import 'dart:core' as $core;
import 'package:protobuf/protobuf.dart' as $pb; import 'package:protobuf/protobuf.dart' as $pb;
import 'field_entities.pb.dart' as $0;
class CreateSelectOptionPayload extends $pb.GeneratedMessage { class CreateSelectOptionPayload extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateSelectOptionPayload', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'CreateSelectOptionPayload', createEmptyInstance: create)
..aOM<CellIdentifierPayload>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'cellIdentifier', subBuilder: CellIdentifierPayload.create) ..aOM<$0.FieldIdentifierPayload>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'fieldIdentifier', subBuilder: $0.FieldIdentifierPayload.create)
..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'optionName') ..aOS(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'optionName')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
CreateSelectOptionPayload._() : super(); CreateSelectOptionPayload._() : super();
factory CreateSelectOptionPayload({ factory CreateSelectOptionPayload({
CellIdentifierPayload? cellIdentifier, $0.FieldIdentifierPayload? fieldIdentifier,
$core.String? optionName, $core.String? optionName,
}) { }) {
final _result = create(); final _result = create();
if (cellIdentifier != null) { if (fieldIdentifier != null) {
_result.cellIdentifier = cellIdentifier; _result.fieldIdentifier = fieldIdentifier;
} }
if (optionName != null) { if (optionName != null) {
_result.optionName = optionName; _result.optionName = optionName;
@ -52,15 +54,15 @@ class CreateSelectOptionPayload extends $pb.GeneratedMessage {
static CreateSelectOptionPayload? _defaultInstance; static CreateSelectOptionPayload? _defaultInstance;
@$pb.TagNumber(1) @$pb.TagNumber(1)
CellIdentifierPayload get cellIdentifier => $_getN(0); $0.FieldIdentifierPayload get fieldIdentifier => $_getN(0);
@$pb.TagNumber(1) @$pb.TagNumber(1)
set cellIdentifier(CellIdentifierPayload v) { setField(1, v); } set fieldIdentifier($0.FieldIdentifierPayload v) { setField(1, v); }
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.bool hasCellIdentifier() => $_has(0); $core.bool hasFieldIdentifier() => $_has(0);
@$pb.TagNumber(1) @$pb.TagNumber(1)
void clearCellIdentifier() => clearField(1); void clearFieldIdentifier() => clearField(1);
@$pb.TagNumber(1) @$pb.TagNumber(1)
CellIdentifierPayload ensureCellIdentifier() => $_ensure(0); $0.FieldIdentifierPayload ensureFieldIdentifier() => $_ensure(0);
@$pb.TagNumber(2) @$pb.TagNumber(2)
$core.String get optionName => $_getSZ(1); $core.String get optionName => $_getSZ(1);
@ -147,50 +149,3 @@ class CellIdentifierPayload extends $pb.GeneratedMessage {
void clearRowId() => clearField(3); void clearRowId() => clearField(3);
} }
class SelectOptionName extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'SelectOptionName', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'name')
..hasRequiredFields = false
;
SelectOptionName._() : super();
factory SelectOptionName({
$core.String? name,
}) {
final _result = create();
if (name != null) {
_result.name = name;
}
return _result;
}
factory SelectOptionName.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory SelectOptionName.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')
SelectOptionName clone() => SelectOptionName()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
SelectOptionName copyWith(void Function(SelectOptionName) updates) => super.copyWith((message) => updates(message as SelectOptionName)) as SelectOptionName; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static SelectOptionName create() => SelectOptionName._();
SelectOptionName createEmptyInstance() => create();
static $pb.PbList<SelectOptionName> createRepeated() => $pb.PbList<SelectOptionName>();
@$core.pragma('dart2js:noInline')
static SelectOptionName getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<SelectOptionName>(create);
static SelectOptionName? _defaultInstance;
@$pb.TagNumber(1)
$core.String get name => $_getSZ(0);
@$pb.TagNumber(1)
set name($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasName() => $_has(0);
@$pb.TagNumber(1)
void clearName() => clearField(1);
}

View File

@ -12,13 +12,13 @@ import 'dart:typed_data' as $typed_data;
const CreateSelectOptionPayload$json = const { const CreateSelectOptionPayload$json = const {
'1': 'CreateSelectOptionPayload', '1': 'CreateSelectOptionPayload',
'2': const [ '2': const [
const {'1': 'cell_identifier', '3': 1, '4': 1, '5': 11, '6': '.CellIdentifierPayload', '10': 'cellIdentifier'}, const {'1': 'field_identifier', '3': 1, '4': 1, '5': 11, '6': '.FieldIdentifierPayload', '10': 'fieldIdentifier'},
const {'1': 'option_name', '3': 2, '4': 1, '5': 9, '10': 'optionName'}, const {'1': 'option_name', '3': 2, '4': 1, '5': 9, '10': 'optionName'},
], ],
}; };
/// Descriptor for `CreateSelectOptionPayload`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `CreateSelectOptionPayload`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List createSelectOptionPayloadDescriptor = $convert.base64Decode('ChlDcmVhdGVTZWxlY3RPcHRpb25QYXlsb2FkEj8KD2NlbGxfaWRlbnRpZmllchgBIAEoCzIWLkNlbGxJZGVudGlmaWVyUGF5bG9hZFIOY2VsbElkZW50aWZpZXISHwoLb3B0aW9uX25hbWUYAiABKAlSCm9wdGlvbk5hbWU='); final $typed_data.Uint8List createSelectOptionPayloadDescriptor = $convert.base64Decode('ChlDcmVhdGVTZWxlY3RPcHRpb25QYXlsb2FkEkIKEGZpZWxkX2lkZW50aWZpZXIYASABKAsyFy5GaWVsZElkZW50aWZpZXJQYXlsb2FkUg9maWVsZElkZW50aWZpZXISHwoLb3B0aW9uX25hbWUYAiABKAlSCm9wdGlvbk5hbWU=');
@$core.Deprecated('Use cellIdentifierPayloadDescriptor instead') @$core.Deprecated('Use cellIdentifierPayloadDescriptor instead')
const CellIdentifierPayload$json = const { const CellIdentifierPayload$json = const {
'1': 'CellIdentifierPayload', '1': 'CellIdentifierPayload',
@ -31,13 +31,3 @@ const CellIdentifierPayload$json = const {
/// Descriptor for `CellIdentifierPayload`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `CellIdentifierPayload`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List cellIdentifierPayloadDescriptor = $convert.base64Decode('ChVDZWxsSWRlbnRpZmllclBheWxvYWQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEhkKCGZpZWxkX2lkGAIgASgJUgdmaWVsZElkEhUKBnJvd19pZBgDIAEoCVIFcm93SWQ='); final $typed_data.Uint8List cellIdentifierPayloadDescriptor = $convert.base64Decode('ChVDZWxsSWRlbnRpZmllclBheWxvYWQSFwoHZ3JpZF9pZBgBIAEoCVIGZ3JpZElkEhkKCGZpZWxkX2lkGAIgASgJUgdmaWVsZElkEhUKBnJvd19pZBgDIAEoCVIFcm93SWQ=');
@$core.Deprecated('Use selectOptionNameDescriptor instead')
const SelectOptionName$json = const {
'1': 'SelectOptionName',
'2': const [
const {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'},
],
};
/// Descriptor for `SelectOptionName`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List selectOptionNameDescriptor = $convert.base64Decode('ChBTZWxlY3RPcHRpb25OYW1lEhIKBG5hbWUYASABKAlSBG5hbWU=');

View File

@ -2,9 +2,7 @@
proto_crates = [ proto_crates = [
"src/event_map.rs", "src/event_map.rs",
"src/services/field/type_options", "src/services/field/type_options",
"src/services/field/field_entities.rs", "src/services/entities",
"src/services/cell/cell_entities.rs",
"src/services/row/row_entities.rs",
"src/dart_notification.rs" "src/dart_notification.rs"
] ]
event_files = ["src/event_map.rs"] event_files = ["src/event_map.rs"]

View File

@ -1,10 +1,8 @@
use crate::manager::GridManager; use crate::manager::GridManager;
use crate::services::cell::cell_entities::*; use crate::services::entities::*;
use crate::services::field::field_entities::*;
use crate::services::field::type_options::*; use crate::services::field::type_options::*;
use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_json_str}; use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_json_str};
use crate::services::grid_editor::ClientGridEditor; use crate::services::grid_editor::ClientGridEditor;
use crate::services::row::row_entities::*;
use flowy_error::{ErrorCode, FlowyError, FlowyResult}; use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::entities::*; use flowy_grid_data_model::entities::*;
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult}; use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
@ -248,9 +246,20 @@ pub(crate) async fn update_cell_handler(
} }
#[tracing::instrument(level = "debug", skip_all, err)] #[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn new_select_option_handler(data: Data<SelectOptionName>) -> DataResult<SelectOption, FlowyError> { pub(crate) async fn new_select_option_handler(
let params = data.into_inner(); data: Data<CreateSelectOptionPayload>,
data_result(SelectOption::new(&params.name)) manager: AppData<Arc<GridManager>>,
) -> DataResult<SelectOption, FlowyError> {
let params: CreateSelectOptionParams = data.into_inner().try_into()?;
let editor = manager.get_grid_editor(&params.grid_id)?;
match editor.get_field_meta(&params.field_id).await {
None => Err(ErrorCode::InvalidData.into()),
Some(field_meta) => {
let type_option = select_option_operation(&field_meta)?;
let select_option = type_option.create_option(&params.option_name);
data_result(select_option)
}
}
} }
#[tracing::instrument(level = "debug", skip_all, err)] #[tracing::instrument(level = "debug", skip_all, err)]
@ -337,20 +346,3 @@ pub(crate) async fn update_cell_select_option_handler(
let _ = editor.update_cell(changeset).await?; let _ = editor.update_cell(changeset).await?;
Ok(()) Ok(())
} }
fn select_option_operation(field_meta: &FieldMeta) -> FlowyResult<Box<dyn SelectOptionOperation>> {
match &field_meta.field_type {
FieldType::SingleSelect => {
let type_option = SingleSelectTypeOption::from(field_meta);
Ok(Box::new(type_option))
}
FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field_meta);
Ok(Box::new(type_option))
}
ty => {
tracing::error!("Unsupported field type: {:?} for this handler", ty);
Err(ErrorCode::FieldInvalidOperation.into())
}
}
}

View File

@ -69,7 +69,7 @@ pub enum GridEvent {
#[event(input = "MoveItemPayload")] #[event(input = "MoveItemPayload")]
MoveItem = 17, MoveItem = 17,
#[event(input = "SelectOptionName", output = "SelectOption")] #[event(input = "CreateSelectOptionPayload", output = "SelectOption")]
NewSelectOption = 30, NewSelectOption = 30,
#[event(input = "CellIdentifierPayload", output = "SelectOptionContext")] #[event(input = "CellIdentifierPayload", output = "SelectOptionContext")]

View File

@ -26,7 +26,7 @@
#[derive(PartialEq,Clone,Default)] #[derive(PartialEq,Clone,Default)]
pub struct CreateSelectOptionPayload { pub struct CreateSelectOptionPayload {
// message fields // message fields
pub cell_identifier: ::protobuf::SingularPtrField<CellIdentifierPayload>, pub field_identifier: ::protobuf::SingularPtrField<super::field_entities::FieldIdentifierPayload>,
pub option_name: ::std::string::String, pub option_name: ::std::string::String,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
@ -44,37 +44,37 @@ impl CreateSelectOptionPayload {
::std::default::Default::default() ::std::default::Default::default()
} }
// .CellIdentifierPayload cell_identifier = 1; // .FieldIdentifierPayload field_identifier = 1;
pub fn get_cell_identifier(&self) -> &CellIdentifierPayload { pub fn get_field_identifier(&self) -> &super::field_entities::FieldIdentifierPayload {
self.cell_identifier.as_ref().unwrap_or_else(|| <CellIdentifierPayload as ::protobuf::Message>::default_instance()) self.field_identifier.as_ref().unwrap_or_else(|| <super::field_entities::FieldIdentifierPayload as ::protobuf::Message>::default_instance())
} }
pub fn clear_cell_identifier(&mut self) { pub fn clear_field_identifier(&mut self) {
self.cell_identifier.clear(); self.field_identifier.clear();
} }
pub fn has_cell_identifier(&self) -> bool { pub fn has_field_identifier(&self) -> bool {
self.cell_identifier.is_some() self.field_identifier.is_some()
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_cell_identifier(&mut self, v: CellIdentifierPayload) { pub fn set_field_identifier(&mut self, v: super::field_entities::FieldIdentifierPayload) {
self.cell_identifier = ::protobuf::SingularPtrField::some(v); self.field_identifier = ::protobuf::SingularPtrField::some(v);
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. // If field is not initialized, it is initialized with default value first.
pub fn mut_cell_identifier(&mut self) -> &mut CellIdentifierPayload { pub fn mut_field_identifier(&mut self) -> &mut super::field_entities::FieldIdentifierPayload {
if self.cell_identifier.is_none() { if self.field_identifier.is_none() {
self.cell_identifier.set_default(); self.field_identifier.set_default();
} }
self.cell_identifier.as_mut().unwrap() self.field_identifier.as_mut().unwrap()
} }
// Take field // Take field
pub fn take_cell_identifier(&mut self) -> CellIdentifierPayload { pub fn take_field_identifier(&mut self) -> super::field_entities::FieldIdentifierPayload {
self.cell_identifier.take().unwrap_or_else(|| CellIdentifierPayload::new()) self.field_identifier.take().unwrap_or_else(|| super::field_entities::FieldIdentifierPayload::new())
} }
// string option_name = 2; // string option_name = 2;
@ -106,7 +106,7 @@ impl CreateSelectOptionPayload {
impl ::protobuf::Message for CreateSelectOptionPayload { impl ::protobuf::Message for CreateSelectOptionPayload {
fn is_initialized(&self) -> bool { fn is_initialized(&self) -> bool {
for v in &self.cell_identifier { for v in &self.field_identifier {
if !v.is_initialized() { if !v.is_initialized() {
return false; return false;
} }
@ -119,7 +119,7 @@ impl ::protobuf::Message for CreateSelectOptionPayload {
let (field_number, wire_type) = is.read_tag_unpack()?; let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number { match field_number {
1 => { 1 => {
::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.cell_identifier)?; ::protobuf::rt::read_singular_message_into(wire_type, is, &mut self.field_identifier)?;
}, },
2 => { 2 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.option_name)?; ::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.option_name)?;
@ -136,7 +136,7 @@ impl ::protobuf::Message for CreateSelectOptionPayload {
#[allow(unused_variables)] #[allow(unused_variables)]
fn compute_size(&self) -> u32 { fn compute_size(&self) -> u32 {
let mut my_size = 0; let mut my_size = 0;
if let Some(ref v) = self.cell_identifier.as_ref() { if let Some(ref v) = self.field_identifier.as_ref() {
let len = v.compute_size(); let len = v.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len; my_size += 1 + ::protobuf::rt::compute_raw_varint32_size(len) + len;
} }
@ -149,7 +149,7 @@ impl ::protobuf::Message for CreateSelectOptionPayload {
} }
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if let Some(ref v) = self.cell_identifier.as_ref() { if let Some(ref v) = self.field_identifier.as_ref() {
os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?; os.write_tag(1, ::protobuf::wire_format::WireTypeLengthDelimited)?;
os.write_raw_varint32(v.get_cached_size())?; os.write_raw_varint32(v.get_cached_size())?;
v.write_to_with_cached_sizes(os)?; v.write_to_with_cached_sizes(os)?;
@ -195,10 +195,10 @@ impl ::protobuf::Message for CreateSelectOptionPayload {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| { descriptor.get(|| {
let mut fields = ::std::vec::Vec::new(); let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<CellIdentifierPayload>>( fields.push(::protobuf::reflect::accessor::make_singular_ptr_field_accessor::<_, ::protobuf::types::ProtobufTypeMessage<super::field_entities::FieldIdentifierPayload>>(
"cell_identifier", "field_identifier",
|m: &CreateSelectOptionPayload| { &m.cell_identifier }, |m: &CreateSelectOptionPayload| { &m.field_identifier },
|m: &mut CreateSelectOptionPayload| { &mut m.cell_identifier }, |m: &mut CreateSelectOptionPayload| { &mut m.field_identifier },
)); ));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"option_name", "option_name",
@ -221,7 +221,7 @@ impl ::protobuf::Message for CreateSelectOptionPayload {
impl ::protobuf::Clear for CreateSelectOptionPayload { impl ::protobuf::Clear for CreateSelectOptionPayload {
fn clear(&mut self) { fn clear(&mut self) {
self.cell_identifier.clear(); self.field_identifier.clear();
self.option_name.clear(); self.option_name.clear();
self.unknown_fields.clear(); self.unknown_fields.clear();
} }
@ -482,173 +482,14 @@ impl ::protobuf::reflect::ProtobufValue for CellIdentifierPayload {
} }
} }
#[derive(PartialEq,Clone,Default)]
pub struct SelectOptionName {
// message fields
pub name: ::std::string::String,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a SelectOptionName {
fn default() -> &'a SelectOptionName {
<SelectOptionName as ::protobuf::Message>::default_instance()
}
}
impl SelectOptionName {
pub fn new() -> SelectOptionName {
::std::default::Default::default()
}
// string name = 1;
pub fn get_name(&self) -> &str {
&self.name
}
pub fn clear_name(&mut self) {
self.name.clear();
}
// Param is passed by value, moved
pub fn set_name(&mut self, v: ::std::string::String) {
self.name = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_name(&mut self) -> &mut ::std::string::String {
&mut self.name
}
// Take field
pub fn take_name(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.name, ::std::string::String::new())
}
}
impl ::protobuf::Message for SelectOptionName {
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.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.name.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.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.name.is_empty() {
os.write_string(1, &self.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<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
self
}
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
Self::descriptor_static()
}
fn new() -> SelectOptionName {
SelectOptionName::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>(
"name",
|m: &SelectOptionName| { &m.name },
|m: &mut SelectOptionName| { &mut m.name },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<SelectOptionName>(
"SelectOptionName",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static SelectOptionName {
static instance: ::protobuf::rt::LazyV2<SelectOptionName> = ::protobuf::rt::LazyV2::INIT;
instance.get(SelectOptionName::new)
}
}
impl ::protobuf::Clear for SelectOptionName {
fn clear(&mut self) {
self.name.clear();
self.unknown_fields.clear();
}
}
impl ::std::fmt::Debug for SelectOptionName {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for SelectOptionName {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x13cell_entities.proto\"}\n\x19CreateSelectOptionPayload\x12?\n\x0fce\ \n\x13cell_entities.proto\x1a\x14field_entities.proto\"\x80\x01\n\x19Cre\
ll_identifier\x18\x01\x20\x01(\x0b2\x16.CellIdentifierPayloadR\x0ecellId\ ateSelectOptionPayload\x12B\n\x10field_identifier\x18\x01\x20\x01(\x0b2\
entifier\x12\x1f\n\x0boption_name\x18\x02\x20\x01(\tR\noptionName\"b\n\ \x17.FieldIdentifierPayloadR\x0ffieldIdentifier\x12\x1f\n\x0boption_name\
\x15CellIdentifierPayload\x12\x17\n\x07grid_id\x18\x01\x20\x01(\tR\x06gr\ \x18\x02\x20\x01(\tR\noptionName\"b\n\x15CellIdentifierPayload\x12\x17\n\
idId\x12\x19\n\x08field_id\x18\x02\x20\x01(\tR\x07fieldId\x12\x15\n\x06r\ \x07grid_id\x18\x01\x20\x01(\tR\x06gridId\x12\x19\n\x08field_id\x18\x02\
ow_id\x18\x03\x20\x01(\tR\x05rowId\"&\n\x10SelectOptionName\x12\x12\n\ \x20\x01(\tR\x07fieldId\x12\x15\n\x06row_id\x18\x03\x20\x01(\tR\x05rowId\
\x04name\x18\x01\x20\x01(\tR\x04nameb\x06proto3\ b\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -1,7 +1,8 @@
syntax = "proto3"; syntax = "proto3";
import "field_entities.proto";
message CreateSelectOptionPayload { message CreateSelectOptionPayload {
CellIdentifierPayload cell_identifier = 1; FieldIdentifierPayload field_identifier = 1;
string option_name = 2; string option_name = 2;
} }
message CellIdentifierPayload { message CellIdentifierPayload {
@ -9,6 +10,3 @@ message CellIdentifierPayload {
string field_id = 2; string field_id = 2;
string row_id = 3; string row_id = 3;
} }
message SelectOptionName {
string name = 1;
}

View File

@ -1,3 +0,0 @@
pub(crate) mod cell_entities;
pub use cell_entities::*;

View File

@ -1,3 +1,4 @@
use crate::services::entities::{FieldIdentifier, FieldIdentifierPayload};
use flowy_derive::ProtoBuf; use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode; use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr; use flowy_grid_data_model::parser::NotEmptyStr;
@ -5,25 +6,33 @@ use flowy_grid_data_model::parser::NotEmptyStr;
#[derive(ProtoBuf, Default)] #[derive(ProtoBuf, Default)]
pub struct CreateSelectOptionPayload { pub struct CreateSelectOptionPayload {
#[pb(index = 1)] #[pb(index = 1)]
pub cell_identifier: CellIdentifierPayload, pub field_identifier: FieldIdentifierPayload,
#[pb(index = 2)] #[pb(index = 2)]
pub option_name: String, pub option_name: String,
} }
pub struct CreateSelectOptionParams { pub struct CreateSelectOptionParams {
pub cell_identifier: CellIdentifier, pub field_identifier: FieldIdentifier,
pub option_name: String, pub option_name: String,
} }
impl std::ops::Deref for CreateSelectOptionParams {
type Target = FieldIdentifier;
fn deref(&self) -> &Self::Target {
&self.field_identifier
}
}
impl TryInto<CreateSelectOptionParams> for CreateSelectOptionPayload { impl TryInto<CreateSelectOptionParams> for CreateSelectOptionPayload {
type Error = ErrorCode; type Error = ErrorCode;
fn try_into(self) -> Result<CreateSelectOptionParams, Self::Error> { fn try_into(self) -> Result<CreateSelectOptionParams, Self::Error> {
let option_name = NotEmptyStr::parse(self.option_name).map_err(|_| ErrorCode::SelectOptionNameIsEmpty)?; let option_name = NotEmptyStr::parse(self.option_name).map_err(|_| ErrorCode::SelectOptionNameIsEmpty)?;
let cell_identifier = self.cell_identifier.try_into()?; let field_identifier = self.field_identifier.try_into()?;
Ok(CreateSelectOptionParams { Ok(CreateSelectOptionParams {
cell_identifier, field_identifier,
option_name: option_name.0, option_name: option_name.0,
}) })
} }
@ -61,9 +70,3 @@ impl TryInto<CellIdentifier> for CellIdentifierPayload {
}) })
} }
} }
#[derive(ProtoBuf, Default)]
pub struct SelectOptionName {
#[pb(index = 1)]
pub name: String,
}

View File

@ -0,0 +1,7 @@
mod cell_entities;
mod field_entities;
mod row_entities;
pub use cell_entities::*;
pub use field_entities::*;
pub use row_entities::*;

View File

@ -0,0 +1,31 @@
use flowy_derive::ProtoBuf;
use flowy_error::ErrorCode;
use flowy_grid_data_model::parser::NotEmptyStr;
#[derive(ProtoBuf, Default)]
pub struct RowIdentifierPayload {
#[pb(index = 1)]
pub grid_id: String,
#[pb(index = 3)]
pub row_id: String,
}
pub struct RowIdentifier {
pub grid_id: String,
pub row_id: String,
}
impl TryInto<RowIdentifier> for RowIdentifierPayload {
type Error = ErrorCode;
fn try_into(self) -> Result<RowIdentifier, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let row_id = NotEmptyStr::parse(self.row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?;
Ok(RowIdentifier {
grid_id: grid_id.0,
row_id: row_id.0,
})
}
}

View File

@ -1,7 +1,5 @@
mod field_builder; mod field_builder;
pub(crate) mod field_entities;
pub(crate) mod type_options; pub(crate) mod type_options;
pub use field_builder::*; pub use field_builder::*;
pub use field_entities::*;
pub use type_options::*; pub use type_options::*;

View File

@ -1,10 +1,10 @@
use crate::impl_type_option; use crate::impl_type_option;
use crate::services::cell::{CellIdentifier, CellIdentifierPayload}; use crate::services::entities::{CellIdentifier, CellIdentifierPayload};
use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder}; use crate::services::field::{BoxTypeOptionBuilder, TypeOptionBuilder};
use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData}; use crate::services::row::{CellDataChangeset, CellDataOperation, TypeOptionCellData};
use bytes::Bytes; use bytes::Bytes;
use flowy_derive::{ProtoBuf, ProtoBuf_Enum}; use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
use flowy_error::{ErrorCode, FlowyError}; use flowy_error::{ErrorCode, FlowyError, FlowyResult};
use flowy_grid_data_model::entities::{ use flowy_grid_data_model::entities::{
CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry, CellChangeset, CellMeta, FieldMeta, FieldType, TypeOptionDataDeserializer, TypeOptionDataEntry,
}; };
@ -36,10 +36,35 @@ pub trait SelectOptionOperation: TypeOptionDataEntry + Send + Sync {
} }
} }
fn create_option(&self, name: &str) -> SelectOption {
let color = select_option_color_from_index(self.options().len());
SelectOption::with_color(name, color)
}
fn option_context(&self, cell_meta: &Option<CellMeta>) -> SelectOptionContext; fn option_context(&self, cell_meta: &Option<CellMeta>) -> SelectOptionContext;
fn options(&self) -> &Vec<SelectOption>;
fn mut_options(&mut self) -> &mut Vec<SelectOption>; fn mut_options(&mut self) -> &mut Vec<SelectOption>;
} }
pub fn select_option_operation(field_meta: &FieldMeta) -> FlowyResult<Box<dyn SelectOptionOperation>> {
match &field_meta.field_type {
FieldType::SingleSelect => {
let type_option = SingleSelectTypeOption::from(field_meta);
Ok(Box::new(type_option))
}
FieldType::MultiSelect => {
let type_option = MultiSelectTypeOption::from(field_meta);
Ok(Box::new(type_option))
}
ty => {
tracing::error!("Unsupported field type: {:?} for this handler", ty);
Err(ErrorCode::FieldInvalidOperation.into())
}
}
}
// Single select // Single select
#[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)] #[derive(Clone, Debug, Default, Serialize, Deserialize, ProtoBuf)]
pub struct SingleSelectTypeOption { pub struct SingleSelectTypeOption {
@ -60,6 +85,10 @@ impl SelectOptionOperation for SingleSelectTypeOption {
} }
} }
fn options(&self) -> &Vec<SelectOption> {
&self.options
}
fn mut_options(&mut self) -> &mut Vec<SelectOption> { fn mut_options(&mut self) -> &mut Vec<SelectOption> {
&mut self.options &mut self.options
} }
@ -155,6 +184,10 @@ impl SelectOptionOperation for MultiSelectTypeOption {
} }
} }
fn options(&self) -> &Vec<SelectOption> {
&self.options
}
fn mut_options(&mut self) -> &mut Vec<SelectOption> { fn mut_options(&mut self) -> &mut Vec<SelectOption> {
&mut self.options &mut self.options
} }
@ -265,6 +298,14 @@ impl SelectOption {
color: SelectOptionColor::default(), color: SelectOptionColor::default(),
} }
} }
pub fn with_color(name: &str, color: SelectOptionColor) -> Self {
SelectOption {
id: nanoid!(4),
name: name.to_owned(),
color,
}
}
} }
#[derive(Clone, Debug, Default, ProtoBuf)] #[derive(Clone, Debug, Default, ProtoBuf)]
@ -430,6 +471,21 @@ pub enum SelectOptionColor {
Blue = 8, Blue = 8,
} }
pub fn select_option_color_from_index(index: usize) -> SelectOptionColor {
match index % 8 {
0 => SelectOptionColor::Purple,
1 => SelectOptionColor::Pink,
2 => SelectOptionColor::LightPink,
3 => SelectOptionColor::Orange,
4 => SelectOptionColor::Yellow,
5 => SelectOptionColor::Lime,
6 => SelectOptionColor::Green,
7 => SelectOptionColor::Aqua,
8 => SelectOptionColor::Blue,
_ => SelectOptionColor::Purple,
}
}
impl std::default::Default for SelectOptionColor { impl std::default::Default for SelectOptionColor {
fn default() -> Self { fn default() -> Self {
SelectOptionColor::Purple SelectOptionColor::Purple

View File

@ -1,8 +1,11 @@
use crate::dart_notification::{send_dart_notification, GridNotification}; use crate::dart_notification::{send_dart_notification, GridNotification};
use crate::manager::GridUser; use crate::manager::GridUser;
use crate::services::block_meta_manager::GridBlockMetaEditorManager; use crate::services::block_meta_manager::GridBlockMetaEditorManager;
use crate::services::cell::CellIdentifier; use crate::services::entities::{CellIdentifier, CreateSelectOptionParams};
use crate::services::field::{default_type_option_builder_from_type, type_option_builder_from_bytes, FieldBuilder}; use crate::services::field::{
default_type_option_builder_from_type, select_option_operation, type_option_builder_from_bytes, FieldBuilder,
SelectOption,
};
use crate::services::persistence::block_index::BlockIndexPersistence; use crate::services::persistence::block_index::BlockIndexPersistence;
use crate::services::row::*; use crate::services::row::*;
use bytes::Bytes; use bytes::Bytes;
@ -22,7 +25,7 @@ use tokio::sync::RwLock;
pub struct ClientGridEditor { pub struct ClientGridEditor {
grid_id: String, grid_id: String,
user: Arc<dyn GridUser>, user: Arc<dyn GridUser>,
pad: Arc<RwLock<GridMetaPad>>, grid_pad: Arc<RwLock<GridMetaPad>>,
rev_manager: Arc<RevisionManager>, rev_manager: Arc<RevisionManager>,
block_meta_manager: Arc<GridBlockMetaEditorManager>, block_meta_manager: Arc<GridBlockMetaEditorManager>,
} }
@ -38,14 +41,14 @@ impl ClientGridEditor {
let cloud = Arc::new(GridRevisionCloudService { token }); let cloud = Arc::new(GridRevisionCloudService { token });
let grid_pad = rev_manager.load::<GridPadBuilder>(Some(cloud)).await?; let grid_pad = rev_manager.load::<GridPadBuilder>(Some(cloud)).await?;
let rev_manager = Arc::new(rev_manager); let rev_manager = Arc::new(rev_manager);
let pad = Arc::new(RwLock::new(grid_pad)); let grid_pad = Arc::new(RwLock::new(grid_pad));
let blocks = pad.read().await.get_block_metas(); let blocks = grid_pad.read().await.get_block_metas();
let block_meta_manager = Arc::new(GridBlockMetaEditorManager::new(grid_id, &user, blocks, persistence).await?); let block_meta_manager = Arc::new(GridBlockMetaEditorManager::new(grid_id, &user, blocks, persistence).await?);
Ok(Arc::new(Self { Ok(Arc::new(Self {
grid_id: grid_id.to_owned(), grid_id: grid_id.to_owned(),
user, user,
pad, grid_pad,
rev_manager, rev_manager,
block_meta_manager, block_meta_manager,
})) }))
@ -94,18 +97,18 @@ impl ClientGridEditor {
} }
pub async fn create_next_field_meta(&self, field_type: &FieldType) -> FlowyResult<FieldMeta> { pub async fn create_next_field_meta(&self, field_type: &FieldType) -> FlowyResult<FieldMeta> {
let name = format!("Property {}", self.pad.read().await.fields().len() + 1); let name = format!("Property {}", self.grid_pad.read().await.fields().len() + 1);
let field_meta = FieldBuilder::from_field_type(field_type).name(&name).build(); let field_meta = FieldBuilder::from_field_type(field_type).name(&name).build();
Ok(field_meta) Ok(field_meta)
} }
pub async fn contain_field(&self, field_id: &str) -> bool { pub async fn contain_field(&self, field_id: &str) -> bool {
self.pad.read().await.contain_field(field_id) self.grid_pad.read().await.contain_field(field_id)
} }
pub async fn update_field(&self, params: FieldChangesetParams) -> FlowyResult<()> { pub async fn update_field(&self, params: FieldChangesetParams) -> FlowyResult<()> {
let field_id = params.field_id.clone(); let field_id = params.field_id.clone();
let json_deserializer = match self.pad.read().await.get_field_meta(params.field_id.as_str()) { let json_deserializer = match self.grid_pad.read().await.get_field_meta(params.field_id.as_str()) {
None => return Err(ErrorCode::FieldDoesNotExist.into()), None => return Err(ErrorCode::FieldDoesNotExist.into()),
Some((_, field_meta)) => TypeOptionJsonDeserializer(field_meta.field_type.clone()), Some((_, field_meta)) => TypeOptionJsonDeserializer(field_meta.field_type.clone()),
}; };
@ -169,7 +172,7 @@ impl ClientGridEditor {
} }
pub async fn get_field_meta(&self, field_id: &str) -> Option<FieldMeta> { pub async fn get_field_meta(&self, field_id: &str) -> Option<FieldMeta> {
let field_meta = self.pad.read().await.get_field_meta(field_id)?.1.clone(); let field_meta = self.grid_pad.read().await.get_field_meta(field_id)?.1.clone();
Some(field_meta) Some(field_meta)
} }
@ -178,14 +181,14 @@ impl ClientGridEditor {
T: Into<FieldOrder>, T: Into<FieldOrder>,
{ {
if field_ids.is_none() { if field_ids.is_none() {
let field_metas = self.pad.read().await.get_field_metas(None)?; let field_metas = self.grid_pad.read().await.get_field_metas(None)?;
return Ok(field_metas); return Ok(field_metas);
} }
let to_field_orders = |item: Vec<T>| item.into_iter().map(|data| data.into()).collect(); let to_field_orders = |item: Vec<T>| item.into_iter().map(|data| data.into()).collect();
let field_orders = field_ids.map_or(vec![], to_field_orders); let field_orders = field_ids.map_or(vec![], to_field_orders);
let expected_len = field_orders.len(); let expected_len = field_orders.len();
let field_metas = self.pad.read().await.get_field_metas(Some(field_orders))?; let field_metas = self.grid_pad.read().await.get_field_metas(Some(field_orders))?;
if expected_len != 0 && field_metas.len() != expected_len { if expected_len != 0 && field_metas.len() != expected_len {
tracing::error!( tracing::error!(
"This is a bug. The len of the field_metas should equal to {}", "This is a bug. The len of the field_metas should equal to {}",
@ -207,7 +210,7 @@ impl ClientGridEditor {
} }
pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<RowOrder> { pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<RowOrder> {
let field_metas = self.pad.read().await.get_field_metas(None)?; let field_metas = self.grid_pad.read().await.get_field_metas(None)?;
let block_id = self.block_id().await?; let block_id = self.block_id().await?;
// insert empty row below the row whose id is upper_row_id // insert empty row below the row whose id is upper_row_id
@ -314,7 +317,7 @@ impl ClientGridEditor {
let cell_data_changeset = changeset.data.unwrap(); let cell_data_changeset = changeset.data.unwrap();
let cell_meta = self.get_cell_meta(&changeset.row_id, &changeset.field_id).await?; let cell_meta = self.get_cell_meta(&changeset.row_id, &changeset.field_id).await?;
tracing::trace!("{}: {:?}", &changeset.field_id, cell_meta); tracing::trace!("{}: {:?}", &changeset.field_id, cell_meta);
match self.pad.read().await.get_field_meta(&changeset.field_id) { match self.grid_pad.read().await.get_field_meta(&changeset.field_id) {
None => { None => {
let msg = format!("Field not found with id: {}", &changeset.field_id); let msg = format!("Field not found with id: {}", &changeset.field_id);
Err(FlowyError::internal().context(msg)) Err(FlowyError::internal().context(msg))
@ -334,7 +337,7 @@ impl ClientGridEditor {
} }
pub async fn get_block_metas(&self) -> FlowyResult<Vec<GridBlockMeta>> { pub async fn get_block_metas(&self) -> FlowyResult<Vec<GridBlockMeta>> {
let grid_blocks = self.pad.read().await.get_block_metas(); let grid_blocks = self.grid_pad.read().await.get_block_metas();
Ok(grid_blocks) Ok(grid_blocks)
} }
@ -347,7 +350,7 @@ impl ClientGridEditor {
} }
pub async fn grid_data(&self) -> FlowyResult<Grid> { pub async fn grid_data(&self) -> FlowyResult<Grid> {
let pad_read_guard = self.pad.read().await; let pad_read_guard = self.grid_pad.read().await;
let field_orders = pad_read_guard.get_field_orders(); let field_orders = pad_read_guard.get_field_orders();
let mut block_orders = vec![]; let mut block_orders = vec![];
for block_order in pad_read_guard.get_block_metas() { for block_order in pad_read_guard.get_block_metas() {
@ -369,7 +372,7 @@ impl ClientGridEditor {
pub async fn grid_block_snapshots(&self, block_ids: Option<Vec<String>>) -> FlowyResult<Vec<GridBlockSnapshot>> { pub async fn grid_block_snapshots(&self, block_ids: Option<Vec<String>>) -> FlowyResult<Vec<GridBlockSnapshot>> {
let block_ids = match block_ids { let block_ids = match block_ids {
None => self None => self
.pad .grid_pad
.read() .read()
.await .await
.get_block_metas() .get_block_metas()
@ -396,7 +399,7 @@ impl ClientGridEditor {
let _ = self let _ = self
.modify(|grid_pad| Ok(grid_pad.move_field(field_id, from as usize, to as usize)?)) .modify(|grid_pad| Ok(grid_pad.move_field(field_id, from as usize, to as usize)?))
.await?; .await?;
if let Some((index, field_meta)) = self.pad.read().await.get_field_meta(field_id) { if let Some((index, field_meta)) = self.grid_pad.read().await.get_field_meta(field_id) {
let delete_field_order = FieldOrder::from(field_id); let delete_field_order = FieldOrder::from(field_id);
let insert_field = IndexField::from_field_meta(field_meta, index); let insert_field = IndexField::from_field_meta(field_meta, index);
let notified_changeset = GridFieldChangeset { let notified_changeset = GridFieldChangeset {
@ -420,14 +423,14 @@ impl ClientGridEditor {
} }
pub async fn delta_bytes(&self) -> Bytes { pub async fn delta_bytes(&self) -> Bytes {
self.pad.read().await.delta_bytes() self.grid_pad.read().await.delta_bytes()
} }
async fn modify<F>(&self, f: F) -> FlowyResult<()> async fn modify<F>(&self, f: F) -> FlowyResult<()>
where where
F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult<Option<GridChangeset>>, F: for<'a> FnOnce(&'a mut GridMetaPad) -> FlowyResult<Option<GridChangeset>>,
{ {
let mut write_guard = self.pad.write().await; let mut write_guard = self.grid_pad.write().await;
if let Some(changeset) = f(&mut *write_guard)? { if let Some(changeset) = f(&mut *write_guard)? {
let _ = self.apply_change(changeset).await?; let _ = self.apply_change(changeset).await?;
} }
@ -455,7 +458,7 @@ impl ClientGridEditor {
} }
async fn block_id(&self) -> FlowyResult<String> { async fn block_id(&self) -> FlowyResult<String> {
match self.pad.read().await.get_block_metas().last() { match self.grid_pad.read().await.get_block_metas().last() {
None => Err(FlowyError::internal().context("There is no grid block in this grid")), None => Err(FlowyError::internal().context("There is no grid block in this grid")),
Some(grid_block) => Ok(grid_block.block_id.clone()), Some(grid_block) => Ok(grid_block.block_id.clone()),
} }
@ -463,7 +466,7 @@ impl ClientGridEditor {
#[tracing::instrument(level = "trace", skip_all, err)] #[tracing::instrument(level = "trace", skip_all, err)]
async fn notify_did_insert_grid_field(&self, field_id: &str) -> FlowyResult<()> { async fn notify_did_insert_grid_field(&self, field_id: &str) -> FlowyResult<()> {
if let Some((index, field_meta)) = self.pad.read().await.get_field_meta(field_id) { if let Some((index, field_meta)) = self.grid_pad.read().await.get_field_meta(field_id) {
let index_field = IndexField::from_field_meta(field_meta, index); let index_field = IndexField::from_field_meta(field_meta, index);
let notified_changeset = GridFieldChangeset::insert(&self.grid_id, vec![index_field]); let notified_changeset = GridFieldChangeset::insert(&self.grid_id, vec![index_field]);
let _ = self.notify_did_update_grid(notified_changeset).await?; let _ = self.notify_did_update_grid(notified_changeset).await?;
@ -473,10 +476,13 @@ impl ClientGridEditor {
#[tracing::instrument(level = "trace", skip_all, err)] #[tracing::instrument(level = "trace", skip_all, err)]
async fn notify_did_update_grid_field(&self, field_id: &str) -> FlowyResult<()> { async fn notify_did_update_grid_field(&self, field_id: &str) -> FlowyResult<()> {
let mut field_metas = self.get_field_metas(Some(vec![field_id])).await?; if let Some((_, field_meta)) = self
debug_assert!(field_metas.len() == 1); .grid_pad
.read()
if let Some(field_meta) = field_metas.pop() { .await
.get_field_meta(field_id)
.map(|(index, field)| (index, field.clone()))
{
let updated_field = Field::from(field_meta); let updated_field = Field::from(field_meta);
let notified_changeset = GridFieldChangeset::update(&self.grid_id, vec![updated_field.clone()]); let notified_changeset = GridFieldChangeset::update(&self.grid_id, vec![updated_field.clone()]);
let _ = self.notify_did_update_grid(notified_changeset).await?; let _ = self.notify_did_update_grid(notified_changeset).await?;

View File

@ -2,7 +2,7 @@ mod util;
pub mod block_meta_editor; pub mod block_meta_editor;
mod block_meta_manager; mod block_meta_manager;
pub mod cell; pub mod entities;
pub mod field; pub mod field;
pub mod grid_editor; pub mod grid_editor;
pub mod persistence; pub mod persistence;