Browse Source

chore: optimaze create option progress

appflowy 3 years ago
parent
commit
f3b87d419f

+ 0 - 101
frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_bloc.dart

@@ -1,101 +0,0 @@
-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';
-
-typedef MultiSelectTypeOptionContext = TypeOptionContext<MultiSelectTypeOption>;
-
-class MultiSelectTypeOptionDataBuilder extends TypeOptionDataBuilder<MultiSelectTypeOption> {
-  @override
-  MultiSelectTypeOption fromBuffer(List<int> buffer) {
-    return MultiSelectTypeOption.fromBuffer(buffer);
-  }
-}
-
-class MultiSelectTypeOptionBloc extends Bloc<MultiSelectTypeOptionEvent, MultiSelectTypeOptionState> {
-  final TypeOptionService service;
-
-  MultiSelectTypeOptionBloc(MultiSelectTypeOptionContext typeOptionContext)
-      : service = TypeOptionService(
-          gridId: typeOptionContext.gridId,
-          fieldId: typeOptionContext.field.id,
-        ),
-        super(MultiSelectTypeOptionState.initial(typeOptionContext.typeOption)) {
-    on<MultiSelectTypeOptionEvent>(
-      (event, emit) async {
-        await event.map(
-          createOption: (_CreateOption value) async {
-            final result = await service.newOption(name: 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)));
-          },
-        );
-      },
-    );
-  }
-
-  @override
-  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.updateOption(SelectOption option) = _UpdateOption;
-  const factory MultiSelectTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption;
-}
-
-@freezed
-class MultiSelectTypeOptionState with _$MultiSelectTypeOptionState {
-  const factory MultiSelectTypeOptionState({
-    required MultiSelectTypeOption typeOption,
-  }) = _MultiSelectTypeOptionState;
-
-  factory MultiSelectTypeOptionState.initial(MultiSelectTypeOption typeOption) => MultiSelectTypeOptionState(
-        typeOption: typeOption,
-      );
-}

+ 77 - 0
frontend/app_flowy/lib/workspace/application/grid/field/type_option/multi_select_type_option.dart

@@ -0,0 +1,77 @@
+import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
+import 'package:flowy_sdk/log.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
+import 'dart:async';
+import 'package:protobuf/protobuf.dart';
+import 'select_option_type_option_bloc.dart';
+import 'type_option_service.dart';
+
+class MultiSelectTypeOptionContext extends TypeOptionContext<MultiSelectTypeOption> with SelectOptionTypeOptionAction {
+  final TypeOptionService service;
+
+  MultiSelectTypeOptionContext({
+    required MultiSelectTypeOptionDataBuilder dataBuilder,
+    required GridFieldContext fieldContext,
+  })  : service = TypeOptionService(
+          gridId: fieldContext.gridId,
+          fieldId: fieldContext.field.id,
+        ),
+        super(dataBuilder: dataBuilder, fieldContext: fieldContext);
+
+  @override
+  List<SelectOption> Function(SelectOption) get deleteOption {
+    return (SelectOption option) {
+      typeOption.freeze();
+      typeOption = typeOption.rebuild((typeOption) {
+        final index = typeOption.options.indexWhere((element) => element.id == option.id);
+        if (index != -1) {
+          typeOption.options.removeAt(index);
+        }
+      });
+      return typeOption.options;
+    };
+  }
+
+  @override
+  Future<List<SelectOption>> Function(String) get insertOption {
+    return (String optionName) {
+      return service.newOption(name: optionName).then((result) {
+        return result.fold(
+          (option) {
+            typeOption.freeze();
+            typeOption = typeOption.rebuild((typeOption) {
+              typeOption.options.insert(0, option);
+            });
+
+            return typeOption.options;
+          },
+          (err) {
+            Log.error(err);
+            return typeOption.options;
+          },
+        );
+      });
+    };
+  }
+
+  @override
+  List<SelectOption> Function(SelectOption) get udpateOption {
+    return (SelectOption option) {
+      typeOption.freeze();
+      typeOption = typeOption.rebuild((typeOption) {
+        final index = typeOption.options.indexWhere((element) => element.id == option.id);
+        if (index != -1) {
+          typeOption.options[index] = option;
+        }
+      });
+      return typeOption.options;
+    };
+  }
+}
+
+class MultiSelectTypeOptionDataBuilder extends TypeOptionDataBuilder<MultiSelectTypeOption> {
+  @override
+  MultiSelectTypeOption fromBuffer(List<int> buffer) {
+    return MultiSelectTypeOption.fromBuffer(buffer);
+  }
+}

+ 30 - 19
frontend/app_flowy/lib/workspace/application/grid/field/type_option/select_option_type_option_bloc.dart

@@ -5,26 +5,41 @@ import 'dart:async';
 import 'package:dartz/dartz.dart';
 part 'select_option_type_option_bloc.freezed.dart';
 
-class SelectOptionTypeOptionBloc extends Bloc<SelectOptionTypeOptionEvent, SelectOptionTyepOptionState> {
-  SelectOptionTypeOptionBloc({required List<SelectOption> options})
-      : super(SelectOptionTyepOptionState.initial(options)) {
+abstract class SelectOptionTypeOptionAction {
+  Future<List<SelectOption>> Function(String) get insertOption;
+
+  List<SelectOption> Function(SelectOption) get deleteOption;
+
+  List<SelectOption> Function(SelectOption) get udpateOption;
+}
+
+class SelectOptionTypeOptionBloc extends Bloc<SelectOptionTypeOptionEvent, SelectOptionTypeOptionState> {
+  final SelectOptionTypeOptionAction typeOptionAction;
+
+  SelectOptionTypeOptionBloc({
+    required List<SelectOption> options,
+    required this.typeOptionAction,
+  }) : super(SelectOptionTypeOptionState.initial(options)) {
     on<SelectOptionTypeOptionEvent>(
       (event, emit) async {
-        await event.map(
-          createOption: (_CreateOption value) async {
-            emit(state.copyWith(isEditingOption: true, newOptionName: Some(value.optionName)));
+        await event.when(
+          createOption: (optionName) async {
+            final List<SelectOption> options = await typeOptionAction.insertOption(optionName);
+            emit(state.copyWith(options: options));
           },
-          addingOption: (_AddingOption value) {
+          addingOption: () {
             emit(state.copyWith(isEditingOption: true, newOptionName: none()));
           },
-          endAddingOption: (_EndAddingOption value) {
+          endAddingOption: () {
             emit(state.copyWith(isEditingOption: false, newOptionName: none()));
           },
-          updateOption: (_UpdateOption value) {
-            emit(state.copyWith(updateOption: Some(value.option)));
+          updateOption: (option) {
+            final List<SelectOption> options = typeOptionAction.udpateOption(option);
+            emit(state.copyWith(options: options));
           },
-          deleteOption: (_DeleteOption value) {
-            emit(state.copyWith(deleteOption: Some(value.option)));
+          deleteOption: (option) {
+            final List<SelectOption> options = typeOptionAction.deleteOption(option);
+            emit(state.copyWith(options: options));
           },
         );
       },
@@ -47,20 +62,16 @@ class SelectOptionTypeOptionEvent with _$SelectOptionTypeOptionEvent {
 }
 
 @freezed
-class SelectOptionTyepOptionState with _$SelectOptionTyepOptionState {
-  const factory SelectOptionTyepOptionState({
+class SelectOptionTypeOptionState with _$SelectOptionTypeOptionState {
+  const factory SelectOptionTypeOptionState({
     required List<SelectOption> options,
     required bool isEditingOption,
     required Option<String> newOptionName,
-    required Option<SelectOption> updateOption,
-    required Option<SelectOption> deleteOption,
   }) = _SelectOptionTyepOptionState;
 
-  factory SelectOptionTyepOptionState.initial(List<SelectOption> options) => SelectOptionTyepOptionState(
+  factory SelectOptionTypeOptionState.initial(List<SelectOption> options) => SelectOptionTypeOptionState(
         options: options,
         isEditingOption: false,
         newOptionName: none(),
-        updateOption: none(),
-        deleteOption: none(),
       );
 }

+ 0 - 99
frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_bloc.dart

@@ -1,99 +0,0 @@
-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 'single_select_bloc.freezed.dart';
-
-typedef SingleSelectTypeOptionContext = TypeOptionContext<SingleSelectTypeOption>;
-
-class SingleSelectTypeOptionDataBuilder extends TypeOptionDataBuilder<SingleSelectTypeOption> {
-  @override
-  SingleSelectTypeOption fromBuffer(List<int> buffer) {
-    return SingleSelectTypeOption.fromBuffer(buffer);
-  }
-}
-
-class SingleSelectTypeOptionBloc extends Bloc<SingleSelectTypeOptionEvent, SingleSelectTypeOptionState> {
-  final TypeOptionService service;
-
-  SingleSelectTypeOptionBloc(
-    SingleSelectTypeOptionContext typeOptionContext,
-  )   : service = TypeOptionService(gridId: typeOptionContext.gridId, fieldId: typeOptionContext.field.id),
-        super(SingleSelectTypeOptionState.initial(typeOptionContext.typeOption)) {
-    on<SingleSelectTypeOptionEvent>(
-      (event, emit) async {
-        await event.map(
-          createOption: (_CreateOption value) async {
-            final result = await service.newOption(name: 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)));
-          },
-        );
-      },
-    );
-  }
-
-  @override
-  Future<void> close() async {
-    return super.close();
-  }
-
-  SingleSelectTypeOption _insertOption(SelectOption option) {
-    state.typeOption.freeze();
-    return state.typeOption.rebuild((typeOption) {
-      typeOption.options.insert(0, option);
-    });
-  }
-
-  SingleSelectTypeOption _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;
-      }
-    });
-  }
-
-  SingleSelectTypeOption _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 SingleSelectTypeOptionEvent with _$SingleSelectTypeOptionEvent {
-  const factory SingleSelectTypeOptionEvent.createOption(String optionName) = _CreateOption;
-  const factory SingleSelectTypeOptionEvent.updateOption(SelectOption option) = _UpdateOption;
-  const factory SingleSelectTypeOptionEvent.deleteOption(SelectOption option) = _DeleteOption;
-}
-
-@freezed
-class SingleSelectTypeOptionState with _$SingleSelectTypeOptionState {
-  const factory SingleSelectTypeOptionState({
-    required SingleSelectTypeOption typeOption,
-  }) = _SingleSelectTypeOptionState;
-
-  factory SingleSelectTypeOptionState.initial(SingleSelectTypeOption typeOption) => SingleSelectTypeOptionState(
-        typeOption: typeOption,
-      );
-}

+ 78 - 0
frontend/app_flowy/lib/workspace/application/grid/field/type_option/single_select_type_option.dart

@@ -0,0 +1,78 @@
+import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
+import 'package:flowy_sdk/log.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
+import 'dart:async';
+import 'package:protobuf/protobuf.dart';
+import 'select_option_type_option_bloc.dart';
+import 'type_option_service.dart';
+
+class SingleSelectTypeOptionContext extends TypeOptionContext<SingleSelectTypeOption>
+    with SelectOptionTypeOptionAction {
+  final TypeOptionService service;
+
+  SingleSelectTypeOptionContext({
+    required SingleSelectTypeOptionDataBuilder dataBuilder,
+    required GridFieldContext fieldContext,
+  })  : service = TypeOptionService(
+          gridId: fieldContext.gridId,
+          fieldId: fieldContext.field.id,
+        ),
+        super(dataBuilder: dataBuilder, fieldContext: fieldContext);
+
+  @override
+  List<SelectOption> Function(SelectOption) get deleteOption {
+    return (SelectOption option) {
+      typeOption.freeze();
+      typeOption = typeOption.rebuild((typeOption) {
+        final index = typeOption.options.indexWhere((element) => element.id == option.id);
+        if (index != -1) {
+          typeOption.options.removeAt(index);
+        }
+      });
+      return typeOption.options;
+    };
+  }
+
+  @override
+  Future<List<SelectOption>> Function(String) get insertOption {
+    return (String optionName) {
+      return service.newOption(name: optionName).then((result) {
+        return result.fold(
+          (option) {
+            typeOption.freeze();
+            typeOption = typeOption.rebuild((typeOption) {
+              typeOption.options.insert(0, option);
+            });
+
+            return typeOption.options;
+          },
+          (err) {
+            Log.error(err);
+            return typeOption.options;
+          },
+        );
+      });
+    };
+  }
+
+  @override
+  List<SelectOption> Function(SelectOption) get udpateOption {
+    return (SelectOption option) {
+      typeOption.freeze();
+      typeOption = typeOption.rebuild((typeOption) {
+        final index = typeOption.options.indexWhere((element) => element.id == option.id);
+        if (index != -1) {
+          typeOption.options[index] = option;
+        }
+      });
+      return typeOption.options;
+    };
+  }
+}
+
+class SingleSelectTypeOptionDataBuilder extends TypeOptionDataBuilder<SingleSelectTypeOption> {
+  @override
+  SingleSelectTypeOption fromBuffer(List<int> buffer) {
+    return SingleSelectTypeOption.fromBuffer(buffer);
+  }
+}

+ 1 - 1
frontend/app_flowy/lib/workspace/application/grid/field/type_option/type_option_service.dart

@@ -64,7 +64,7 @@ class TypeOptionContext<T extends GeneratedMessage> {
 
   set typeOption(T typeOption) {
     _fieldContext.typeOptionData = typeOption.writeToBuffer();
-    _typeOptionObject = null;
+    _typeOptionObject = typeOption;
   }
 }
 

+ 1 - 1
frontend/app_flowy/lib/workspace/application/grid/prelude.dart

@@ -13,7 +13,7 @@ export 'field/field_editor_pannel_bloc.dart';
 // Field Type Option
 export 'field/type_option/date_bloc.dart';
 export 'field/type_option/number_bloc.dart';
-export 'field/type_option/single_select_bloc.dart';
+export 'field/type_option/single_select_type_option.dart';
 
 // Cell
 export 'cell/text_cell_bloc.dart';

+ 6 - 0
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/common/text_field.dart

@@ -7,6 +7,7 @@ class InputTextField extends StatefulWidget {
   final void Function(String)? onDone;
   final void Function(String)? onChanged;
   final void Function() onCanceled;
+  final bool autoClearWhenDone;
   final String text;
 
   const InputTextField({
@@ -14,6 +15,7 @@ class InputTextField extends StatefulWidget {
     this.onDone,
     required this.onCanceled,
     this.onChanged,
+    this.autoClearWhenDone = false,
     Key? key,
   }) : super(key: key);
 
@@ -57,6 +59,10 @@ class _InputTextFieldState extends State<InputTextField> {
         if (widget.onDone != null) {
           widget.onDone!(_controller.text);
         }
+
+        if (widget.autoClearWhenDone) {
+          _controller.text = "";
+        }
       },
     );
   }

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

@@ -1,6 +1,6 @@
 import 'dart:typed_data';
 
-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_type_option.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/checkbox.dart';
 import 'package:dartz/dartz.dart' show Either;

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

@@ -1,7 +1,6 @@
-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_type_option.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
 
 import 'select_option.dart';
 
@@ -32,32 +31,12 @@ class MultiSelectTypeOptionWidget extends TypeOptionWidget {
 
   @override
   Widget build(BuildContext context) {
-    return BlocProvider(
-      create: (context) => MultiSelectTypeOptionBloc(typeOptionContext),
-      child: BlocConsumer<MultiSelectTypeOptionBloc, MultiSelectTypeOptionState>(
-        listener: (context, state) {
-          typeOptionContext.typeOption = state.typeOption;
-        },
-        builder: (context, state) {
-          return SelectOptionTypeOptionWidget(
-            options: state.typeOption.options,
-            beginEdit: () {
-              overlayDelegate.hideOverlay(context);
-            },
-            createSelectOptionCallback: (name) {
-              context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.createOption(name));
-            },
-            updateSelectOptionCallback: (option) {
-              context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.updateOption(option));
-            },
-            deleteSelectOptionCallback: (option) {
-              context.read<MultiSelectTypeOptionBloc>().add(MultiSelectTypeOptionEvent.deleteOption(option));
-            },
-            overlayDelegate: overlayDelegate,
-            // key: ValueKey(state.typeOption.hashCode),
-          );
-        },
-      ),
+    return SelectOptionTypeOptionWidget(
+      options: typeOptionContext.typeOption.options,
+      beginEdit: () => overlayDelegate.hideOverlay(context),
+      overlayDelegate: overlayDelegate,
+      typeOptionAction: typeOptionContext,
+      // key: ValueKey(state.typeOption.hashCode),
     );
   }
 }

+ 19 - 36
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/select_option.dart

@@ -19,45 +19,22 @@ import 'select_option_editor.dart';
 class SelectOptionTypeOptionWidget extends StatelessWidget {
   final List<SelectOption> options;
   final VoidCallback beginEdit;
-  final Function(String optionName) createSelectOptionCallback;
-  final Function(SelectOption) updateSelectOptionCallback;
-  final Function(SelectOption) deleteSelectOptionCallback;
   final TypeOptionOverlayDelegate overlayDelegate;
+  final SelectOptionTypeOptionAction typeOptionAction;
 
   const SelectOptionTypeOptionWidget({
     required this.options,
     required this.beginEdit,
-    required this.createSelectOptionCallback,
-    required this.updateSelectOptionCallback,
-    required this.deleteSelectOptionCallback,
     required this.overlayDelegate,
+    required this.typeOptionAction,
     Key? key,
   }) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
     return BlocProvider(
-      create: (context) => SelectOptionTypeOptionBloc(options: options),
-      child: BlocConsumer<SelectOptionTypeOptionBloc, SelectOptionTyepOptionState>(
-        listener: (context, state) {
-          if (state.isEditingOption) {
-            beginEdit();
-          }
-          state.newOptionName.fold(
-            () => null,
-            (optionName) => createSelectOptionCallback(optionName),
-          );
-
-          state.updateOption.fold(
-            () => null,
-            (updateOption) => updateSelectOptionCallback(updateOption),
-          );
-
-          state.deleteOption.fold(
-            () => null,
-            (deleteOption) => deleteSelectOptionCallback(deleteOption),
-          );
-        },
+      create: (context) => SelectOptionTypeOptionBloc(options: options, typeOptionAction: typeOptionAction),
+      child: BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTypeOptionState>(
         builder: (context, state) {
           List<Widget> children = [
             const TypeOptionSeparator(),
@@ -83,7 +60,7 @@ class OptionTitle extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTyepOptionState>(
+    return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTypeOptionState>(
       builder: (context, state) {
         List<Widget> children = [FlowyText.medium(LocaleKeys.grid_field_optionTitle.tr(), fontSize: 12)];
         if (state.options.isNotEmpty) {
@@ -130,7 +107,7 @@ class _OptionList extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTyepOptionState>(
+    return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTypeOptionState>(
       buildWhen: (previous, current) {
         return previous.options != current.options;
       },
@@ -230,13 +207,19 @@ class _CreateOptionTextField extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return InputTextField(
-      text: "",
-      onCanceled: () {
-        context.read<SelectOptionTypeOptionBloc>().add(const SelectOptionTypeOptionEvent.endAddingOption());
-      },
-      onDone: (optionName) {
-        context.read<SelectOptionTypeOptionBloc>().add(SelectOptionTypeOptionEvent.createOption(optionName));
+    return BlocBuilder<SelectOptionTypeOptionBloc, SelectOptionTypeOptionState>(
+      builder: (context, state) {
+        final text = state.newOptionName.foldRight("", (a, previous) => a);
+        return InputTextField(
+          autoClearWhenDone: true,
+          text: text,
+          onCanceled: () {
+            context.read<SelectOptionTypeOptionBloc>().add(const SelectOptionTypeOptionEvent.endAddingOption());
+          },
+          onDone: (optionName) {
+            context.read<SelectOptionTypeOptionBloc>().add(SelectOptionTypeOptionEvent.createOption(optionName));
+          },
+        );
       },
     );
   }

+ 7 - 28
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/single_select.dart

@@ -1,7 +1,6 @@
-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_type_option.dart';
 import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor_pannel.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
 import 'select_option.dart';
 
 class SingleSelectTypeOptionBuilder extends TypeOptionBuilder {
@@ -31,32 +30,12 @@ class SingleSelectTypeOptionWidget extends TypeOptionWidget {
 
   @override
   Widget build(BuildContext context) {
-    return BlocProvider(
-      create: (context) => SingleSelectTypeOptionBloc(typeOptionContext),
-      child: BlocConsumer<SingleSelectTypeOptionBloc, SingleSelectTypeOptionState>(
-        listener: (context, state) {
-          typeOptionContext.typeOption = state.typeOption;
-        },
-        builder: (context, state) {
-          return SelectOptionTypeOptionWidget(
-            options: state.typeOption.options,
-            beginEdit: () {
-              overlayDelegate.hideOverlay(context);
-            },
-            createSelectOptionCallback: (name) {
-              context.read<SingleSelectTypeOptionBloc>().add(SingleSelectTypeOptionEvent.createOption(name));
-            },
-            updateSelectOptionCallback: (option) {
-              context.read<SingleSelectTypeOptionBloc>().add(SingleSelectTypeOptionEvent.updateOption(option));
-            },
-            deleteSelectOptionCallback: (option) {
-              context.read<SingleSelectTypeOptionBloc>().add(SingleSelectTypeOptionEvent.deleteOption(option));
-            },
-            overlayDelegate: overlayDelegate,
-            // key: ValueKey(state.typeOption.hashCode),
-          );
-        },
-      ),
+    return SelectOptionTypeOptionWidget(
+      options: typeOptionContext.typeOption.options,
+      beginEdit: () => overlayDelegate.hideOverlay(context),
+      overlayDelegate: overlayDelegate,
+      typeOptionAction: typeOptionContext,
+      // key: ValueKey(state.typeOption.hashCode),
     );
   }
 }