فهرست منبع

chore: multi select

appflowy 3 سال پیش
والد
کامیت
7c6a857a69

+ 3 - 0
frontend/app_flowy/assets/images/grid/checkmark.svg

@@ -0,0 +1,3 @@
+<svg width="10" height="8" viewBox="0 0 10 8" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1 5.2L2.84615 7L9 1" stroke="#00BCF0" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 2 - 2
frontend/app_flowy/lib/startup/deps_resolver.dart

@@ -221,8 +221,8 @@ void _resolveGridDeps(GetIt getIt) {
     (typeOption, fieldId) => SingleSelectTypeOptionBloc(typeOption, fieldId),
   );
 
-  getIt.registerFactoryParam<MultiSelectTypeOptionBloc, MultiSelectTypeOption, void>(
-    (typeOption, _) => MultiSelectTypeOptionBloc(typeOption),
+  getIt.registerFactoryParam<MultiSelectTypeOptionBloc, MultiSelectTypeOption, String>(
+    (typeOption, fieldId) => MultiSelectTypeOptionBloc(typeOption, fieldId),
   );
 
   getIt.registerFactoryParam<DateTypeOptionBloc, DateTypeOption, void>(

+ 52 - 5
frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart

@@ -1,18 +1,37 @@
-import 'dart:typed_data';
+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 'package:protobuf/protobuf.dart';
+import 'type_option_service.dart';
 
 part 'multi_select_bloc.freezed.dart';
 
 class MultiSelectTypeOptionBloc extends Bloc<MultiSelectTypeOptionEvent, MultiSelectTypeOptionState> {
-  MultiSelectTypeOptionBloc(MultiSelectTypeOption typeOption) : super(MultiSelectTypeOptionState.initial(typeOption)) {
+  final TypeOptionService service;
+
+  MultiSelectTypeOptionBloc(MultiSelectTypeOption typeOption, String fieldId)
+      : service = TypeOptionService(fieldId: fieldId),
+        super(MultiSelectTypeOptionState.initial(typeOption)) {
     on<MultiSelectTypeOptionEvent>(
       (event, emit) async {
         await event.map(
-          createOption: (_CreateOption value) {},
-          updateOptions: (_UpdateOptions value) async {},
+          createOption: (_CreateOption value) async {
+            final result = await service.createOption(value.optionName);
+            result.fold(
+              (option) {
+                emit(state.copyWith(typeOption: _insertOption(option)));
+              },
+              (err) => Log.error(err),
+            );
+          },
+          updateOption: (_UpdateOption value) async {
+            emit(state.copyWith(typeOption: _updateOption(value.option)));
+          },
+          deleteOption: (_DeleteOption value) {
+            emit(state.copyWith(typeOption: _deleteOption(value.option)));
+          },
         );
       },
     );
@@ -22,12 +41,40 @@ class MultiSelectTypeOptionBloc extends Bloc<MultiSelectTypeOptionEvent, MultiSe
   Future<void> close() async {
     return super.close();
   }
+
+  MultiSelectTypeOption _insertOption(SelectOption option) {
+    state.typeOption.freeze();
+    return state.typeOption.rebuild((typeOption) {
+      typeOption.options.insert(0, option);
+    });
+  }
+
+  MultiSelectTypeOption _updateOption(SelectOption option) {
+    state.typeOption.freeze();
+    return state.typeOption.rebuild((typeOption) {
+      final index = typeOption.options.indexWhere((element) => element.id == option.id);
+      if (index != -1) {
+        typeOption.options[index] = option;
+      }
+    });
+  }
+
+  MultiSelectTypeOption _deleteOption(SelectOption option) {
+    state.typeOption.freeze();
+    return state.typeOption.rebuild((typeOption) {
+      final index = typeOption.options.indexWhere((element) => element.id == option.id);
+      if (index != -1) {
+        typeOption.options.removeAt(index);
+      }
+    });
+  }
 }
 
 @freezed
 class MultiSelectTypeOptionEvent with _$MultiSelectTypeOptionEvent {
   const factory MultiSelectTypeOptionEvent.createOption(String optionName) = _CreateOption;
-  const factory MultiSelectTypeOptionEvent.updateOptions(List<SelectOption> options) = _UpdateOptions;
+  const factory MultiSelectTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption;
+  const factory MultiSelectTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption;
 }
 
 @freezed

+ 1 - 1
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_tyep_switcher.dart

@@ -156,7 +156,7 @@ TypeOptionBuilder _makeTypeOptionBuild({
     case FieldType.SingleSelect:
       return SingleSelectTypeOptionBuilder(field.id, data, overlayDelegate, dataDelegate);
     case FieldType.MultiSelect:
-      return MultiSelectTypeOptionBuilder(data, overlayDelegate);
+      return MultiSelectTypeOptionBuilder(field.id, data, overlayDelegate, dataDelegate);
     case FieldType.Number:
       return NumberTypeOptionBuilder(data, overlayDelegate, dataDelegate);
     case FieldType.RichText:

+ 34 - 10
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/multi_select.dart

@@ -8,26 +8,45 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 import 'option_pannel.dart';
 
 class MultiSelectTypeOptionBuilder extends TypeOptionBuilder {
-  MultiSelectTypeOption typeOption;
-  TypeOptionOverlayDelegate delegate;
+  MultiSelectTypeOptionWidget _widget;
 
-  MultiSelectTypeOptionBuilder(TypeOptionData typeOptionData, this.delegate)
-      : typeOption = MultiSelectTypeOption.fromBuffer(typeOptionData);
+  MultiSelectTypeOptionBuilder(
+    String fieldId,
+    TypeOptionData typeOptionData,
+    TypeOptionOverlayDelegate overlayDelegate,
+    TypeOptionDataDelegate dataDelegate,
+  ) : _widget = MultiSelectTypeOptionWidget(
+          fieldId: fieldId,
+          typeOption: MultiSelectTypeOption.fromBuffer(typeOptionData),
+          overlayDelegate: overlayDelegate,
+          dataDelegate: dataDelegate,
+        );
 
   @override
-  Widget? get customWidget => MultiSelectTypeOptionWidget(typeOption, delegate);
+  Widget? get customWidget => _widget;
 }
 
 class MultiSelectTypeOptionWidget extends TypeOptionWidget {
+  final String fieldId;
   final MultiSelectTypeOption typeOption;
   final TypeOptionOverlayDelegate overlayDelegate;
-  const MultiSelectTypeOptionWidget(this.typeOption, this.overlayDelegate, {Key? key}) : super(key: key);
+  final TypeOptionDataDelegate dataDelegate;
+  const MultiSelectTypeOptionWidget({
+    required this.fieldId,
+    required this.typeOption,
+    required this.overlayDelegate,
+    required this.dataDelegate,
+    Key? key,
+  }) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
     return BlocProvider(
-      create: (context) => getIt<MultiSelectTypeOptionBloc>(param1: typeOption),
-      child: BlocBuilder<MultiSelectTypeOptionBloc, MultiSelectTypeOptionState>(
+      create: (context) => getIt<MultiSelectTypeOptionBloc>(param1: typeOption, param2: fieldId),
+      child: BlocConsumer<MultiSelectTypeOptionBloc, MultiSelectTypeOptionState>(
+        listener: (context, state) {
+          dataDelegate.didUpdateTypeOptionData(state.typeOption.writeToBuffer());
+        },
         builder: (context, state) {
           return OptionPannel(
             options: state.typeOption.options,
@@ -37,9 +56,14 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
             createOptionCallback: (name) {
               context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.createOption(name));
             },
-            updateOptionCallback: (updateOption) {},
-            deleteOptionCallback: (deleteOption) {},
+            updateOptionCallback: (updateOption) {
+              context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.updateOption(updateOption));
+            },
+            deleteOptionCallback: (deleteOption) {
+              context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.deleteOption(deleteOption));
+            },
             overlayDelegate: overlayDelegate,
+            key: ValueKey(state.typeOption.hashCode),
           );
         },
       ),