mirror of
				https://github.com/AppFlowy-IO/AppFlowy.git
				synced 2025-11-04 03:54:44 +00:00 
			
		
		
		
	chore: more select option cell editor improvements (#5019)
This commit is contained in:
		
							parent
							
								
									129d56e494
								
							
						
					
					
						commit
						53dbef25ab
					
				@ -6,6 +6,7 @@ import 'package:appflowy/plugins/database/domain/field_service.dart';
 | 
			
		||||
import 'package:appflowy/plugins/database/domain/select_option_cell_service.dart';
 | 
			
		||||
import 'package:appflowy_backend/log.dart';
 | 
			
		||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
 | 
			
		||||
import 'package:collection/collection.dart';
 | 
			
		||||
import 'package:flutter/widgets.dart';
 | 
			
		||||
import 'package:flutter_bloc/flutter_bloc.dart';
 | 
			
		||||
import 'package:freezed_annotation/freezed_annotation.dart';
 | 
			
		||||
@ -56,15 +57,20 @@ class SelectOptionCellEditorBloc
 | 
			
		||||
 | 
			
		||||
  VoidCallback? _onCellChangedFn;
 | 
			
		||||
 | 
			
		||||
  final List<SelectOptionPB> allOptions = [];
 | 
			
		||||
  String filter = "";
 | 
			
		||||
 | 
			
		||||
  void _dispatch() {
 | 
			
		||||
    on<SelectOptionCellEditorEvent>(
 | 
			
		||||
      (event, emit) async {
 | 
			
		||||
        await event.when(
 | 
			
		||||
          didReceiveOptions: (options, selectedOptions) {
 | 
			
		||||
            final result = _makeOptions(state.filter, options);
 | 
			
		||||
            final result = _getVisibleOptions(options);
 | 
			
		||||
            allOptions
 | 
			
		||||
              ..clear()
 | 
			
		||||
              ..addAll(options);
 | 
			
		||||
            emit(
 | 
			
		||||
              state.copyWith(
 | 
			
		||||
                allOptions: options,
 | 
			
		||||
                options: result.options,
 | 
			
		||||
                createSelectOptionSuggestion:
 | 
			
		||||
                    result.createSelectOptionSuggestion,
 | 
			
		||||
@ -76,22 +82,19 @@ class SelectOptionCellEditorBloc
 | 
			
		||||
            if (state.createSelectOptionSuggestion == null) {
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
            filter = "";
 | 
			
		||||
            await _createOption(
 | 
			
		||||
              name: state.createSelectOptionSuggestion!.name,
 | 
			
		||||
              color: state.createSelectOptionSuggestion!.color,
 | 
			
		||||
            );
 | 
			
		||||
            emit(
 | 
			
		||||
              state.copyWith(
 | 
			
		||||
                filter: null,
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
            emit(state.copyWith(clearFilter: true));
 | 
			
		||||
          },
 | 
			
		||||
          deleteOption: (option) async {
 | 
			
		||||
            await _deleteOption([option]);
 | 
			
		||||
          },
 | 
			
		||||
          deleteAllOptions: () async {
 | 
			
		||||
            if (state.allOptions.isNotEmpty) {
 | 
			
		||||
              await _deleteOption(state.allOptions);
 | 
			
		||||
            if (allOptions.isNotEmpty) {
 | 
			
		||||
              await _deleteOption(allOptions);
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          updateOption: (option) async {
 | 
			
		||||
@ -99,27 +102,17 @@ class SelectOptionCellEditorBloc
 | 
			
		||||
          },
 | 
			
		||||
          selectOption: (optionId) async {
 | 
			
		||||
            await _selectOptionService.select(optionIds: [optionId]);
 | 
			
		||||
            final selectedOption = [
 | 
			
		||||
              ...state.selectedOptions,
 | 
			
		||||
              state.options.firstWhere(
 | 
			
		||||
                (element) => element.id == optionId,
 | 
			
		||||
              ),
 | 
			
		||||
            ];
 | 
			
		||||
            emit(
 | 
			
		||||
              state.copyWith(
 | 
			
		||||
                selectedOptions: selectedOption,
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
          unSelectOption: (optionId) async {
 | 
			
		||||
            await _selectOptionService.unSelect(optionIds: [optionId]);
 | 
			
		||||
            final selectedOptions = [...state.selectedOptions]
 | 
			
		||||
              ..removeWhere((e) => e.id == optionId);
 | 
			
		||||
            emit(
 | 
			
		||||
              state.copyWith(
 | 
			
		||||
                selectedOptions: selectedOptions,
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
          unSelectLastOption: () async {
 | 
			
		||||
            if (state.selectedOptions.isEmpty) {
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
            final lastSelectedOptionId = state.selectedOptions.last.id;
 | 
			
		||||
            await _selectOptionService
 | 
			
		||||
                .unSelect(optionIds: [lastSelectedOptionId]);
 | 
			
		||||
          },
 | 
			
		||||
          submitTextField: () {
 | 
			
		||||
            _submitTextFieldValue(emit);
 | 
			
		||||
@ -132,64 +125,31 @@ class SelectOptionCellEditorBloc
 | 
			
		||||
          },
 | 
			
		||||
          reorderOption: (fromOptionId, toOptionId) {
 | 
			
		||||
            final options = _typeOptionAction.reorderOption(
 | 
			
		||||
              state.allOptions,
 | 
			
		||||
              allOptions,
 | 
			
		||||
              fromOptionId,
 | 
			
		||||
              toOptionId,
 | 
			
		||||
            );
 | 
			
		||||
            final result = _makeOptions(state.filter, options);
 | 
			
		||||
            emit(
 | 
			
		||||
              state.copyWith(
 | 
			
		||||
                allOptions: options,
 | 
			
		||||
                options: result.options,
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
            allOptions
 | 
			
		||||
              ..clear()
 | 
			
		||||
              ..addAll(options);
 | 
			
		||||
            final result = _getVisibleOptions(options);
 | 
			
		||||
            emit(state.copyWith(options: result.options));
 | 
			
		||||
          },
 | 
			
		||||
          filterOption: (optionName) {
 | 
			
		||||
            _filterOption(optionName, emit);
 | 
			
		||||
          filterOption: (filterText) {
 | 
			
		||||
            _filterOption(filterText, emit);
 | 
			
		||||
          },
 | 
			
		||||
          focusPreviousOption: () {
 | 
			
		||||
            if (state.options.isEmpty) {
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
            if (state.focusedOptionId == null) {
 | 
			
		||||
              emit(state.copyWith(focusedOptionId: state.options.last.id));
 | 
			
		||||
            } else {
 | 
			
		||||
              final currentIndex = state.options
 | 
			
		||||
                  .indexWhere((option) => option.id == state.focusedOptionId);
 | 
			
		||||
 | 
			
		||||
              if (currentIndex != -1) {
 | 
			
		||||
                final newIndex = (currentIndex - 1) % state.options.length;
 | 
			
		||||
                emit(
 | 
			
		||||
                  state.copyWith(
 | 
			
		||||
                    focusedOptionId: state.options[newIndex].id,
 | 
			
		||||
                  ),
 | 
			
		||||
                );
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            _focusOption(true, emit);
 | 
			
		||||
          },
 | 
			
		||||
          focusNextOption: () {
 | 
			
		||||
            if (state.options.isEmpty) {
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
            if (state.focusedOptionId == null) {
 | 
			
		||||
              emit(state.copyWith(focusedOptionId: state.options.first.id));
 | 
			
		||||
            } else {
 | 
			
		||||
              final currentIndex = state.options
 | 
			
		||||
                  .indexWhere((option) => option.id == state.focusedOptionId);
 | 
			
		||||
 | 
			
		||||
              if (currentIndex != -1) {
 | 
			
		||||
                final newIndex = (currentIndex + 1) % state.options.length;
 | 
			
		||||
                emit(
 | 
			
		||||
                  state.copyWith(
 | 
			
		||||
                    focusedOptionId: state.options[newIndex].id,
 | 
			
		||||
                  ),
 | 
			
		||||
                );
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            _focusOption(false, emit);
 | 
			
		||||
          },
 | 
			
		||||
          updateFocusedOption: (optionId) {
 | 
			
		||||
            emit(state.copyWith(focusedOptionId: optionId));
 | 
			
		||||
          },
 | 
			
		||||
          resetClearFilterFlag: () {
 | 
			
		||||
            emit(state.copyWith(clearFilter: false));
 | 
			
		||||
          },
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
@ -233,59 +193,57 @@ class SelectOptionCellEditorBloc
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final optionId = state.focusedOptionId!;
 | 
			
		||||
    final focusedOptionId = state.focusedOptionId!;
 | 
			
		||||
 | 
			
		||||
    if (optionId == createSelectOptionSuggestionId) {
 | 
			
		||||
    if (focusedOptionId == createSelectOptionSuggestionId) {
 | 
			
		||||
      filter = "";
 | 
			
		||||
      _createOption(
 | 
			
		||||
        name: state.createSelectOptionSuggestion!.name,
 | 
			
		||||
        color: state.createSelectOptionSuggestion!.color,
 | 
			
		||||
      );
 | 
			
		||||
      emit(
 | 
			
		||||
        state.copyWith(
 | 
			
		||||
          filter: null,
 | 
			
		||||
          createSelectOptionSuggestion: null,
 | 
			
		||||
          clearFilter: true,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
    } else if (!state.selectedOptions.any((option) => option.id == optionId)) {
 | 
			
		||||
      _selectOptionService.select(optionIds: [optionId]);
 | 
			
		||||
    } else if (!state.selectedOptions
 | 
			
		||||
        .any((option) => option.id == focusedOptionId)) {
 | 
			
		||||
      _selectOptionService.select(optionIds: [focusedOptionId]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _selectMultipleOptions(List<String> optionNames) {
 | 
			
		||||
    // The options are unordered. So in order to keep the inserted [optionNames]
 | 
			
		||||
    // order, it needs to get the option id in the [optionNames] order.
 | 
			
		||||
    final lowerCaseNames = optionNames.map((e) => e.toLowerCase());
 | 
			
		||||
    final Map<String, String> optionIdsMap = {};
 | 
			
		||||
    for (final option in state.options) {
 | 
			
		||||
      optionIdsMap[option.name.toLowerCase()] = option.id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final optionIds = lowerCaseNames
 | 
			
		||||
        .where((name) => optionIdsMap[name] != null)
 | 
			
		||||
        .map((name) => optionIdsMap[name]!)
 | 
			
		||||
    final optionIds = optionNames
 | 
			
		||||
        .map(
 | 
			
		||||
          (name) => allOptions.firstWhereOrNull(
 | 
			
		||||
            (option) => option.name.toLowerCase() == name.toLowerCase(),
 | 
			
		||||
          ),
 | 
			
		||||
        )
 | 
			
		||||
        .nonNulls
 | 
			
		||||
        .map((option) => option.id)
 | 
			
		||||
        .toList();
 | 
			
		||||
 | 
			
		||||
    _selectOptionService.select(optionIds: optionIds);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _filterOption(
 | 
			
		||||
    String optionName,
 | 
			
		||||
    String filterText,
 | 
			
		||||
    Emitter<SelectOptionCellEditorState> emit,
 | 
			
		||||
  ) {
 | 
			
		||||
    final _MakeOptionResult result = _makeOptions(
 | 
			
		||||
      optionName,
 | 
			
		||||
      state.allOptions,
 | 
			
		||||
    filter = filterText;
 | 
			
		||||
    final _MakeOptionResult result = _getVisibleOptions(
 | 
			
		||||
      allOptions,
 | 
			
		||||
    );
 | 
			
		||||
    final focusedOptionId = result.options.isEmpty
 | 
			
		||||
        ? result.createSelectOptionSuggestion == null
 | 
			
		||||
            ? null
 | 
			
		||||
            : createSelectOptionSuggestionId
 | 
			
		||||
        : result.options.length != state.options.length
 | 
			
		||||
            ? result.options.first.id
 | 
			
		||||
            : state.focusedOptionId;
 | 
			
		||||
        : result.options.any((option) => option.id == state.focusedOptionId)
 | 
			
		||||
            ? state.focusedOptionId
 | 
			
		||||
            : result.options.first.id;
 | 
			
		||||
    emit(
 | 
			
		||||
      state.copyWith(
 | 
			
		||||
        filter: optionName,
 | 
			
		||||
        options: result.options,
 | 
			
		||||
        createSelectOptionSuggestion: result.createSelectOptionSuggestion,
 | 
			
		||||
        focusedOptionId: focusedOptionId,
 | 
			
		||||
@ -314,39 +272,66 @@ class SelectOptionCellEditorBloc
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _MakeOptionResult _makeOptions(
 | 
			
		||||
    String? filter,
 | 
			
		||||
  _MakeOptionResult _getVisibleOptions(
 | 
			
		||||
    List<SelectOptionPB> allOptions,
 | 
			
		||||
  ) {
 | 
			
		||||
    final List<SelectOptionPB> options = List.from(allOptions);
 | 
			
		||||
    String? newOptionName = filter;
 | 
			
		||||
    String newOptionName = filter;
 | 
			
		||||
 | 
			
		||||
    if (filter != null && filter.isNotEmpty) {
 | 
			
		||||
    if (filter.isNotEmpty) {
 | 
			
		||||
      options.retainWhere((option) {
 | 
			
		||||
        final name = option.name.toLowerCase();
 | 
			
		||||
        final lFilter = filter.toLowerCase();
 | 
			
		||||
 | 
			
		||||
        if (name == lFilter) {
 | 
			
		||||
          newOptionName = null;
 | 
			
		||||
          newOptionName = "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return name.contains(lFilter);
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      newOptionName = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return _MakeOptionResult(
 | 
			
		||||
      options: options,
 | 
			
		||||
      createSelectOptionSuggestion: newOptionName != null
 | 
			
		||||
          ? CreateSelectOptionSuggestion(
 | 
			
		||||
              name: newOptionName!,
 | 
			
		||||
      createSelectOptionSuggestion: newOptionName.isEmpty
 | 
			
		||||
          ? null
 | 
			
		||||
          : CreateSelectOptionSuggestion(
 | 
			
		||||
              name: newOptionName,
 | 
			
		||||
              color: newSelectOptionColor(allOptions),
 | 
			
		||||
            )
 | 
			
		||||
          : null,
 | 
			
		||||
            ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _focusOption(bool previous, Emitter<SelectOptionCellEditorState> emit) {
 | 
			
		||||
    if (state.options.isEmpty && state.createSelectOptionSuggestion == null) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final optionIds = [
 | 
			
		||||
      ...state.options.map((e) => e.id),
 | 
			
		||||
      if (state.createSelectOptionSuggestion != null)
 | 
			
		||||
        createSelectOptionSuggestionId,
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    if (state.focusedOptionId == null) {
 | 
			
		||||
      emit(
 | 
			
		||||
        state.copyWith(
 | 
			
		||||
          focusedOptionId: previous ? optionIds.last : optionIds.first,
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final currentIndex =
 | 
			
		||||
        optionIds.indexWhere((id) => id == state.focusedOptionId);
 | 
			
		||||
 | 
			
		||||
    final newIndex = currentIndex == -1
 | 
			
		||||
        ? 0
 | 
			
		||||
        : (currentIndex + (previous ? -1 : 1)) % optionIds.length;
 | 
			
		||||
 | 
			
		||||
    emit(state.copyWith(focusedOptionId: optionIds[newIndex]));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _startListening() {
 | 
			
		||||
    _onCellChangedFn = cellController.addListener(
 | 
			
		||||
      onCellChanged: (selectOptionContext) {
 | 
			
		||||
@ -370,6 +355,8 @@ class SelectOptionCellEditorEvent with _$SelectOptionCellEditorEvent {
 | 
			
		||||
      _SelectOption;
 | 
			
		||||
  const factory SelectOptionCellEditorEvent.unSelectOption(String optionId) =
 | 
			
		||||
      _UnSelectOption;
 | 
			
		||||
  const factory SelectOptionCellEditorEvent.unSelectLastOption() =
 | 
			
		||||
      _UnSelectLastOption;
 | 
			
		||||
  const factory SelectOptionCellEditorEvent.updateOption(
 | 
			
		||||
    SelectOptionPB option,
 | 
			
		||||
  ) = _UpdateOption;
 | 
			
		||||
@ -382,7 +369,7 @@ class SelectOptionCellEditorEvent with _$SelectOptionCellEditorEvent {
 | 
			
		||||
    String fromOptionId,
 | 
			
		||||
    String toOptionId,
 | 
			
		||||
  ) = _ReorderOption;
 | 
			
		||||
  const factory SelectOptionCellEditorEvent.filterOption(String optionName) =
 | 
			
		||||
  const factory SelectOptionCellEditorEvent.filterOption(String filterText) =
 | 
			
		||||
      _SelectOptionFilter;
 | 
			
		||||
  const factory SelectOptionCellEditorEvent.submitTextField() =
 | 
			
		||||
      _SubmitTextField;
 | 
			
		||||
@ -397,17 +384,18 @@ class SelectOptionCellEditorEvent with _$SelectOptionCellEditorEvent {
 | 
			
		||||
  const factory SelectOptionCellEditorEvent.updateFocusedOption(
 | 
			
		||||
    String? optionId,
 | 
			
		||||
  ) = _UpdateFocusedOption;
 | 
			
		||||
  const factory SelectOptionCellEditorEvent.resetClearFilterFlag() =
 | 
			
		||||
      _ResetClearFilterFlag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@freezed
 | 
			
		||||
class SelectOptionCellEditorState with _$SelectOptionCellEditorState {
 | 
			
		||||
  const factory SelectOptionCellEditorState({
 | 
			
		||||
    required List<SelectOptionPB> options,
 | 
			
		||||
    required List<SelectOptionPB> allOptions,
 | 
			
		||||
    required List<SelectOptionPB> selectedOptions,
 | 
			
		||||
    required CreateSelectOptionSuggestion? createSelectOptionSuggestion,
 | 
			
		||||
    required String? filter,
 | 
			
		||||
    required String? focusedOptionId,
 | 
			
		||||
    required bool clearFilter,
 | 
			
		||||
  }) = _SelectOptionEditorState;
 | 
			
		||||
 | 
			
		||||
  factory SelectOptionCellEditorState.initial(
 | 
			
		||||
@ -416,11 +404,10 @@ class SelectOptionCellEditorState with _$SelectOptionCellEditorState {
 | 
			
		||||
    final data = context.getCellData(loadIfNotExist: false);
 | 
			
		||||
    return SelectOptionCellEditorState(
 | 
			
		||||
      options: data?.options ?? [],
 | 
			
		||||
      allOptions: data?.options ?? [],
 | 
			
		||||
      selectedOptions: data?.selectOptions ?? [],
 | 
			
		||||
      createSelectOptionSuggestion: null,
 | 
			
		||||
      filter: null,
 | 
			
		||||
      focusedOptionId: null,
 | 
			
		||||
      clearFilter: false,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,7 @@ class SelectOptionFilterListBloc<T>
 | 
			
		||||
              emit: emit,
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
          unselectOption: (option) {
 | 
			
		||||
          unSelectOption: (option) {
 | 
			
		||||
            final selectedOptionIds = Set<String>.from(state.selectedOptionIds);
 | 
			
		||||
            selectedOptionIds.remove(option.id);
 | 
			
		||||
 | 
			
		||||
@ -121,7 +121,7 @@ class SelectOptionFilterListEvent with _$SelectOptionFilterListEvent {
 | 
			
		||||
    SelectOptionPB option,
 | 
			
		||||
    SelectOptionFilterConditionPB condition,
 | 
			
		||||
  ) = _SelectOption;
 | 
			
		||||
  const factory SelectOptionFilterListEvent.unselectOption(
 | 
			
		||||
  const factory SelectOptionFilterListEvent.unSelectOption(
 | 
			
		||||
    SelectOptionPB option,
 | 
			
		||||
  ) = _UnSelectOption;
 | 
			
		||||
  const factory SelectOptionFilterListEvent.didReceiveOptions(
 | 
			
		||||
 | 
			
		||||
@ -89,7 +89,7 @@ class _SelectOptionFilterCellState extends State<SelectOptionFilterCell> {
 | 
			
		||||
          if (widget.isSelected) {
 | 
			
		||||
            context
 | 
			
		||||
                .read<SelectOptionFilterListBloc>()
 | 
			
		||||
                .add(SelectOptionFilterListEvent.unselectOption(widget.option));
 | 
			
		||||
                .add(SelectOptionFilterListEvent.unSelectOption(widget.option));
 | 
			
		||||
          } else {
 | 
			
		||||
            context.read<SelectOptionFilterListBloc>().add(
 | 
			
		||||
                  SelectOptionFilterListEvent.selectOption(
 | 
			
		||||
 | 
			
		||||
@ -45,21 +45,20 @@ class _SelectOptionCellEditorState extends State<SelectOptionCellEditor> {
 | 
			
		||||
    super.initState();
 | 
			
		||||
    focusNode = FocusNode(
 | 
			
		||||
      onKeyEvent: (node, event) {
 | 
			
		||||
        if (event is KeyUpEvent) {
 | 
			
		||||
          return KeyEventResult.ignored;
 | 
			
		||||
        }
 | 
			
		||||
        switch (event.logicalKey) {
 | 
			
		||||
          case LogicalKeyboardKey.arrowUp:
 | 
			
		||||
          case LogicalKeyboardKey.arrowUp when event is! KeyUpEvent:
 | 
			
		||||
            if (textEditingController.value.composing.isCollapsed) {
 | 
			
		||||
              bloc.add(const SelectOptionCellEditorEvent.focusPreviousOption());
 | 
			
		||||
              return KeyEventResult.handled;
 | 
			
		||||
            }
 | 
			
		||||
          case LogicalKeyboardKey.arrowDown:
 | 
			
		||||
            break;
 | 
			
		||||
          case LogicalKeyboardKey.arrowDown when event is! KeyUpEvent:
 | 
			
		||||
            if (textEditingController.value.composing.isCollapsed) {
 | 
			
		||||
              bloc.add(const SelectOptionCellEditorEvent.focusNextOption());
 | 
			
		||||
              return KeyEventResult.handled;
 | 
			
		||||
            }
 | 
			
		||||
          case LogicalKeyboardKey.escape:
 | 
			
		||||
            break;
 | 
			
		||||
          case LogicalKeyboardKey.escape when event is! KeyUpEvent:
 | 
			
		||||
            if (!textEditingController.value.composing.isCollapsed) {
 | 
			
		||||
              final end = textEditingController.value.composing.end;
 | 
			
		||||
              final text = textEditingController.text;
 | 
			
		||||
@ -70,6 +69,13 @@ class _SelectOptionCellEditorState extends State<SelectOptionCellEditor> {
 | 
			
		||||
              );
 | 
			
		||||
              return KeyEventResult.handled;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
          case LogicalKeyboardKey.backspace when event is KeyUpEvent:
 | 
			
		||||
            if (!textEditingController.text.isNotEmpty) {
 | 
			
		||||
              bloc.add(const SelectOptionCellEditorEvent.unSelectLastOption());
 | 
			
		||||
              return KeyEventResult.handled;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        return KeyEventResult.ignored;
 | 
			
		||||
      },
 | 
			
		||||
@ -126,7 +132,18 @@ class _OptionList extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return BlocBuilder<SelectOptionCellEditorBloc, SelectOptionCellEditorState>(
 | 
			
		||||
    return BlocConsumer<SelectOptionCellEditorBloc,
 | 
			
		||||
        SelectOptionCellEditorState>(
 | 
			
		||||
      listenWhen: (previous, current) =>
 | 
			
		||||
          previous.clearFilter != current.clearFilter,
 | 
			
		||||
      listener: (context, state) {
 | 
			
		||||
        if (state.clearFilter) {
 | 
			
		||||
          textEditingController.clear();
 | 
			
		||||
          context
 | 
			
		||||
              .read<SelectOptionCellEditorBloc>()
 | 
			
		||||
              .add(const SelectOptionCellEditorEvent.resetClearFilterFlag());
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      buildWhen: (previous, current) =>
 | 
			
		||||
          !listEquals(previous.options, current.options) ||
 | 
			
		||||
          previous.createSelectOptionSuggestion !=
 | 
			
		||||
@ -231,7 +248,6 @@ class _TextField extends StatelessWidget {
 | 
			
		||||
                context
 | 
			
		||||
                    .read<SelectOptionCellEditorBloc>()
 | 
			
		||||
                    .add(const SelectOptionCellEditorEvent.submitTextField());
 | 
			
		||||
                textEditingController.clear();
 | 
			
		||||
                focusNode.requestFocus();
 | 
			
		||||
              },
 | 
			
		||||
              onPaste: (tagNames, remainder) {
 | 
			
		||||
 | 
			
		||||
@ -184,7 +184,7 @@ void main() {
 | 
			
		||||
 | 
			
		||||
      assert(bloc.state.selectedOptions.length == 1);
 | 
			
		||||
      expect(bloc.state.selectedOptions[0].name, "A");
 | 
			
		||||
      expect(bloc.state.filter, "x");
 | 
			
		||||
      expect(bloc.filter, "x");
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    test('filter options', () async {
 | 
			
		||||
@ -234,12 +234,12 @@ void main() {
 | 
			
		||||
        reason: "Options: ${bloc.state.options}",
 | 
			
		||||
      );
 | 
			
		||||
      expect(
 | 
			
		||||
        bloc.state.allOptions.length,
 | 
			
		||||
        bloc.allOptions.length,
 | 
			
		||||
        3,
 | 
			
		||||
        reason: "Options: ${bloc.state.options}",
 | 
			
		||||
      );
 | 
			
		||||
      expect(bloc.state.createSelectOptionSuggestion!.name, "a");
 | 
			
		||||
      expect(bloc.state.filter, "a");
 | 
			
		||||
      expect(bloc.filter, "a");
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user