mirror of
				https://github.com/AppFlowy-IO/AppFlowy.git
				synced 2025-10-31 10:03:18 +00:00 
			
		
		
		
	feat: support multi-select option filter (#1501)
Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
		
							parent
							
								
									bc70b04110
								
							
						
					
					
						commit
						80d1cbabe0
					
				| @ -529,7 +529,7 @@ class FieldInfo { | |||||||
| 
 | 
 | ||||||
|     switch (_field.fieldType) { |     switch (_field.fieldType) { | ||||||
|       case FieldType.Checkbox: |       case FieldType.Checkbox: | ||||||
|       // case FieldType.MultiSelect: |       case FieldType.MultiSelect: | ||||||
|       case FieldType.RichText: |       case FieldType.RichText: | ||||||
|       case FieldType.SingleSelect: |       case FieldType.SingleSelect: | ||||||
|         return true; |         return true; | ||||||
|  | |||||||
| @ -109,15 +109,16 @@ class TypeOptionContext<T extends GeneratedMessage> { | |||||||
| 
 | 
 | ||||||
|   String get fieldId => _dataController.field.id; |   String get fieldId => _dataController.field.id; | ||||||
| 
 | 
 | ||||||
|   Future<void> loadTypeOptionData({ |   Future<T> loadTypeOptionData({ | ||||||
|     required void Function(T) onCompleted, |     void Function(T)? onCompleted, | ||||||
|     required void Function(FlowyError) onError, |     required void Function(FlowyError) onError, | ||||||
|   }) async { |   }) async { | ||||||
|     await _dataController.loadTypeOptionData().then((result) { |     await _dataController.loadTypeOptionData().then((result) { | ||||||
|       result.fold((l) => null, (err) => onError(err)); |       result.fold((l) => null, (err) => onError(err)); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     onCompleted(typeOption); |     onCompleted?.call(typeOption); | ||||||
|  |     return typeOption; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   T get typeOption { |   T get typeOption { | ||||||
|  | |||||||
| @ -33,14 +33,14 @@ class TypeOptionDataController { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<Either<Unit, FlowyError>> loadTypeOptionData() async { |   Future<Either<TypeOptionPB, FlowyError>> loadTypeOptionData() async { | ||||||
|     final result = await loader.load(); |     final result = await loader.load(); | ||||||
|     return result.fold( |     return result.fold( | ||||||
|       (data) { |       (data) { | ||||||
|         data.freeze(); |         data.freeze(); | ||||||
|         _data = data; |         _data = data; | ||||||
|         _fieldNotifier.value = data.field_2; |         _fieldNotifier.value = data.field_2; | ||||||
|         return left(unit); |         return left(data); | ||||||
|       }, |       }, | ||||||
|       (err) { |       (err) { | ||||||
|         Log.error(err); |         Log.error(err); | ||||||
|  | |||||||
| @ -31,15 +31,15 @@ class CheckboxFilterEditorBloc | |||||||
|           updateCondition: (CheckboxFilterCondition condition) { |           updateCondition: (CheckboxFilterCondition condition) { | ||||||
|             _ffiService.insertCheckboxFilter( |             _ffiService.insertCheckboxFilter( | ||||||
|               filterId: filterInfo.filter.id, |               filterId: filterInfo.filter.id, | ||||||
|               fieldId: filterInfo.field.id, |               fieldId: filterInfo.fieldInfo.id, | ||||||
|               condition: condition, |               condition: condition, | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|           delete: () { |           delete: () { | ||||||
|             _ffiService.deleteFilter( |             _ffiService.deleteFilter( | ||||||
|               fieldId: filterInfo.field.id, |               fieldId: filterInfo.fieldInfo.id, | ||||||
|               filterId: filterInfo.filter.id, |               filterId: filterInfo.filter.id, | ||||||
|               fieldType: filterInfo.field.fieldType, |               fieldType: filterInfo.fieldInfo.fieldType, | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|           didReceiveFilter: (FilterPB filter) { |           didReceiveFilter: (FilterPB filter) { | ||||||
|  | |||||||
| @ -1,7 +1,5 @@ | |||||||
| import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart'; | import 'package:app_flowy/plugins/grid/presentation/widgets/filter/choicechip/select_option/select_option_loader.dart'; | ||||||
| import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.dart'; | import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.dart'; | ||||||
| import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/builder.dart'; |  | ||||||
| import 'package:flowy_sdk/log.dart'; |  | ||||||
| import 'package:flowy_sdk/protobuf/flowy-grid/select_option_filter.pbserver.dart'; | import 'package:flowy_sdk/protobuf/flowy-grid/select_option_filter.pbserver.dart'; | ||||||
| import 'package:flowy_sdk/protobuf/flowy-grid/util.pb.dart'; | import 'package:flowy_sdk/protobuf/flowy-grid/util.pb.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| @ -17,18 +15,16 @@ class SelectOptionFilterEditorBloc | |||||||
|   final FilterInfo filterInfo; |   final FilterInfo filterInfo; | ||||||
|   final FilterFFIService _ffiService; |   final FilterFFIService _ffiService; | ||||||
|   final FilterListener _listener; |   final FilterListener _listener; | ||||||
|   final SingleSelectTypeOptionContext typeOptionContext; |   final SelectOptionFilterDelegate delegate; | ||||||
| 
 | 
 | ||||||
|   SelectOptionFilterEditorBloc({required this.filterInfo}) |   SelectOptionFilterEditorBloc({ | ||||||
|       : _ffiService = FilterFFIService(viewId: filterInfo.viewId), |     required this.filterInfo, | ||||||
|  |     required this.delegate, | ||||||
|  |   })  : _ffiService = FilterFFIService(viewId: filterInfo.viewId), | ||||||
|         _listener = FilterListener( |         _listener = FilterListener( | ||||||
|           viewId: filterInfo.viewId, |           viewId: filterInfo.viewId, | ||||||
|           filterId: filterInfo.filter.id, |           filterId: filterInfo.filter.id, | ||||||
|         ), |         ), | ||||||
|         typeOptionContext = makeSingleSelectTypeOptionContext( |  | ||||||
|           gridId: filterInfo.viewId, |  | ||||||
|           fieldPB: filterInfo.field.field, |  | ||||||
|         ), |  | ||||||
|         super(SelectOptionFilterEditorState.initial(filterInfo)) { |         super(SelectOptionFilterEditorState.initial(filterInfo)) { | ||||||
|     on<SelectOptionFilterEditorEvent>( |     on<SelectOptionFilterEditorEvent>( | ||||||
|       (event, emit) async { |       (event, emit) async { | ||||||
| @ -40,26 +36,26 @@ class SelectOptionFilterEditorBloc | |||||||
|           updateCondition: (SelectOptionCondition condition) { |           updateCondition: (SelectOptionCondition condition) { | ||||||
|             _ffiService.insertSelectOptionFilter( |             _ffiService.insertSelectOptionFilter( | ||||||
|               filterId: filterInfo.filter.id, |               filterId: filterInfo.filter.id, | ||||||
|               fieldId: filterInfo.field.id, |               fieldId: filterInfo.fieldInfo.id, | ||||||
|               condition: condition, |               condition: condition, | ||||||
|               optionIds: state.filter.optionIds, |               optionIds: state.filter.optionIds, | ||||||
|               fieldType: state.filterInfo.field.fieldType, |               fieldType: state.filterInfo.fieldInfo.fieldType, | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|           updateContent: (List<String> optionIds) { |           updateContent: (List<String> optionIds) { | ||||||
|             _ffiService.insertSelectOptionFilter( |             _ffiService.insertSelectOptionFilter( | ||||||
|               filterId: filterInfo.filter.id, |               filterId: filterInfo.filter.id, | ||||||
|               fieldId: filterInfo.field.id, |               fieldId: filterInfo.fieldInfo.id, | ||||||
|               condition: state.filter.condition, |               condition: state.filter.condition, | ||||||
|               optionIds: optionIds, |               optionIds: optionIds, | ||||||
|               fieldType: state.filterInfo.field.fieldType, |               fieldType: state.filterInfo.fieldInfo.fieldType, | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|           delete: () { |           delete: () { | ||||||
|             _ffiService.deleteFilter( |             _ffiService.deleteFilter( | ||||||
|               fieldId: filterInfo.field.id, |               fieldId: filterInfo.fieldInfo.id, | ||||||
|               filterId: filterInfo.filter.id, |               filterId: filterInfo.filter.id, | ||||||
|               fieldType: filterInfo.field.fieldType, |               fieldType: filterInfo.fieldInfo.fieldType, | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|           didReceiveFilter: (FilterPB filter) { |           didReceiveFilter: (FilterPB filter) { | ||||||
| @ -92,21 +88,17 @@ class SelectOptionFilterEditorBloc | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void _loadOptions() { |   void _loadOptions() { | ||||||
|     typeOptionContext.loadTypeOptionData( |     delegate.loadOptions().then((options) { | ||||||
|       onCompleted: (value) { |  | ||||||
|       if (!isClosed) { |       if (!isClosed) { | ||||||
|         String filterDesc = ''; |         String filterDesc = ''; | ||||||
|           for (final option in value.options) { |         for (final option in options) { | ||||||
|           if (state.filter.optionIds.contains(option.id)) { |           if (state.filter.optionIds.contains(option.id)) { | ||||||
|             filterDesc += "${option.name} "; |             filterDesc += "${option.name} "; | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
|           add(SelectOptionFilterEditorEvent.updateFilterDescription( |         add(SelectOptionFilterEditorEvent.updateFilterDescription(filterDesc)); | ||||||
|               filterDesc)); |  | ||||||
|       } |       } | ||||||
|       }, |     }); | ||||||
|       onError: (error) => Log.error(error), |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|  | |||||||
| @ -1,8 +1,6 @@ | |||||||
| import 'dart:async'; | import 'dart:async'; | ||||||
| 
 | 
 | ||||||
| import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart'; | import 'package:app_flowy/plugins/grid/presentation/widgets/filter/choicechip/select_option/select_option_loader.dart'; | ||||||
| import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/builder.dart'; |  | ||||||
| import 'package:flowy_sdk/log.dart'; |  | ||||||
| import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; | import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; | ||||||
| import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart'; | import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart'; | ||||||
| import 'package:flutter_bloc/flutter_bloc.dart'; | import 'package:flutter_bloc/flutter_bloc.dart'; | ||||||
| @ -12,16 +10,13 @@ part 'select_option_filter_list_bloc.freezed.dart'; | |||||||
| 
 | 
 | ||||||
| class SelectOptionFilterListBloc<T> | class SelectOptionFilterListBloc<T> | ||||||
|     extends Bloc<SelectOptionFilterListEvent, SelectOptionFilterListState> { |     extends Bloc<SelectOptionFilterListEvent, SelectOptionFilterListState> { | ||||||
|   final SingleSelectTypeOptionContext typeOptionContext; |   final SelectOptionFilterDelegate delegate; | ||||||
|   SelectOptionFilterListBloc({ |   SelectOptionFilterListBloc({ | ||||||
|     required String viewId, |     required String viewId, | ||||||
|     required FieldPB fieldPB, |     required FieldPB fieldPB, | ||||||
|  |     required this.delegate, | ||||||
|     required List<String> selectedOptionIds, |     required List<String> selectedOptionIds, | ||||||
|   })  : typeOptionContext = makeSingleSelectTypeOptionContext( |   }) : super(SelectOptionFilterListState.initial(selectedOptionIds)) { | ||||||
|           gridId: viewId, |  | ||||||
|           fieldPB: fieldPB, |  | ||||||
|         ), |  | ||||||
|         super(SelectOptionFilterListState.initial(selectedOptionIds)) { |  | ||||||
|     on<SelectOptionFilterListEvent>( |     on<SelectOptionFilterListEvent>( | ||||||
|       (event, emit) async { |       (event, emit) async { | ||||||
|         await event.when( |         await event.when( | ||||||
| @ -103,14 +98,11 @@ class SelectOptionFilterListBloc<T> | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void _loadOptions() { |   void _loadOptions() { | ||||||
|     typeOptionContext.loadTypeOptionData( |     delegate.loadOptions().then((options) { | ||||||
|       onCompleted: (value) { |  | ||||||
|       if (!isClosed) { |       if (!isClosed) { | ||||||
|           add(SelectOptionFilterListEvent.didReceiveOptions(value.options)); |         add(SelectOptionFilterListEvent.didReceiveOptions(options)); | ||||||
|       } |       } | ||||||
|       }, |     }); | ||||||
|       onError: (error) => Log.error(error), |  | ||||||
|     ); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void _startListening() {} |   void _startListening() {} | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ class TextFilterEditorBloc | |||||||
|           updateCondition: (TextFilterCondition condition) { |           updateCondition: (TextFilterCondition condition) { | ||||||
|             _ffiService.insertTextFilter( |             _ffiService.insertTextFilter( | ||||||
|               filterId: filterInfo.filter.id, |               filterId: filterInfo.filter.id, | ||||||
|               fieldId: filterInfo.field.id, |               fieldId: filterInfo.fieldInfo.id, | ||||||
|               condition: condition, |               condition: condition, | ||||||
|               content: state.filter.content, |               content: state.filter.content, | ||||||
|             ); |             ); | ||||||
| @ -39,16 +39,16 @@ class TextFilterEditorBloc | |||||||
|           updateContent: (content) { |           updateContent: (content) { | ||||||
|             _ffiService.insertTextFilter( |             _ffiService.insertTextFilter( | ||||||
|               filterId: filterInfo.filter.id, |               filterId: filterInfo.filter.id, | ||||||
|               fieldId: filterInfo.field.id, |               fieldId: filterInfo.fieldInfo.id, | ||||||
|               condition: state.filter.condition, |               condition: state.filter.condition, | ||||||
|               content: content, |               content: content, | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|           delete: () { |           delete: () { | ||||||
|             _ffiService.deleteFilter( |             _ffiService.deleteFilter( | ||||||
|               fieldId: filterInfo.field.id, |               fieldId: filterInfo.fieldInfo.id, | ||||||
|               filterId: filterInfo.filter.id, |               filterId: filterInfo.filter.id, | ||||||
|               fieldType: filterInfo.field.fieldType, |               fieldType: filterInfo.fieldInfo.fieldType, | ||||||
|             ); |             ); | ||||||
|           }, |           }, | ||||||
|           didReceiveFilter: (FilterPB filter) { |           didReceiveFilter: (FilterPB filter) { | ||||||
|  | |||||||
| @ -107,7 +107,7 @@ class _CheckboxFilterEditorState extends State<CheckboxFilterEditor> { | |||||||
|       height: 20, |       height: 20, | ||||||
|       child: Row( |       child: Row( | ||||||
|         children: [ |         children: [ | ||||||
|           FlowyText(state.filterInfo.field.name), |           FlowyText(state.filterInfo.fieldInfo.name), | ||||||
|           const HSpace(4), |           const HSpace(4), | ||||||
|           CheckboxFilterConditionList( |           CheckboxFilterConditionList( | ||||||
|             filterInfo: state.filterInfo, |             filterInfo: state.filterInfo, | ||||||
|  | |||||||
| @ -37,11 +37,11 @@ class ChoiceChipButton extends StatelessWidget { | |||||||
|       child: FlowyButton( |       child: FlowyButton( | ||||||
|         decoration: decoration, |         decoration: decoration, | ||||||
|         useIntrinsicWidth: true, |         useIntrinsicWidth: true, | ||||||
|         text: FlowyText(filterInfo.field.name, fontSize: 12), |         text: FlowyText(filterInfo.fieldInfo.name, fontSize: 12), | ||||||
|         margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), |         margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), | ||||||
|         radius: const BorderRadius.all(Radius.circular(14)), |         radius: const BorderRadius.all(Radius.circular(14)), | ||||||
|         leftIcon: svgWidget( |         leftIcon: svgWidget( | ||||||
|           filterInfo.field.fieldType.iconName(), |           filterInfo.fieldInfo.fieldType.iconName(), | ||||||
|           color: Theme.of(context).colorScheme.onSurface, |           color: Theme.of(context).colorScheme.onSurface, | ||||||
|         ), |         ), | ||||||
|         rightIcon: _ChoicechipFilterDesc(filterDesc: filterDesc), |         rightIcon: _ChoicechipFilterDesc(filterDesc: filterDesc), | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ class SelectOptionFilterConditionList extends StatelessWidget { | |||||||
|             (action) => ConditionWrapper( |             (action) => ConditionWrapper( | ||||||
|               action, |               action, | ||||||
|               selectOptionFilter.condition == action, |               selectOptionFilter.condition == action, | ||||||
|               filterInfo.field.fieldType, |               filterInfo.fieldInfo.fieldType, | ||||||
|             ), |             ), | ||||||
|           ) |           ) | ||||||
|           .toList(), |           .toList(), | ||||||
| @ -50,7 +50,7 @@ class SelectOptionFilterConditionList extends StatelessWidget { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   String filterName(SelectOptionFilterPB filter) { |   String filterName(SelectOptionFilterPB filter) { | ||||||
|     if (filterInfo.field.fieldType == FieldType.SingleSelect) { |     if (filterInfo.fieldInfo.fieldType == FieldType.SingleSelect) { | ||||||
|       return filter.condition.singleSelectFilterName; |       return filter.condition.singleSelectFilterName; | ||||||
|     } else { |     } else { | ||||||
|       return filter.condition.multiSelectFilterName; |       return filter.condition.multiSelectFilterName; | ||||||
|  | |||||||
| @ -1,22 +1,23 @@ | |||||||
| import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; |  | ||||||
| import 'package:app_flowy/plugins/grid/application/filter/select_option_filter_list_bloc.dart'; | import 'package:app_flowy/plugins/grid/application/filter/select_option_filter_list_bloc.dart'; | ||||||
| import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart'; | import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart'; | ||||||
| import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/extension.dart'; | import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/extension.dart'; | ||||||
|  | import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.dart'; | ||||||
| import 'package:flowy_infra/image.dart'; | import 'package:flowy_infra/image.dart'; | ||||||
| import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; | import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; | ||||||
| import 'package:flowy_infra_ui/widget/spacing.dart'; | import 'package:flowy_infra_ui/widget/spacing.dart'; | ||||||
|  | import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pbenum.dart'; | ||||||
| import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart'; | import 'package:flowy_sdk/protobuf/flowy-grid/select_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 'select_option_loader.dart'; | ||||||
|  | 
 | ||||||
| class SelectOptionFilterList extends StatelessWidget { | class SelectOptionFilterList extends StatelessWidget { | ||||||
|   final String viewId; |   final FilterInfo filterInfo; | ||||||
|   final FieldInfo fieldInfo; |  | ||||||
|   final List<String> selectedOptionIds; |   final List<String> selectedOptionIds; | ||||||
|   final Function(List<String>) onSelectedOptions; |   final Function(List<String>) onSelectedOptions; | ||||||
|   const SelectOptionFilterList({ |   const SelectOptionFilterList({ | ||||||
|     required this.viewId, |     required this.filterInfo, | ||||||
|     required this.fieldInfo, |  | ||||||
|     required this.selectedOptionIds, |     required this.selectedOptionIds, | ||||||
|     required this.onSelectedOptions, |     required this.onSelectedOptions, | ||||||
|     Key? key, |     Key? key, | ||||||
| @ -25,11 +26,27 @@ class SelectOptionFilterList extends StatelessWidget { | |||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return BlocProvider( |     return BlocProvider( | ||||||
|       create: (context) => SelectOptionFilterListBloc( |       create: (context) { | ||||||
|         viewId: viewId, |         late SelectOptionFilterListBloc bloc; | ||||||
|         fieldPB: fieldInfo.field, |         if (filterInfo.fieldInfo.fieldType == FieldType.SingleSelect) { | ||||||
|  |           bloc = SelectOptionFilterListBloc( | ||||||
|  |             viewId: filterInfo.viewId, | ||||||
|  |             fieldPB: filterInfo.fieldInfo.field, | ||||||
|             selectedOptionIds: selectedOptionIds, |             selectedOptionIds: selectedOptionIds, | ||||||
|       )..add(const SelectOptionFilterListEvent.initial()), |             delegate: SingleSelectOptionFilterDelegateImpl(filterInfo), | ||||||
|  |           ); | ||||||
|  |         } else { | ||||||
|  |           bloc = SelectOptionFilterListBloc( | ||||||
|  |             viewId: filterInfo.viewId, | ||||||
|  |             fieldPB: filterInfo.fieldInfo.field, | ||||||
|  |             selectedOptionIds: selectedOptionIds, | ||||||
|  |             delegate: MultiSelectOptionFilterDelegateImpl(filterInfo), | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         bloc.add(const SelectOptionFilterListEvent.initial()); | ||||||
|  |         return bloc; | ||||||
|  |       }, | ||||||
|       child: |       child: | ||||||
|           BlocListener<SelectOptionFilterListBloc, SelectOptionFilterListState>( |           BlocListener<SelectOptionFilterListBloc, SelectOptionFilterListState>( | ||||||
|         listenWhen: (previous, current) => |         listenWhen: (previous, current) => | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart'; | |||||||
| import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; | import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; | ||||||
| import 'package:flowy_infra_ui/style_widget/text.dart'; | import 'package:flowy_infra_ui/style_widget/text.dart'; | ||||||
| import 'package:flowy_infra_ui/widget/spacing.dart'; | import 'package:flowy_infra_ui/widget/spacing.dart'; | ||||||
|  | import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; | ||||||
| import 'package:flowy_sdk/protobuf/flowy-grid/select_option_filter.pb.dart'; | import 'package:flowy_sdk/protobuf/flowy-grid/select_option_filter.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'; | ||||||
| @ -13,6 +14,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; | |||||||
| import '../choicechip.dart'; | import '../choicechip.dart'; | ||||||
| import 'condition_list.dart'; | import 'condition_list.dart'; | ||||||
| import 'option_list.dart'; | import 'option_list.dart'; | ||||||
|  | import 'select_option_loader.dart'; | ||||||
| 
 | 
 | ||||||
| class SelectOptionFilterChoicechip extends StatefulWidget { | class SelectOptionFilterChoicechip extends StatefulWidget { | ||||||
|   final FilterInfo filterInfo; |   final FilterInfo filterInfo; | ||||||
| @ -30,8 +32,18 @@ class _SelectOptionFilterChoicechipState | |||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   void initState() { |   void initState() { | ||||||
|     bloc = SelectOptionFilterEditorBloc(filterInfo: widget.filterInfo) |     if (widget.filterInfo.fieldInfo.fieldType == FieldType.SingleSelect) { | ||||||
|       ..add(const SelectOptionFilterEditorEvent.initial()); |       bloc = SelectOptionFilterEditorBloc( | ||||||
|  |         filterInfo: widget.filterInfo, | ||||||
|  |         delegate: SingleSelectOptionFilterDelegateImpl(widget.filterInfo), | ||||||
|  |       ); | ||||||
|  |     } else { | ||||||
|  |       bloc = SelectOptionFilterEditorBloc( | ||||||
|  |         filterInfo: widget.filterInfo, | ||||||
|  |         delegate: MultiSelectOptionFilterDelegateImpl(widget.filterInfo), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     bloc.add(const SelectOptionFilterEditorEvent.initial()); | ||||||
|     super.initState(); |     super.initState(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -97,8 +109,7 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> { | |||||||
|             slivers.add( |             slivers.add( | ||||||
|               SliverToBoxAdapter( |               SliverToBoxAdapter( | ||||||
|                 child: SelectOptionFilterList( |                 child: SelectOptionFilterList( | ||||||
|                   viewId: state.filterInfo.viewId, |                   filterInfo: state.filterInfo, | ||||||
|                   fieldInfo: state.filterInfo.field, |  | ||||||
|                   selectedOptionIds: state.filter.optionIds, |                   selectedOptionIds: state.filter.optionIds, | ||||||
|                   onSelectedOptions: (optionIds) { |                   onSelectedOptions: (optionIds) { | ||||||
|                     context.read<SelectOptionFilterEditorBloc>().add( |                     context.read<SelectOptionFilterEditorBloc>().add( | ||||||
| @ -129,7 +140,7 @@ class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> { | |||||||
|       height: 20, |       height: 20, | ||||||
|       child: Row( |       child: Row( | ||||||
|         children: [ |         children: [ | ||||||
|           FlowyText(state.filterInfo.field.name), |           FlowyText(state.filterInfo.fieldInfo.name), | ||||||
|           const HSpace(4), |           const HSpace(4), | ||||||
|           SelectOptionFilterConditionList( |           SelectOptionFilterConditionList( | ||||||
|             filterInfo: state.filterInfo, |             filterInfo: state.filterInfo, | ||||||
|  | |||||||
| @ -0,0 +1,49 @@ | |||||||
|  | import 'package:app_flowy/plugins/grid/application/field/type_option/type_option_context.dart'; | ||||||
|  | import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.dart'; | ||||||
|  | import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/builder.dart'; | ||||||
|  | import 'package:flowy_sdk/log.dart'; | ||||||
|  | import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart'; | ||||||
|  | 
 | ||||||
|  | abstract class SelectOptionFilterDelegate { | ||||||
|  |   Future<List<SelectOptionPB>> loadOptions(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class SingleSelectOptionFilterDelegateImpl | ||||||
|  |     implements SelectOptionFilterDelegate { | ||||||
|  |   final SingleSelectTypeOptionContext typeOptionContext; | ||||||
|  | 
 | ||||||
|  |   SingleSelectOptionFilterDelegateImpl(FilterInfo filterInfo) | ||||||
|  |       : typeOptionContext = makeSingleSelectTypeOptionContext( | ||||||
|  |           gridId: filterInfo.viewId, | ||||||
|  |           fieldPB: filterInfo.fieldInfo.field, | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<List<SelectOptionPB>> loadOptions() { | ||||||
|  |     return typeOptionContext | ||||||
|  |         .loadTypeOptionData( | ||||||
|  |           onError: (error) => Log.error(error), | ||||||
|  |         ) | ||||||
|  |         .then((value) => value.options); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class MultiSelectOptionFilterDelegateImpl | ||||||
|  |     implements SelectOptionFilterDelegate { | ||||||
|  |   final MultiSelectTypeOptionContext typeOptionContext; | ||||||
|  | 
 | ||||||
|  |   MultiSelectOptionFilterDelegateImpl(FilterInfo filterInfo) | ||||||
|  |       : typeOptionContext = makeMultiSelectTypeOptionContext( | ||||||
|  |           gridId: filterInfo.viewId, | ||||||
|  |           fieldPB: filterInfo.fieldInfo.field, | ||||||
|  |         ); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Future<List<SelectOptionPB>> loadOptions() { | ||||||
|  |     return typeOptionContext | ||||||
|  |         .loadTypeOptionData( | ||||||
|  |           onError: (error) => Log.error(error), | ||||||
|  |         ) | ||||||
|  |         .then((value) => value.options); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -120,7 +120,7 @@ class _TextFilterEditorState extends State<TextFilterEditor> { | |||||||
|       height: 20, |       height: 20, | ||||||
|       child: Row( |       child: Row( | ||||||
|         children: [ |         children: [ | ||||||
|           FlowyText(state.filterInfo.field.name), |           FlowyText(state.filterInfo.fieldInfo.name), | ||||||
|           const HSpace(4), |           const HSpace(4), | ||||||
|           TextFilterConditionList( |           TextFilterConditionList( | ||||||
|             filterInfo: state.filterInfo, |             filterInfo: state.filterInfo, | ||||||
|  | |||||||
| @ -9,15 +9,15 @@ import 'package:flowy_sdk/protobuf/flowy-grid/util.pb.dart'; | |||||||
| class FilterInfo { | class FilterInfo { | ||||||
|   final String viewId; |   final String viewId; | ||||||
|   final FilterPB filter; |   final FilterPB filter; | ||||||
|   final FieldInfo field; |   final FieldInfo fieldInfo; | ||||||
| 
 | 
 | ||||||
|   FilterInfo(this.viewId, this.filter, this.field); |   FilterInfo(this.viewId, this.filter, this.fieldInfo); | ||||||
| 
 | 
 | ||||||
|   FilterInfo copyWith({FilterPB? filter, FieldInfo? field}) { |   FilterInfo copyWith({FilterPB? filter, FieldInfo? fieldInfo}) { | ||||||
|     return FilterInfo( |     return FilterInfo( | ||||||
|       viewId, |       viewId, | ||||||
|       filter ?? this.filter, |       filter ?? this.filter, | ||||||
|       field ?? this.field, |       fieldInfo ?? this.fieldInfo, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ class FilterMenuItem extends StatelessWidget { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Widget buildFilterChoicechip(FilterInfo filterInfo) { | Widget buildFilterChoicechip(FilterInfo filterInfo) { | ||||||
|   switch (filterInfo.field.fieldType) { |   switch (filterInfo.fieldInfo.fieldType) { | ||||||
|     case FieldType.Checkbox: |     case FieldType.Checkbox: | ||||||
|       return CheckboxFilterChoicechip(filterInfo: filterInfo); |       return CheckboxFilterChoicechip(filterInfo: filterInfo); | ||||||
|     case FieldType.DateTime: |     case FieldType.DateTime: | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nathan.fooo
						Nathan.fooo