mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: enable number filter (#4653)
* chore: enable filtering by number field type * chore: code cleanup * fix: integration test * chore: remove unnecessary async from event handler
This commit is contained in:
parent
1311e2d379
commit
c159a5e42b
@ -9,7 +9,7 @@ import '../util/database_test_op.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
group('database filter', () {
|
group('grid filter:', () {
|
||||||
testWidgets('add text filter', (tester) async {
|
testWidgets('add text filter', (tester) async {
|
||||||
await tester.openV020database();
|
await tester.openV020database();
|
||||||
|
|
||||||
|
@ -47,9 +47,12 @@ class FieldInfo with _$FieldInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool get canCreateFilter {
|
bool get canCreateFilter {
|
||||||
if (hasFilter) return false;
|
if (hasFilter) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (field.fieldType) {
|
switch (field.fieldType) {
|
||||||
|
case FieldType.Number:
|
||||||
case FieldType.Checkbox:
|
case FieldType.Checkbox:
|
||||||
case FieldType.MultiSelect:
|
case FieldType.MultiSelect:
|
||||||
case FieldType.RichText:
|
case FieldType.RichText:
|
||||||
@ -62,7 +65,9 @@ class FieldInfo with _$FieldInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool get canCreateSort {
|
bool get canCreateSort {
|
||||||
if (hasSort) return false;
|
if (hasSort) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (field.fieldType) {
|
switch (field.fieldType) {
|
||||||
case FieldType.RichText:
|
case FieldType.RichText:
|
||||||
|
@ -0,0 +1,117 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:appflowy/plugins/database/application/filter/filter_listener.dart';
|
||||||
|
import 'package:appflowy/plugins/database/application/filter/filter_service.dart';
|
||||||
|
import 'package:appflowy/plugins/database/grid/presentation/widgets/filter/filter_info.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'number_filter_editor_bloc.freezed.dart';
|
||||||
|
|
||||||
|
class NumberFilterEditorBloc
|
||||||
|
extends Bloc<NumberFilterEditorEvent, NumberFilterEditorState> {
|
||||||
|
NumberFilterEditorBloc({required this.filterInfo})
|
||||||
|
: _filterBackendSvc = FilterBackendService(viewId: filterInfo.viewId),
|
||||||
|
_listener = FilterListener(
|
||||||
|
viewId: filterInfo.viewId,
|
||||||
|
filterId: filterInfo.filter.id,
|
||||||
|
),
|
||||||
|
super(NumberFilterEditorState.initial(filterInfo)) {
|
||||||
|
_dispatch();
|
||||||
|
_startListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
final FilterInfo filterInfo;
|
||||||
|
final FilterBackendService _filterBackendSvc;
|
||||||
|
final FilterListener _listener;
|
||||||
|
|
||||||
|
void _dispatch() {
|
||||||
|
on<NumberFilterEditorEvent>(
|
||||||
|
(event, emit) async {
|
||||||
|
event.when(
|
||||||
|
didReceiveFilter: (filter) {
|
||||||
|
final filterInfo = state.filterInfo.copyWith(filter: filter);
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
filterInfo: filterInfo,
|
||||||
|
filter: filterInfo.numberFilter()!,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
updateCondition: (NumberFilterConditionPB condition) {
|
||||||
|
_filterBackendSvc.insertNumberFilter(
|
||||||
|
filterId: filterInfo.filter.id,
|
||||||
|
fieldId: filterInfo.fieldInfo.id,
|
||||||
|
condition: condition,
|
||||||
|
content: state.filter.content,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
updateContent: (content) {
|
||||||
|
_filterBackendSvc.insertNumberFilter(
|
||||||
|
filterId: filterInfo.filter.id,
|
||||||
|
fieldId: filterInfo.fieldInfo.id,
|
||||||
|
condition: state.filter.condition,
|
||||||
|
content: content,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
delete: () {
|
||||||
|
_filterBackendSvc.deleteFilter(
|
||||||
|
fieldId: filterInfo.fieldInfo.id,
|
||||||
|
filterId: filterInfo.filter.id,
|
||||||
|
fieldType: filterInfo.fieldInfo.fieldType,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startListening() {
|
||||||
|
_listener.start(
|
||||||
|
onDeleted: () {
|
||||||
|
if (!isClosed) {
|
||||||
|
add(const NumberFilterEditorEvent.delete());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onUpdated: (filter) {
|
||||||
|
if (!isClosed) {
|
||||||
|
add(NumberFilterEditorEvent.didReceiveFilter(filter));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
await _listener.stop();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class NumberFilterEditorEvent with _$NumberFilterEditorEvent {
|
||||||
|
const factory NumberFilterEditorEvent.didReceiveFilter(FilterPB filter) =
|
||||||
|
_DidReceiveFilter;
|
||||||
|
const factory NumberFilterEditorEvent.updateCondition(
|
||||||
|
NumberFilterConditionPB condition,
|
||||||
|
) = _UpdateCondition;
|
||||||
|
const factory NumberFilterEditorEvent.updateContent(String content) =
|
||||||
|
_UpdateContent;
|
||||||
|
const factory NumberFilterEditorEvent.delete() = _Delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class NumberFilterEditorState with _$NumberFilterEditorState {
|
||||||
|
const factory NumberFilterEditorState({
|
||||||
|
required FilterInfo filterInfo,
|
||||||
|
required NumberFilterPB filter,
|
||||||
|
}) = _NumberFilterEditorState;
|
||||||
|
|
||||||
|
factory NumberFilterEditorState.initial(FilterInfo filterInfo) {
|
||||||
|
return NumberFilterEditorState(
|
||||||
|
filterInfo: filterInfo,
|
||||||
|
filter: filterInfo.numberFilter()!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,227 @@
|
|||||||
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:appflowy/plugins/database/grid/application/filter/number_filter_editor_bloc.dart';
|
||||||
|
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
|
import '../condition_button.dart';
|
||||||
|
import '../disclosure_button.dart';
|
||||||
import '../filter_info.dart';
|
import '../filter_info.dart';
|
||||||
import 'choicechip.dart';
|
import 'choicechip.dart';
|
||||||
|
|
||||||
class NumberFilterChoicechip extends StatelessWidget {
|
class NumberFilterChoiceChip extends StatefulWidget {
|
||||||
const NumberFilterChoicechip({required this.filterInfo, super.key});
|
const NumberFilterChoiceChip({
|
||||||
|
super.key,
|
||||||
|
required this.filterInfo,
|
||||||
|
});
|
||||||
|
|
||||||
final FilterInfo filterInfo;
|
final FilterInfo filterInfo;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NumberFilterChoiceChip> createState() => _NumberFilterChoiceChipState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NumberFilterChoiceChipState extends State<NumberFilterChoiceChip> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ChoiceChipButton(filterInfo: filterInfo);
|
return BlocProvider(
|
||||||
|
create: (_) => NumberFilterEditorBloc(
|
||||||
|
filterInfo: widget.filterInfo,
|
||||||
|
),
|
||||||
|
child: BlocBuilder<NumberFilterEditorBloc, NumberFilterEditorState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return AppFlowyPopover(
|
||||||
|
constraints: BoxConstraints.loose(const Size(200, 100)),
|
||||||
|
direction: PopoverDirection.bottomWithCenterAligned,
|
||||||
|
popupBuilder: (_) {
|
||||||
|
return BlocProvider.value(
|
||||||
|
value: context.read<NumberFilterEditorBloc>(),
|
||||||
|
child: const NumberFilterEditor(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: ChoiceChipButton(
|
||||||
|
filterInfo: state.filterInfo,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NumberFilterEditor extends StatefulWidget {
|
||||||
|
const NumberFilterEditor({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NumberFilterEditor> createState() => _NumberFilterEditorState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NumberFilterEditorState extends State<NumberFilterEditor> {
|
||||||
|
final popoverMutex = PopoverMutex();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return BlocBuilder<NumberFilterEditorBloc, NumberFilterEditorState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
final List<Widget> children = [
|
||||||
|
_buildFilterPanel(context, state),
|
||||||
|
if (state.filter.condition != NumberFilterConditionPB.NumberIsEmpty &&
|
||||||
|
state.filter.condition !=
|
||||||
|
NumberFilterConditionPB.NumberIsNotEmpty) ...[
|
||||||
|
const VSpace(4),
|
||||||
|
_buildFilterNumberField(context, state),
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
|
||||||
|
child: IntrinsicHeight(child: Column(children: children)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFilterPanel(
|
||||||
|
BuildContext context,
|
||||||
|
NumberFilterEditorState state,
|
||||||
|
) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 20,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: FlowyText(
|
||||||
|
state.filterInfo.fieldInfo.name,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(4),
|
||||||
|
Expanded(
|
||||||
|
child: NumberFilterConditionPBList(
|
||||||
|
filterInfo: state.filterInfo,
|
||||||
|
popoverMutex: popoverMutex,
|
||||||
|
onCondition: (condition) {
|
||||||
|
context
|
||||||
|
.read<NumberFilterEditorBloc>()
|
||||||
|
.add(NumberFilterEditorEvent.updateCondition(condition));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const HSpace(4),
|
||||||
|
DisclosureButton(
|
||||||
|
popoverMutex: popoverMutex,
|
||||||
|
onAction: (action) {
|
||||||
|
switch (action) {
|
||||||
|
case FilterDisclosureAction.delete:
|
||||||
|
context
|
||||||
|
.read<NumberFilterEditorBloc>()
|
||||||
|
.add(const NumberFilterEditorEvent.delete());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildFilterNumberField(
|
||||||
|
BuildContext context,
|
||||||
|
NumberFilterEditorState state,
|
||||||
|
) {
|
||||||
|
return FlowyTextField(
|
||||||
|
text: state.filter.content,
|
||||||
|
hintText: LocaleKeys.grid_settings_typeAValue.tr(),
|
||||||
|
debounceDuration: const Duration(milliseconds: 300),
|
||||||
|
autoFocus: false,
|
||||||
|
onChanged: (text) {
|
||||||
|
context
|
||||||
|
.read<NumberFilterEditorBloc>()
|
||||||
|
.add(NumberFilterEditorEvent.updateContent(text));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NumberFilterConditionPBList extends StatelessWidget {
|
||||||
|
const NumberFilterConditionPBList({
|
||||||
|
super.key,
|
||||||
|
required this.filterInfo,
|
||||||
|
required this.popoverMutex,
|
||||||
|
required this.onCondition,
|
||||||
|
});
|
||||||
|
|
||||||
|
final FilterInfo filterInfo;
|
||||||
|
final PopoverMutex popoverMutex;
|
||||||
|
final Function(NumberFilterConditionPB) onCondition;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final numberFilter = filterInfo.numberFilter()!;
|
||||||
|
return PopoverActionList<ConditionWrapper>(
|
||||||
|
asBarrier: true,
|
||||||
|
mutex: popoverMutex,
|
||||||
|
direction: PopoverDirection.bottomWithCenterAligned,
|
||||||
|
actions: NumberFilterConditionPB.values
|
||||||
|
.map(
|
||||||
|
(action) => ConditionWrapper(
|
||||||
|
action,
|
||||||
|
numberFilter.condition == action,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
buildChild: (controller) {
|
||||||
|
return ConditionButton(
|
||||||
|
conditionName: numberFilter.condition.filterName,
|
||||||
|
onTap: () => controller.show(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onSelected: (action, controller) {
|
||||||
|
onCondition(action.inner);
|
||||||
|
controller.close();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConditionWrapper extends ActionCell {
|
||||||
|
ConditionWrapper(this.inner, this.isSelected);
|
||||||
|
|
||||||
|
final NumberFilterConditionPB inner;
|
||||||
|
final bool isSelected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget? rightIcon(Color iconColor) =>
|
||||||
|
isSelected ? const FlowySvg(FlowySvgs.check_s) : null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => inner.filterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NumberFilterConditionPBExtension on NumberFilterConditionPB {
|
||||||
|
String get filterName {
|
||||||
|
return switch (this) {
|
||||||
|
NumberFilterConditionPB.Equal => LocaleKeys.grid_numberFilter_equal.tr(),
|
||||||
|
NumberFilterConditionPB.NotEqual =>
|
||||||
|
LocaleKeys.grid_numberFilter_notEqual.tr(),
|
||||||
|
NumberFilterConditionPB.LessThan =>
|
||||||
|
LocaleKeys.grid_numberFilter_lessThan.tr(),
|
||||||
|
NumberFilterConditionPB.LessThanOrEqualTo =>
|
||||||
|
LocaleKeys.grid_numberFilter_lessThanOrEqualTo.tr(),
|
||||||
|
NumberFilterConditionPB.GreaterThan =>
|
||||||
|
LocaleKeys.grid_numberFilter_greaterThan.tr(),
|
||||||
|
NumberFilterConditionPB.GreaterThanOrEqualTo =>
|
||||||
|
LocaleKeys.grid_numberFilter_greaterThanOrEqualTo.tr(),
|
||||||
|
NumberFilterConditionPB.NumberIsEmpty =>
|
||||||
|
LocaleKeys.grid_numberFilter_isEmpty.tr(),
|
||||||
|
NumberFilterConditionPB.NumberIsNotEmpty =>
|
||||||
|
LocaleKeys.grid_numberFilter_isNotEmpty.tr(),
|
||||||
|
_ => "",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,51 +27,37 @@ class SelectOptionFilterList extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) {
|
create: (context) {
|
||||||
late SelectOptionFilterListBloc bloc;
|
return SelectOptionFilterListBloc(
|
||||||
if (filterInfo.fieldInfo.fieldType == FieldType.SingleSelect) {
|
selectedOptionIds: selectedOptionIds,
|
||||||
bloc = SelectOptionFilterListBloc(
|
delegate: filterInfo.fieldInfo.fieldType == FieldType.SingleSelect
|
||||||
selectedOptionIds: selectedOptionIds,
|
? SingleSelectOptionFilterDelegateImpl(filterInfo: filterInfo)
|
||||||
delegate:
|
: MultiSelectOptionFilterDelegateImpl(filterInfo: filterInfo),
|
||||||
SingleSelectOptionFilterDelegateImpl(filterInfo: filterInfo),
|
)..add(const SelectOptionFilterListEvent.initial());
|
||||||
);
|
|
||||||
} else {
|
|
||||||
bloc = SelectOptionFilterListBloc(
|
|
||||||
selectedOptionIds: selectedOptionIds,
|
|
||||||
delegate:
|
|
||||||
MultiSelectOptionFilterDelegateImpl(filterInfo: filterInfo),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bloc.add(const SelectOptionFilterListEvent.initial());
|
|
||||||
return bloc;
|
|
||||||
},
|
},
|
||||||
child:
|
child:
|
||||||
BlocListener<SelectOptionFilterListBloc, SelectOptionFilterListState>(
|
BlocConsumer<SelectOptionFilterListBloc, SelectOptionFilterListState>(
|
||||||
listenWhen: (previous, current) =>
|
listenWhen: (previous, current) =>
|
||||||
previous.selectedOptionIds != current.selectedOptionIds,
|
previous.selectedOptionIds != current.selectedOptionIds,
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
onSelectedOptions(state.selectedOptionIds.toList());
|
onSelectedOptions(state.selectedOptionIds.toList());
|
||||||
},
|
},
|
||||||
child: BlocBuilder<SelectOptionFilterListBloc,
|
builder: (context, state) {
|
||||||
SelectOptionFilterListState>(
|
return ListView.separated(
|
||||||
builder: (context, state) {
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
return ListView.separated(
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
itemCount: state.visibleOptions.length,
|
||||||
shrinkWrap: true,
|
separatorBuilder: (context, index) {
|
||||||
itemCount: state.visibleOptions.length,
|
return VSpace(GridSize.typeOptionSeparatorHeight);
|
||||||
separatorBuilder: (context, index) {
|
},
|
||||||
return VSpace(GridSize.typeOptionSeparatorHeight);
|
itemBuilder: (BuildContext context, int index) {
|
||||||
},
|
final option = state.visibleOptions[index];
|
||||||
itemBuilder: (BuildContext context, int index) {
|
return SelectOptionFilterCell(
|
||||||
final option = state.visibleOptions[index];
|
option: option.optionPB,
|
||||||
return SelectOptionFilterCell(
|
isSelected: option.isSelected,
|
||||||
option: option.optionPB,
|
);
|
||||||
isSelected: option.isSelected,
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
import 'package:appflowy/plugins/database/application/field/field_info.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/checkbox_filter.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/checklist_filter.pb.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/date_filter.pb.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_filter.pbserver.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/text_filter.pb.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/util.pb.dart';
|
|
||||||
|
|
||||||
class FilterInfo {
|
class FilterInfo {
|
||||||
FilterInfo(this.viewId, this.filter, this.fieldInfo);
|
FilterInfo(this.viewId, this.filter, this.fieldInfo);
|
||||||
@ -27,44 +21,39 @@ class FilterInfo {
|
|||||||
String get fieldId => filter.fieldId;
|
String get fieldId => filter.fieldId;
|
||||||
|
|
||||||
DateFilterPB? dateFilter() {
|
DateFilterPB? dateFilter() {
|
||||||
if (![
|
return filter.fieldType == FieldType.DateTime
|
||||||
FieldType.DateTime,
|
? DateFilterPB.fromBuffer(filter.data)
|
||||||
FieldType.LastEditedTime,
|
: null;
|
||||||
FieldType.CreatedTime,
|
|
||||||
].contains(filter.fieldType)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return DateFilterPB.fromBuffer(filter.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextFilterPB? textFilter() {
|
TextFilterPB? textFilter() {
|
||||||
if (filter.fieldType != FieldType.RichText) {
|
return filter.fieldType == FieldType.RichText
|
||||||
return null;
|
? TextFilterPB.fromBuffer(filter.data)
|
||||||
}
|
: null;
|
||||||
return TextFilterPB.fromBuffer(filter.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckboxFilterPB? checkboxFilter() {
|
CheckboxFilterPB? checkboxFilter() {
|
||||||
if (filter.fieldType != FieldType.Checkbox) {
|
return filter.fieldType == FieldType.Checkbox
|
||||||
return null;
|
? CheckboxFilterPB.fromBuffer(filter.data)
|
||||||
}
|
: null;
|
||||||
return CheckboxFilterPB.fromBuffer(filter.data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectOptionFilterPB? selectOptionFilter() {
|
SelectOptionFilterPB? selectOptionFilter() {
|
||||||
if (filter.fieldType == FieldType.SingleSelect ||
|
return filter.fieldType == FieldType.SingleSelect ||
|
||||||
filter.fieldType == FieldType.MultiSelect) {
|
filter.fieldType == FieldType.MultiSelect
|
||||||
return SelectOptionFilterPB.fromBuffer(filter.data);
|
? SelectOptionFilterPB.fromBuffer(filter.data)
|
||||||
} else {
|
: null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ChecklistFilterPB? checklistFilter() {
|
ChecklistFilterPB? checklistFilter() {
|
||||||
if (filter.fieldType == FieldType.Checklist) {
|
return filter.fieldType == FieldType.Checklist
|
||||||
return ChecklistFilterPB.fromBuffer(filter.data);
|
? ChecklistFilterPB.fromBuffer(filter.data)
|
||||||
} else {
|
: null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
NumberFilterPB? numberFilter() {
|
||||||
|
return filter.fieldType == FieldType.Number
|
||||||
|
? NumberFilterPB.fromBuffer(filter.data)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,31 +17,18 @@ class FilterMenuItem extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return buildFilterChoicechip(filterInfo);
|
return switch (filterInfo.fieldInfo.fieldType) {
|
||||||
}
|
FieldType.Checkbox => CheckboxFilterChoicechip(filterInfo: filterInfo),
|
||||||
}
|
FieldType.DateTime => DateFilterChoicechip(filterInfo: filterInfo),
|
||||||
|
FieldType.MultiSelect =>
|
||||||
Widget buildFilterChoicechip(FilterInfo filterInfo) {
|
SelectOptionFilterChoicechip(filterInfo: filterInfo),
|
||||||
switch (filterInfo.fieldInfo.fieldType) {
|
FieldType.Number => NumberFilterChoiceChip(filterInfo: filterInfo),
|
||||||
case FieldType.Checkbox:
|
FieldType.RichText => TextFilterChoicechip(filterInfo: filterInfo),
|
||||||
return CheckboxFilterChoicechip(filterInfo: filterInfo);
|
FieldType.SingleSelect =>
|
||||||
case FieldType.DateTime:
|
SelectOptionFilterChoicechip(filterInfo: filterInfo),
|
||||||
case FieldType.LastEditedTime:
|
FieldType.URL => URLFilterChoicechip(filterInfo: filterInfo),
|
||||||
case FieldType.CreatedTime:
|
FieldType.Checklist => ChecklistFilterChoicechip(filterInfo: filterInfo),
|
||||||
return DateFilterChoicechip(filterInfo: filterInfo);
|
_ => const SizedBox(),
|
||||||
case FieldType.MultiSelect:
|
};
|
||||||
return SelectOptionFilterChoicechip(filterInfo: filterInfo);
|
|
||||||
case FieldType.Number:
|
|
||||||
return NumberFilterChoicechip(filterInfo: filterInfo);
|
|
||||||
case FieldType.RichText:
|
|
||||||
return TextFilterChoicechip(filterInfo: filterInfo);
|
|
||||||
case FieldType.SingleSelect:
|
|
||||||
return SelectOptionFilterChoicechip(filterInfo: filterInfo);
|
|
||||||
case FieldType.URL:
|
|
||||||
return URLFilterChoicechip(filterInfo: filterInfo);
|
|
||||||
case FieldType.Checklist:
|
|
||||||
return ChecklistFilterChoicechip(filterInfo: filterInfo);
|
|
||||||
default:
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -540,6 +540,16 @@
|
|||||||
"empty": "Is empty",
|
"empty": "Is empty",
|
||||||
"notEmpty": "Is not empty"
|
"notEmpty": "Is not empty"
|
||||||
},
|
},
|
||||||
|
"numberFilter": {
|
||||||
|
"equal": "Equals",
|
||||||
|
"notEqual": "Does not equal",
|
||||||
|
"lessThan": "Is less than",
|
||||||
|
"greaterThan": "Is greater than",
|
||||||
|
"lessThanOrEqualTo": "Is less than or equal to",
|
||||||
|
"greaterThanOrEqualTo": "Is greater than or equal to",
|
||||||
|
"isEmpty": "Is empty",
|
||||||
|
"isNotEmpty": "Is not empty"
|
||||||
|
},
|
||||||
"field": {
|
"field": {
|
||||||
"hide": "Hide",
|
"hide": "Hide",
|
||||||
"show": "Show",
|
"show": "Show",
|
||||||
@ -1262,4 +1272,4 @@
|
|||||||
"userIcon": "User icon"
|
"userIcon": "User icon"
|
||||||
},
|
},
|
||||||
"noLogFiles": "There're no log files"
|
"noLogFiles": "There're no log files"
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user