From a1b3baa706e1381f51f8807b95ec164240f1fb0e Mon Sep 17 00:00:00 2001 From: hieubt Date: Thu, 31 Aug 2023 00:12:29 +0700 Subject: [PATCH 1/7] TF-2083 add RuleFilterConditionWidget --- .../extensions/color_extension.dart | 1 + .../model/rule_filter_condition_type.dart | 5 + .../widgets/rule_filter_condition_widget.dart | 175 ++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 lib/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart create mode 100644 lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index 1deeff0441..3ba17921ea 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -206,6 +206,7 @@ extension AppColor on Color { static const colorClosePopupDialogButton = Color(0xFFAEB7C2); static const colorEmptyPopupDialogButton = Color(0xFFFFC107); static const colorCancelPopupDialogButton = Color(0xFFEBEDF0); + static const colorRemoveRuleFilterConditionButton = Color(0xFFE6E8EC); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/lib/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart b/lib/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart new file mode 100644 index 0000000000..5c85247b0b --- /dev/null +++ b/lib/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart @@ -0,0 +1,5 @@ +enum RuleFilterConditionType { + mobile, + tablet, + desktop +} \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart new file mode 100644 index 0000000000..88c7071b9a --- /dev/null +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart @@ -0,0 +1,175 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/utils/keyboard_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart'; +import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition; +import 'package:rule_filter/rule_filter/rule_condition.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; +import 'package:core/presentation/resources/image_paths.dart'; + +class RuleFilterConditionWidget extends StatelessWidget { + final RuleFilterConditionType? ruleFilterConditionType; + final RuleCondition? ruleCondition; + final Function(Field?)? tapRuleConditionFieldCallback; + final Function(Comparator?)? tapRuleConditionComparatorCallback; + final String? conditionValueErrorText; + final TextEditingController? conditionValueEditingController; + final FocusNode? conditionValueFocusNode; + final OnChangeFilterInputAction? conditionValueOnChangeAction; + final ImagePaths? imagePaths; + final Function()? onTapRemoveRuleFilterConditionCallback; + + const RuleFilterConditionWidget({ + super.key, + this.ruleFilterConditionType, + this.ruleCondition, + this.tapRuleConditionFieldCallback, + this.tapRuleConditionComparatorCallback, + this.conditionValueErrorText, + this.conditionValueEditingController, + this.conditionValueFocusNode, + this.conditionValueOnChangeAction, + this.imagePaths, + this.onTapRemoveRuleFilterConditionCallback, + }); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: AppColor.colorBackgroundFieldConditionRulesFilter, + borderRadius: BorderRadius.circular(12), + ), + child: _buildRuleFilterCondition( + context, + ruleFilterConditionType, + ruleCondition, + tapRuleConditionFieldCallback, + tapRuleConditionComparatorCallback, + conditionValueErrorText, + conditionValueEditingController, + conditionValueFocusNode, + conditionValueOnChangeAction, + onTapRemoveRuleFilterConditionCallback, + imagePaths, + ) + ); + + } +} + +Widget _buildRuleFilterCondition( + BuildContext context, + RuleFilterConditionType? ruleFilterConditionType, + RuleCondition? ruleCondition, + Function(Field?)? tapRuleConditionFieldCallback, + Function(Comparator?)? tapRuleConditionComparatorCallback, + String? conditionValueErrorText, + TextEditingController? conditionValueEditingController, + FocusNode? conditionValueFocusNode, + OnChangeFilterInputAction? conditionValueOnChangeAction, + Function()? onTapRemoveRuleFilterConditionCallback, + ImagePaths? imagePaths, +) { + switch (ruleFilterConditionType) { + case RuleFilterConditionType.mobile: + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RuleFilterButtonField( + value: ruleCondition!.field.obs.value, + tapActionCallback: (value) { + KeyboardUtils.hideKeyboard(context); + tapRuleConditionFieldCallback!(ruleCondition.field); + }, + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: RuleFilterButtonField( + value: ruleCondition!.comparator.obs.value, + tapActionCallback: (value) { + KeyboardUtils.hideKeyboard(context); + tapRuleConditionComparatorCallback!(ruleCondition.comparator); + }, + ) + ), + RulesFilterInputField( + hintText: AppLocalizations.of(context).conditionValueHintTextInput, + errorText: conditionValueErrorText, + focusNode: conditionValueFocusNode, + onChangeAction: conditionValueOnChangeAction, + editingController: conditionValueEditingController, + ), + ], + ); + case RuleFilterConditionType.tablet: + case RuleFilterConditionType.desktop: + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: DropDownButtonWidget( + items: rule_condition.Field.values, + itemSelected: ruleCondition!.field.obs.value, + dropdownMaxHeight: 250, + onChanged: (newField) => { + tapRuleConditionFieldCallback!(newField) + }, + supportSelectionIcon: true, + ) + ), + Container( + width: 220, + padding: const EdgeInsets.symmetric(horizontal: 12), + child: DropDownButtonWidget( + items: rule_condition.Comparator.values, + itemSelected: ruleCondition!.comparator.obs.value, + onChanged: (newComparator) => { + tapRuleConditionComparatorCallback!(newComparator) + }, + supportSelectionIcon: true, + ) + ), + Expanded( + child: RulesFilterInputField( + hintText: AppLocalizations.of(context).conditionValueHintTextInput, + errorText: conditionValueErrorText, + focusNode: conditionValueFocusNode, + onChangeAction: conditionValueOnChangeAction, + editingController: conditionValueEditingController, + ) + ), + _buildRemoveRuleFilterConditionButton(onTapRemoveRuleFilterConditionCallback, imagePaths), + ], + ); + default: + return Container(); + } +} + +Widget _buildRemoveRuleFilterConditionButton ( + Function()? onTapRemoveRuleFilterConditionCallback, + ImagePaths? imagePath, +) { + return Container( + padding: const EdgeInsets.only(left: 12), + child: InkWell( + onTap: onTapRemoveRuleFilterConditionCallback, + child: CircleAvatar( + backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, + radius: 22, + child: SvgPicture.asset( + imagePath!.icMinimize, + fit: BoxFit.fill, + colorFilter: AppColor.colorDeletePermanentlyButton.asFilter(), + ), + ) + ), + ); +} \ No newline at end of file From a482ff658fb7713af37a0cdc84b5ca3806b19af5 Mon Sep 17 00:00:00 2001 From: hieubt Date: Thu, 31 Aug 2023 12:30:39 +0700 Subject: [PATCH 2/7] TF-2083 change condition widget to RuleFilterConditionWidget --- .../rules_filter_creator_controller.dart | 24 +- .../rules_filter_creator_view.dart | 320 +++++++++++------- .../widgets/rule_filter_condition_widget.dart | 38 +-- 3 files changed, 236 insertions(+), 146 deletions(-) diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart index 5d584a8ef8..30d035b291 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart @@ -14,6 +14,7 @@ import 'package:model/model.dart'; import 'package:rule_filter/rule_filter/rule_action.dart'; import 'package:rule_filter/rule_filter/rule_append_in.dart'; import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition; +import 'package:rule_filter/rule_filter/rule_condition.dart'; import 'package:rule_filter/rule_filter/tmail_rule.dart'; import 'package:tmail_ui_user/features/base/base_mailbox_controller.dart'; import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart'; @@ -55,6 +56,7 @@ class RulesFilterCreatorController extends BaseMailboxController { final emailRuleFilterActionSelected = Rxn(); final mailboxSelected = Rxn(); final actionType = CreatorActionType.create.obs; + final listRuleCondition = RxList(); final TextEditingController inputRuleNameController = TextEditingController(); final TextEditingController inputConditionValueController = TextEditingController(); @@ -145,6 +147,12 @@ class RulesFilterCreatorController extends BaseMailboxController { case CreatorActionType.create: ruleConditionFieldSelected.value = rule_condition.Field.from; ruleConditionComparatorSelected.value = rule_condition.Comparator.contains; + RuleCondition newRuleCondition = RuleCondition( + field: rule_condition.Field.from, + comparator: rule_condition.Comparator.contains, + value: '' + ); + listRuleCondition.add(newRuleCondition); emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; if (_emailAddress != null) { _newRuleConditionValue = _emailAddress?.email; @@ -158,6 +166,12 @@ class RulesFilterCreatorController extends BaseMailboxController { if (_currentTMailRule != null) { ruleConditionFieldSelected.value = _currentTMailRule!.condition.field; ruleConditionComparatorSelected.value = _currentTMailRule!.condition.comparator; + RuleCondition currentRule = RuleCondition( + field: _currentTMailRule!.condition.field, + comparator: _currentTMailRule!.condition.comparator, + value: _currentTMailRule!.condition.value + ); + listRuleCondition.add(currentRule); emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; _newRuleConditionValue = _currentTMailRule!.condition.value; _setValueInputField(inputConditionValueController, _newRuleConditionValue ?? ''); @@ -213,12 +227,14 @@ class RulesFilterCreatorController extends BaseMailboxController { ); } - void selectRuleConditionField(rule_condition.Field? newField) { - ruleConditionFieldSelected.value = newField; + void selectRuleConditionField(rule_condition.Field? newField, int? ruleConditionIndex) { + listRuleCondition[ruleConditionIndex!].field.obs.value = newField!; + listRuleCondition.refresh(); } - void selectRuleConditionComparator(rule_condition.Comparator? newComparator) { - ruleConditionComparatorSelected.value = newComparator; + void selectRuleConditionComparator(rule_condition.Comparator? newComparator, int? ruleConditionIndex) { + listRuleCondition[ruleConditionIndex!].comparator.obs.value = newComparator!; + listRuleCondition.refresh(); } void selectEmailRuleFilterAction(EmailRuleFilterAction? newAction) { diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart index 373578814f..77d17f77cb 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; import 'package:model/model.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition; +import 'package:rule_filter/rule_filter/rule_condition.dart'; import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart'; @@ -13,10 +14,13 @@ import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_condition_comparator_bottom_sheet_action_tile_builder.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_condition_field_bottom_sheet_action_tile_builder.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +import 'model/rule_filter_condition_type.dart'; + class RuleFilterCreatorView extends GetWidget { final _imagePaths = Get.find(); @@ -143,40 +147,62 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColor.colorBackgroundFieldConditionRulesFilter, - borderRadius: BorderRadius.circular(12)), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded(child: Obx(() => DropDownButtonWidget( - items: rule_condition.Field.values, - itemSelected: controller.ruleConditionFieldSelected.value, - dropdownMaxHeight: 250, - onChanged: (newField) => - controller.selectRuleConditionField(newField), - supportSelectionIcon: true))), - Container( - width: 220, - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Obx(() => DropDownButtonWidget( - items: rule_condition.Comparator.values, - itemSelected: controller.ruleConditionComparatorSelected.value, - onChanged: (newComparator) => - controller.selectRuleConditionComparator(newComparator), - supportSelectionIcon: true))), - Expanded(child: Obx(() => RulesFilterInputField( - hintText: AppLocalizations.of(context).conditionValueHintTextInput, - errorText: controller.errorRuleConditionValue.value, - editingController: controller.inputConditionValueController, - focusNode: controller.inputRuleConditionFocusNode, - onChangeAction: (value) => - controller.updateConditionValue(context, value)))) - ] - ) - ), + // Container( + // padding: const EdgeInsets.all(12), + // decoration: BoxDecoration( + // color: AppColor.colorBackgroundFieldConditionRulesFilter, + // borderRadius: BorderRadius.circular(12)), + // child: Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Expanded(child: Obx(() => DropDownButtonWidget( + // items: rule_condition.Field.values, + // itemSelected: controller.ruleConditionFieldSelected.value, + // dropdownMaxHeight: 250, + // onChanged: (newField) => + // controller.selectRuleConditionField(newField), + // supportSelectionIcon: true))), + // Container( + // width: 220, + // padding: const EdgeInsets.symmetric(horizontal: 12), + // child: Obx(() => DropDownButtonWidget( + // items: rule_condition.Comparator.values, + // itemSelected: controller.ruleConditionComparatorSelected.value, + // onChanged: (newComparator) => + // controller.selectRuleConditionComparator(newComparator), + // supportSelectionIcon: true))), + // Expanded(child: Obx(() => RulesFilterInputField( + // hintText: AppLocalizations.of(context).conditionValueHintTextInput, + // errorText: controller.errorRuleConditionValue.value, + // editingController: controller.inputConditionValueController, + // focusNode: controller.inputRuleConditionFocusNode, + // onChangeAction: (value) => + // controller.updateConditionValue(context, value)))) + // ] + // ) + // ), + Obx(() { + return ListView.builder( + shrinkWrap: true, + itemCount: controller.listRuleCondition.length, + itemBuilder: (context, index) { + return RuleFilterConditionWidget( + ruleFilterConditionType: RuleFilterConditionType.desktop, + ruleCondition: controller.listRuleCondition[index], + imagePaths: _imagePaths, + conditionValueErrorText: controller.errorRuleConditionValue.value, + conditionValueFocusNode: controller.inputRuleConditionFocusNode, + conditionValueEditingController: controller.inputConditionValueController, + tapRuleConditionFieldCallback: (value) => + controller.selectRuleConditionField(value, index), + tapRuleConditionComparatorCallback: (value) => + controller.selectRuleConditionComparator(value, index), + conditionValueOnChangeAction: (value) => + controller.updateConditionValue(context, value), + ); + } + ); + }), const SizedBox(height: 24), Text(AppLocalizations.of(context).actionTitleRulesFilter, overflow: CommonTextStyle.defaultTextOverFlow, @@ -302,40 +328,62 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColor.colorBackgroundFieldConditionRulesFilter, - borderRadius: BorderRadius.circular(12)), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded(child: Obx(() => DropDownButtonWidget( - items: rule_condition.Field.values, - itemSelected: controller.ruleConditionFieldSelected.value, - dropdownMaxHeight: 250, - onChanged: (newField) => - controller.selectRuleConditionField(newField), - supportSelectionIcon: true))), - Container( - width: 220, - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Obx(() => DropDownButtonWidget( - items: rule_condition.Comparator.values, - itemSelected: controller.ruleConditionComparatorSelected.value, - onChanged: (newComparator) => - controller.selectRuleConditionComparator(newComparator), - supportSelectionIcon: true))), - Expanded(child: Obx(() => RulesFilterInputField( - hintText: AppLocalizations.of(context).conditionValueHintTextInput, - errorText: controller.errorRuleConditionValue.value, - editingController: controller.inputConditionValueController, - focusNode: controller.inputRuleConditionFocusNode, - onChangeAction: (value) => - controller.updateConditionValue(context, value)))) - ] - ) - ), + // Container( + // padding: const EdgeInsets.all(12), + // decoration: BoxDecoration( + // color: AppColor.colorBackgroundFieldConditionRulesFilter, + // borderRadius: BorderRadius.circular(12)), + // child: Row( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Expanded(child: Obx(() => DropDownButtonWidget( + // items: rule_condition.Field.values, + // itemSelected: controller.ruleConditionFieldSelected.value, + // dropdownMaxHeight: 250, + // onChanged: (newField) => + // controller.selectRuleConditionField(newField), + // supportSelectionIcon: true))), + // Container( + // width: 220, + // padding: const EdgeInsets.symmetric(horizontal: 12), + // child: Obx(() => DropDownButtonWidget( + // items: rule_condition.Comparator.values, + // itemSelected: controller.ruleConditionComparatorSelected.value, + // onChanged: (newComparator) => + // controller.selectRuleConditionComparator(newComparator), + // supportSelectionIcon: true))), + // Expanded(child: Obx(() => RulesFilterInputField( + // hintText: AppLocalizations.of(context).conditionValueHintTextInput, + // errorText: controller.errorRuleConditionValue.value, + // editingController: controller.inputConditionValueController, + // focusNode: controller.inputRuleConditionFocusNode, + // onChangeAction: (value) => + // controller.updateConditionValue(context, value)))) + // ] + // ) + // ), + Obx(() { + return ListView.builder( + shrinkWrap: true, + itemCount: controller.listRuleCondition.length, + itemBuilder: (context, index) { + return RuleFilterConditionWidget( + ruleFilterConditionType: RuleFilterConditionType.tablet, + ruleCondition: controller.listRuleCondition[index], + imagePaths: _imagePaths, + conditionValueErrorText: controller.errorRuleConditionValue.value, + conditionValueFocusNode: controller.inputRuleConditionFocusNode, + conditionValueEditingController: controller.inputConditionValueController, + tapRuleConditionFieldCallback: (value) => + controller.selectRuleConditionField(value, index), + tapRuleConditionComparatorCallback: (value) => + controller.selectRuleConditionComparator(value, index), + conditionValueOnChangeAction: (value) => + controller.updateConditionValue(context, value), + ); + } + ); + }), const SizedBox(height: 24), Text(AppLocalizations.of(context).actionTitleRulesFilter, overflow: CommonTextStyle.defaultTextOverFlow, @@ -467,53 +515,75 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColor.colorBackgroundFieldConditionRulesFilter, - borderRadius: BorderRadius.circular(12)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Obx(() { - return RuleFilterButtonField( - value: controller.ruleConditionFieldSelected.value, - tapActionCallback: (value) { - KeyboardUtils.hideKeyboard(context); - controller.openContextMenuAction( - context, - _bottomSheetRuleConditionFieldActionTiles( - context, - controller.ruleConditionFieldSelected.value)); - } - ); - }), - Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: Obx(() { - return RuleFilterButtonField( - value: controller.ruleConditionComparatorSelected.value, - tapActionCallback: (value) { - KeyboardUtils.hideKeyboard(context); - controller.openContextMenuAction( - context, - _bottomSheetRuleConditionComparatorActionTiles( - context, - controller.ruleConditionComparatorSelected.value)); - } - ); - }), - ), - Obx(() => RulesFilterInputField( - hintText: AppLocalizations.of(context).conditionValueHintTextInput, - errorText: controller.errorRuleConditionValue.value, - editingController: controller.inputConditionValueController, - focusNode: controller.inputRuleConditionFocusNode, - onChangeAction: (value) => - controller.updateConditionValue(context, value))) - ] - ) - ), + // Container( + // padding: const EdgeInsets.all(12), + // decoration: BoxDecoration( + // color: AppColor.colorBackgroundFieldConditionRulesFilter, + // borderRadius: BorderRadius.circular(12)), + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // Obx(() { + // return RuleFilterButtonField( + // value: controller.ruleConditionFieldSelected.value, + // tapActionCallback: (value) { + // KeyboardUtils.hideKeyboard(context); + // controller.openContextMenuAction( + // context, + // _bottomSheetRuleConditionFieldActionTiles( + // context, + // controller.ruleConditionFieldSelected.value)); + // } + // ); + // }), + // Padding( + // padding: const EdgeInsets.symmetric(vertical: 12), + // child: Obx(() { + // return RuleFilterButtonField( + // value: controller.ruleConditionComparatorSelected.value, + // tapActionCallback: (value) { + // KeyboardUtils.hideKeyboard(context); + // controller.openContextMenuAction( + // context, + // _bottomSheetRuleConditionComparatorActionTiles( + // context, + // controller.ruleConditionComparatorSelected.value)); + // } + // ); + // }), + // ), + // Obx(() => RulesFilterInputField( + // hintText: AppLocalizations.of(context).conditionValueHintTextInput, + // errorText: controller.errorRuleConditionValue.value, + // editingController: controller.inputConditionValueController, + // focusNode: controller.inputRuleConditionFocusNode, + // onChangeAction: (value) => + // controller.updateConditionValue(context, value))) + // ] + // ) + // ), + Obx(() { + return ListView.builder( + shrinkWrap: true, + itemCount: controller.listRuleCondition.length, + itemBuilder: (context, index) { + return RuleFilterConditionWidget( + ruleFilterConditionType: RuleFilterConditionType.mobile, + ruleCondition: controller.listRuleCondition[index], + imagePaths: _imagePaths, + conditionValueErrorText: controller.errorRuleConditionValue.value, + conditionValueFocusNode: controller.inputRuleConditionFocusNode, + conditionValueEditingController: controller.inputConditionValueController, + tapRuleConditionFieldCallback: (value) => + controller.selectRuleConditionField(value, index), + tapRuleConditionComparatorCallback: (value) => + controller.selectRuleConditionComparator(value, index), + conditionValueOnChangeAction: (value) => + controller.updateConditionValue(context, value), + ); + } + ); + }), const Padding( padding: EdgeInsets.symmetric(vertical: 12), child: Divider( @@ -616,18 +686,20 @@ class RuleFilterCreatorView extends GetWidget { List _bottomSheetRuleConditionFieldActionTiles( BuildContext context, - rule_condition.Field? fieldSelected + rule_condition.Field? fieldSelected, + int? ruleConditionIndex, ) { return rule_condition.Field.values .map((field) => - _buildRuleConditionFieldWidget(context, field, fieldSelected)) + _buildRuleConditionFieldWidget(context, field, fieldSelected, ruleConditionIndex)) .toList(); } Widget _buildRuleConditionFieldWidget( BuildContext context, rule_condition.Field field, - rule_condition.Field? fieldSelected + rule_condition.Field? fieldSelected, + int? ruleConditionIndex, ) { return (RuleConditionFieldSheetActionTileBuilder( field.getTitle(context), @@ -641,7 +713,7 @@ class RuleFilterCreatorView extends GetWidget { height: 20, fit: BoxFit.fill)) ..onActionClick((field) { - controller.selectRuleConditionField(field); + controller.selectRuleConditionField(field, ruleConditionIndex); popBack(); })) .build(); @@ -649,18 +721,20 @@ class RuleFilterCreatorView extends GetWidget { List _bottomSheetRuleConditionComparatorActionTiles( BuildContext context, - rule_condition.Comparator? comparatorSelected + rule_condition.Comparator? comparatorSelected, + int? ruleConditionIndex, ) { return rule_condition.Comparator.values .map((comparator) => - _buildRuleConditionComparatorWidget(context, comparator, comparatorSelected)) + _buildRuleConditionComparatorWidget(context, comparator, comparatorSelected, ruleConditionIndex)) .toList(); } Widget _buildRuleConditionComparatorWidget( BuildContext context, rule_condition.Comparator comparator, - rule_condition.Comparator? comparatorSelected + rule_condition.Comparator? comparatorSelected, + int? ruleConditionIndex, ) { return (RuleConditionComparatorSheetActionTileBuilder( comparator.getTitle(context), @@ -674,7 +748,7 @@ class RuleFilterCreatorView extends GetWidget { height: 20, fit: BoxFit.fill)) ..onActionClick((comparator) { - controller.selectRuleConditionComparator(comparator); + controller.selectRuleConditionComparator(comparator, ruleConditionIndex); popBack(); })) .build(); diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart index 88c7071b9a..8bcbba3b8a 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart @@ -41,25 +41,25 @@ class RuleFilterConditionWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColor.colorBackgroundFieldConditionRulesFilter, - borderRadius: BorderRadius.circular(12), - ), - child: _buildRuleFilterCondition( - context, - ruleFilterConditionType, - ruleCondition, - tapRuleConditionFieldCallback, - tapRuleConditionComparatorCallback, - conditionValueErrorText, - conditionValueEditingController, - conditionValueFocusNode, - conditionValueOnChangeAction, - onTapRemoveRuleFilterConditionCallback, - imagePaths, - ) - ); + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: AppColor.colorBackgroundFieldConditionRulesFilter, + borderRadius: BorderRadius.circular(12), + ), + child: _buildRuleFilterCondition( + context, + ruleFilterConditionType, + ruleCondition, + tapRuleConditionFieldCallback, + tapRuleConditionComparatorCallback, + conditionValueErrorText, + conditionValueEditingController, + conditionValueFocusNode, + conditionValueOnChangeAction, + onTapRemoveRuleFilterConditionCallback, + imagePaths, + ) + ); } } From 0a5c636da526d9e775c1e7be13a0a63491679ccc Mon Sep 17 00:00:00 2001 From: hieubt Date: Thu, 31 Aug 2023 15:41:55 +0700 Subject: [PATCH 3/7] TF-2083 Add listRuleCondition --- .../rules_filter_creator_controller.dart | 71 ++++-- .../rules_filter_creator_view.dart | 235 ++++++++---------- .../widgets/rule_filter_condition_widget.dart | 17 +- lib/l10n/intl_messages.arb | 8 +- lib/main/localizations/app_localizations.dart | 7 + 5 files changed, 185 insertions(+), 153 deletions(-) diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart index 30d035b291..0da27c21a0 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart @@ -4,6 +4,7 @@ import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/presentation/utils/keyboard_utils.dart'; import 'package:core/utils/app_logger.dart'; import 'package:core/utils/platform_info.dart'; +import 'package:equatable/equatable.dart'; import 'package:flutter/cupertino.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; @@ -51,8 +52,6 @@ class RulesFilterCreatorController extends BaseMailboxController { final errorRuleName = Rxn(); final errorRuleConditionValue = Rxn(); final errorRuleActionValue = Rxn(); - final ruleConditionFieldSelected = Rxn(); - final ruleConditionComparatorSelected = Rxn(); final emailRuleFilterActionSelected = Rxn(); final mailboxSelected = Rxn(); final actionType = CreatorActionType.create.obs; @@ -145,8 +144,6 @@ class RulesFilterCreatorController extends BaseMailboxController { void _setUpDefaultValueRuleFilter() { switch(actionType.value) { case CreatorActionType.create: - ruleConditionFieldSelected.value = rule_condition.Field.from; - ruleConditionComparatorSelected.value = rule_condition.Comparator.contains; RuleCondition newRuleCondition = RuleCondition( field: rule_condition.Field.from, comparator: rule_condition.Comparator.contains, @@ -164,8 +161,6 @@ class RulesFilterCreatorController extends BaseMailboxController { break; case CreatorActionType.edit: if (_currentTMailRule != null) { - ruleConditionFieldSelected.value = _currentTMailRule!.condition.field; - ruleConditionComparatorSelected.value = _currentTMailRule!.condition.comparator; RuleCondition currentRule = RuleCondition( field: _currentTMailRule!.condition.field, comparator: _currentTMailRule!.condition.comparator, @@ -228,12 +223,22 @@ class RulesFilterCreatorController extends BaseMailboxController { } void selectRuleConditionField(rule_condition.Field? newField, int? ruleConditionIndex) { - listRuleCondition[ruleConditionIndex!].field.obs.value = newField!; + RuleCondition newRuleCondition = RuleCondition( + field: newField!, + comparator: listRuleCondition[ruleConditionIndex!].comparator.obs.value, + value: listRuleCondition[ruleConditionIndex].value.obs.value, + ); + listRuleCondition[ruleConditionIndex] = newRuleCondition; listRuleCondition.refresh(); } void selectRuleConditionComparator(rule_condition.Comparator? newComparator, int? ruleConditionIndex) { - listRuleCondition[ruleConditionIndex!].comparator.obs.value = newComparator!; + RuleCondition newRuleCondition = RuleCondition( + field: listRuleCondition[ruleConditionIndex!].field.obs.value, + comparator: newComparator!, + value: listRuleCondition[ruleConditionIndex].value.obs.value, + ); + listRuleCondition[ruleConditionIndex] = newRuleCondition; listRuleCondition.refresh(); } @@ -289,9 +294,7 @@ class RulesFilterCreatorController extends BaseMailboxController { return; } - if (ruleConditionFieldSelected.value == null || - ruleConditionComparatorSelected.value == null || - emailRuleFilterActionSelected.value == null) { + if (listRuleCondition.isEmpty || emailRuleFilterActionSelected.value == null) { if (currentOverlayContext != null && currentContext != null) { _appToast.showToastErrorMessage( currentOverlayContext!, @@ -300,7 +303,11 @@ class RulesFilterCreatorController extends BaseMailboxController { return; } - final newTMailRule = TMailRule( + late EquatableMixin ruleFilterRequest; + + if (actionType.value == CreatorActionType.create) { + for (var ruleCondition in listRuleCondition) { + final newTMailRule = TMailRule( id: _currentTMailRule?.id, name: _newRuleName!, action: RuleAction( @@ -309,15 +316,28 @@ class RulesFilterCreatorController extends BaseMailboxController { ) ), condition: rule_condition.RuleCondition( - field: ruleConditionFieldSelected.value!, - comparator: ruleConditionComparatorSelected.value!, + field: ruleCondition.field, + comparator: ruleCondition.comparator, value: _newRuleConditionValue! )); - - final ruleFilterRequest = - actionType.value == CreatorActionType.create - ? CreateNewEmailRuleFilterRequest(_listEmailRule ?? [], newTMailRule) - : EditEmailRuleFilterRequest(_listEmailRule?.withIds ?? [], newTMailRule); + ruleFilterRequest = CreateNewEmailRuleFilterRequest(_listEmailRule ?? [], newTMailRule); + } + } else { + final newTMailRule = TMailRule( + id: _currentTMailRule?.id, + name: _newRuleName!, + action: RuleAction( + appendIn: RuleAppendIn( + mailboxIds: [mailboxSelected.value!.id] + ) + ), + condition: rule_condition.RuleCondition( + field: listRuleCondition[0].field, + comparator: listRuleCondition[0].comparator, + value: _newRuleConditionValue! + )); + ruleFilterRequest = EditEmailRuleFilterRequest(_listEmailRule?.withIds ?? [], newTMailRule); + } popBack(result: ruleFilterRequest); } @@ -325,4 +345,17 @@ class RulesFilterCreatorController extends BaseMailboxController { KeyboardUtils.hideKeyboard(context); popBack(); } + + void tapAddCondition() { + RuleCondition newRuleCondition = RuleCondition( + field: rule_condition.Field.from, + comparator: rule_condition.Comparator.contains, + value: '' + ); + listRuleCondition.add(newRuleCondition); + } + + void tapRemoveCondition(int ruleConditionIndex) { + listRuleCondition.removeAt(ruleConditionIndex); + } } \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart index 77d17f77cb..2284dee247 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart @@ -147,42 +147,8 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - // Container( - // padding: const EdgeInsets.all(12), - // decoration: BoxDecoration( - // color: AppColor.colorBackgroundFieldConditionRulesFilter, - // borderRadius: BorderRadius.circular(12)), - // child: Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Expanded(child: Obx(() => DropDownButtonWidget( - // items: rule_condition.Field.values, - // itemSelected: controller.ruleConditionFieldSelected.value, - // dropdownMaxHeight: 250, - // onChanged: (newField) => - // controller.selectRuleConditionField(newField), - // supportSelectionIcon: true))), - // Container( - // width: 220, - // padding: const EdgeInsets.symmetric(horizontal: 12), - // child: Obx(() => DropDownButtonWidget( - // items: rule_condition.Comparator.values, - // itemSelected: controller.ruleConditionComparatorSelected.value, - // onChanged: (newComparator) => - // controller.selectRuleConditionComparator(newComparator), - // supportSelectionIcon: true))), - // Expanded(child: Obx(() => RulesFilterInputField( - // hintText: AppLocalizations.of(context).conditionValueHintTextInput, - // errorText: controller.errorRuleConditionValue.value, - // editingController: controller.inputConditionValueController, - // focusNode: controller.inputRuleConditionFocusNode, - // onChangeAction: (value) => - // controller.updateConditionValue(context, value)))) - // ] - // ) - // ), Obx(() { - return ListView.builder( + return ListView.separated( shrinkWrap: true, itemCount: controller.listRuleCondition.length, itemBuilder: (context, index) { @@ -199,10 +165,39 @@ class RuleFilterCreatorView extends GetWidget { controller.selectRuleConditionComparator(value, index), conditionValueOnChangeAction: (value) => controller.updateConditionValue(context, value), + tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), ); - } + }, + separatorBuilder: (context, index) { + return const SizedBox(height: 12,); + }, ); }), + Container( + padding: const EdgeInsets.only(top: 8), + child: InkWell( + onTap: controller.tapAddCondition, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SvgPicture.asset( + _imagePaths.icAddNewFolder, + fit: BoxFit.fill, + ), + const SizedBox(width: 15,), + Text( + AppLocalizations.of(context).addCondition, + maxLines: 1, + style: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 17, + color: AppColor.primaryColor + ) + ) + ], + ), + ), + ), const SizedBox(height: 24), Text(AppLocalizations.of(context).actionTitleRulesFilter, overflow: CommonTextStyle.defaultTextOverFlow, @@ -328,42 +323,8 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - // Container( - // padding: const EdgeInsets.all(12), - // decoration: BoxDecoration( - // color: AppColor.colorBackgroundFieldConditionRulesFilter, - // borderRadius: BorderRadius.circular(12)), - // child: Row( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Expanded(child: Obx(() => DropDownButtonWidget( - // items: rule_condition.Field.values, - // itemSelected: controller.ruleConditionFieldSelected.value, - // dropdownMaxHeight: 250, - // onChanged: (newField) => - // controller.selectRuleConditionField(newField), - // supportSelectionIcon: true))), - // Container( - // width: 220, - // padding: const EdgeInsets.symmetric(horizontal: 12), - // child: Obx(() => DropDownButtonWidget( - // items: rule_condition.Comparator.values, - // itemSelected: controller.ruleConditionComparatorSelected.value, - // onChanged: (newComparator) => - // controller.selectRuleConditionComparator(newComparator), - // supportSelectionIcon: true))), - // Expanded(child: Obx(() => RulesFilterInputField( - // hintText: AppLocalizations.of(context).conditionValueHintTextInput, - // errorText: controller.errorRuleConditionValue.value, - // editingController: controller.inputConditionValueController, - // focusNode: controller.inputRuleConditionFocusNode, - // onChangeAction: (value) => - // controller.updateConditionValue(context, value)))) - // ] - // ) - // ), Obx(() { - return ListView.builder( + return ListView.separated( shrinkWrap: true, itemCount: controller.listRuleCondition.length, itemBuilder: (context, index) { @@ -380,10 +341,39 @@ class RuleFilterCreatorView extends GetWidget { controller.selectRuleConditionComparator(value, index), conditionValueOnChangeAction: (value) => controller.updateConditionValue(context, value), + tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), ); - } + }, + separatorBuilder: (context, index) { + return const SizedBox(height: 12,); + }, ); }), + Container( + padding: const EdgeInsets.only(top: 8), + child: InkWell( + onTap: controller.tapAddCondition, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SvgPicture.asset( + _imagePaths.icAddNewFolder, + fit: BoxFit.fill, + ), + const SizedBox(width: 15,), + Text( + AppLocalizations.of(context).addCondition, + maxLines: 1, + style: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 17, + color: AppColor.primaryColor + ) + ) + ], + ), + ), + ), const SizedBox(height: 24), Text(AppLocalizations.of(context).actionTitleRulesFilter, overflow: CommonTextStyle.defaultTextOverFlow, @@ -515,55 +505,8 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - // Container( - // padding: const EdgeInsets.all(12), - // decoration: BoxDecoration( - // color: AppColor.colorBackgroundFieldConditionRulesFilter, - // borderRadius: BorderRadius.circular(12)), - // child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Obx(() { - // return RuleFilterButtonField( - // value: controller.ruleConditionFieldSelected.value, - // tapActionCallback: (value) { - // KeyboardUtils.hideKeyboard(context); - // controller.openContextMenuAction( - // context, - // _bottomSheetRuleConditionFieldActionTiles( - // context, - // controller.ruleConditionFieldSelected.value)); - // } - // ); - // }), - // Padding( - // padding: const EdgeInsets.symmetric(vertical: 12), - // child: Obx(() { - // return RuleFilterButtonField( - // value: controller.ruleConditionComparatorSelected.value, - // tapActionCallback: (value) { - // KeyboardUtils.hideKeyboard(context); - // controller.openContextMenuAction( - // context, - // _bottomSheetRuleConditionComparatorActionTiles( - // context, - // controller.ruleConditionComparatorSelected.value)); - // } - // ); - // }), - // ), - // Obx(() => RulesFilterInputField( - // hintText: AppLocalizations.of(context).conditionValueHintTextInput, - // errorText: controller.errorRuleConditionValue.value, - // editingController: controller.inputConditionValueController, - // focusNode: controller.inputRuleConditionFocusNode, - // onChangeAction: (value) => - // controller.updateConditionValue(context, value))) - // ] - // ) - // ), Obx(() { - return ListView.builder( + return ListView.separated( shrinkWrap: true, itemCount: controller.listRuleCondition.length, itemBuilder: (context, index) { @@ -574,16 +517,58 @@ class RuleFilterCreatorView extends GetWidget { conditionValueErrorText: controller.errorRuleConditionValue.value, conditionValueFocusNode: controller.inputRuleConditionFocusNode, conditionValueEditingController: controller.inputConditionValueController, - tapRuleConditionFieldCallback: (value) => - controller.selectRuleConditionField(value, index), - tapRuleConditionComparatorCallback: (value) => - controller.selectRuleConditionComparator(value, index), + tapRuleConditionFieldCallback: (value) => controller.openContextMenuAction( + context, + _bottomSheetRuleConditionFieldActionTiles( + context, + controller.listRuleCondition[index].field.obs.value, + index, + ) + ), + tapRuleConditionComparatorCallback: (value) => controller.openContextMenuAction( + context, + _bottomSheetRuleConditionComparatorActionTiles( + context, + controller.listRuleCondition[index].comparator.obs.value, + index, + ) + ), conditionValueOnChangeAction: (value) => controller.updateConditionValue(context, value), + tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), ); - } + }, + separatorBuilder: (context, index) { + return const SizedBox(height: 12,); + }, ); }), + Container( + padding: const EdgeInsets.only(top: 12), + child: InkWell( + onTap: controller.tapAddCondition, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset( + _imagePaths.icAddNewFolder, + fit: BoxFit.fill, + ), + const SizedBox(width: 15,), + Text( + AppLocalizations.of(context).addCondition, + maxLines: 1, + style: const TextStyle( + fontWeight: FontWeight.w500, + fontSize: 17, + color: AppColor.primaryColor + ) + ) + ], + ), + ), + ), const Padding( padding: EdgeInsets.symmetric(vertical: 12), child: Divider( diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart index 8bcbba3b8a..e4bd55b4c3 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart @@ -22,7 +22,7 @@ class RuleFilterConditionWidget extends StatelessWidget { final FocusNode? conditionValueFocusNode; final OnChangeFilterInputAction? conditionValueOnChangeAction; final ImagePaths? imagePaths; - final Function()? onTapRemoveRuleFilterConditionCallback; + final Function()? tapRemoveRuleFilterConditionCallback; const RuleFilterConditionWidget({ super.key, @@ -35,7 +35,7 @@ class RuleFilterConditionWidget extends StatelessWidget { this.conditionValueFocusNode, this.conditionValueOnChangeAction, this.imagePaths, - this.onTapRemoveRuleFilterConditionCallback, + this.tapRemoveRuleFilterConditionCallback, }); @override @@ -56,7 +56,7 @@ class RuleFilterConditionWidget extends StatelessWidget { conditionValueEditingController, conditionValueFocusNode, conditionValueOnChangeAction, - onTapRemoveRuleFilterConditionCallback, + tapRemoveRuleFilterConditionCallback, imagePaths, ) ); @@ -74,7 +74,7 @@ Widget _buildRuleFilterCondition( TextEditingController? conditionValueEditingController, FocusNode? conditionValueFocusNode, OnChangeFilterInputAction? conditionValueOnChangeAction, - Function()? onTapRemoveRuleFilterConditionCallback, + Function()? tapRemoveRuleFilterConditionCallback, ImagePaths? imagePaths, ) { switch (ruleFilterConditionType) { @@ -111,7 +111,7 @@ Widget _buildRuleFilterCondition( case RuleFilterConditionType.tablet: case RuleFilterConditionType.desktop: return Row( - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: DropDownButtonWidget( @@ -145,7 +145,7 @@ Widget _buildRuleFilterCondition( editingController: conditionValueEditingController, ) ), - _buildRemoveRuleFilterConditionButton(onTapRemoveRuleFilterConditionCallback, imagePaths), + _buildRemoveRuleFilterConditionButton(tapRemoveRuleFilterConditionCallback, imagePaths), ], ); default: @@ -154,13 +154,14 @@ Widget _buildRuleFilterCondition( } Widget _buildRemoveRuleFilterConditionButton ( - Function()? onTapRemoveRuleFilterConditionCallback, + Function()? tapRemoveRuleFilterConditionCallback, ImagePaths? imagePath, ) { return Container( padding: const EdgeInsets.only(left: 12), + alignment: Alignment.center, child: InkWell( - onTap: onTapRemoveRuleFilterConditionCallback, + onTap: tapRemoveRuleFilterConditionCallback, child: CircleAvatar( backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, radius: 22, diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index b2c4fb9310..2175ee6773 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-08-30T16:14:12.029258", + "@@last_modified": "2023-08-31T14:39:56.761446", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -3211,5 +3211,11 @@ "placeholders": { "folder": {} } + }, + "addCondition": "Add condition", + "@addCondition": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index d3fe0532e0..0d81d81ea2 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -3310,4 +3310,11 @@ class AppLocalizations { args: [folder] ); } + + String get addCondition { + return Intl.message( + 'Add condition', + name: 'addCondition', + ); + } } \ No newline at end of file From 8416c3d46796e034414608304cbff209b30290e9 Mon Sep 17 00:00:00 2001 From: hieubt Date: Wed, 6 Sep 2023 10:40:52 +0700 Subject: [PATCH 4/7] tf-2083 make each rule condition can change value field separately --- .../model/rule_filter_condition_type.dart | 2 +- .../rules_filter_creator_controller.dart | 77 ++++++++++++++----- .../rules_filter_creator_view.dart | 31 ++++---- .../widgets/rule_filter_condition_widget.dart | 31 ++++---- ...rules_filter_input_decoration_builder.dart | 2 +- 5 files changed, 90 insertions(+), 53 deletions(-) diff --git a/lib/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart b/lib/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart index 5c85247b0b..a8984f187b 100644 --- a/lib/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart +++ b/lib/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart @@ -1,4 +1,4 @@ -enum RuleFilterConditionType { +enum RuleFilterConditionScreenType { mobile, tablet, desktop diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart index 0da27c21a0..7e7826e6bd 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart @@ -50,7 +50,7 @@ class RulesFilterCreatorController extends BaseMailboxController { GetAllRulesInteractor? _getAllRulesInteractor; final errorRuleName = Rxn(); - final errorRuleConditionValue = Rxn(); + final listErrorRuleConditionValue = RxList(); final errorRuleActionValue = Rxn(); final emailRuleFilterActionSelected = Rxn(); final mailboxSelected = Rxn(); @@ -58,12 +58,11 @@ class RulesFilterCreatorController extends BaseMailboxController { final listRuleCondition = RxList(); final TextEditingController inputRuleNameController = TextEditingController(); - final TextEditingController inputConditionValueController = TextEditingController(); + final List listInputConditionValueController = []; final FocusNode inputRuleNameFocusNode = FocusNode(); - final FocusNode inputRuleConditionFocusNode = FocusNode(); + final List listInputRuleConditionFocusNode = []; String? _newRuleName; - String? _newRuleConditionValue; RulesFilterCreatorArguments? arguments; AccountId? _accountId; @@ -112,9 +111,13 @@ class RulesFilterCreatorController extends BaseMailboxController { void onClose() { log('RulesFilterCreatorController::onClose():'); inputRuleNameFocusNode.dispose(); - inputRuleConditionFocusNode.dispose(); + for (var inputRuleConditionFocusNode in listInputRuleConditionFocusNode) { + inputRuleConditionFocusNode.dispose(); + } inputRuleNameController.dispose(); - inputConditionValueController.dispose(); + for (var inputConditionValueController in listInputConditionValueController) { + inputConditionValueController.dispose(); + } super.onClose(); } @@ -150,10 +153,19 @@ class RulesFilterCreatorController extends BaseMailboxController { value: '' ); listRuleCondition.add(newRuleCondition); + listInputConditionValueController.add(TextEditingController()); + listInputRuleConditionFocusNode.add(FocusNode()); + listErrorRuleConditionValue.add(''); emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; if (_emailAddress != null) { - _newRuleConditionValue = _emailAddress?.email; - _setValueInputField(inputConditionValueController, _newRuleConditionValue ?? ''); + RuleCondition firstRuleCondition = RuleCondition( + field: rule_condition.Field.from, + comparator: rule_condition.Comparator.contains, + value: _emailAddress!.email!, + ); + listRuleCondition[0] = firstRuleCondition; + listRuleCondition.refresh(); + _setValueInputField(listInputConditionValueController[0], listRuleCondition[0].value.obs.value); } if (_mailboxDestination != null) { mailboxSelected.value = _mailboxDestination; @@ -167,9 +179,11 @@ class RulesFilterCreatorController extends BaseMailboxController { value: _currentTMailRule!.condition.value ); listRuleCondition.add(currentRule); + listInputConditionValueController.add(TextEditingController()); + listInputRuleConditionFocusNode.add(FocusNode()); + listErrorRuleConditionValue.add(''); emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; - _newRuleConditionValue = _currentTMailRule!.condition.value; - _setValueInputField(inputConditionValueController, _newRuleConditionValue ?? ''); + _setValueInputField(listInputConditionValueController[0], listRuleCondition[0].value.obs.value); _newRuleName = _currentTMailRule!.name; _setValueInputField(inputRuleNameController, _newRuleName ?? ''); _getAllMailboxAction(); @@ -204,9 +218,21 @@ class RulesFilterCreatorController extends BaseMailboxController { errorRuleName.value = _getErrorStringByInputValue(context, _newRuleName); } - void updateConditionValue(BuildContext context, String? value) { - _newRuleConditionValue = value; - errorRuleConditionValue.value = _getErrorStringByInputValue(context, _newRuleConditionValue); + void updateConditionValue(BuildContext context, String? value, int ruleConditionIndex) { + RuleCondition newRuleCondition = RuleCondition( + field: listRuleCondition[ruleConditionIndex].field.obs.value, + comparator: listRuleCondition[ruleConditionIndex].comparator.obs.value, + value: value!, + ); + listRuleCondition[ruleConditionIndex] = newRuleCondition; + listRuleCondition.refresh(); + String? errorString = _getErrorStringByInputValue(context, listRuleCondition[ruleConditionIndex].value.obs.value); + if (listErrorRuleConditionValue.length > ruleConditionIndex) { + listErrorRuleConditionValue[ruleConditionIndex] = errorString ?? ''; + } else { + listErrorRuleConditionValue.add(errorString ?? ''); + } + listErrorRuleConditionValue.refresh(); } String? _getErrorStringByInputValue(BuildContext context, String? inputValue) { @@ -276,10 +302,17 @@ class RulesFilterCreatorController extends BaseMailboxController { return; } - final errorCondition = _getErrorStringByInputValue(context, _newRuleConditionValue); - if (errorCondition?.isNotEmpty == true) { - errorRuleConditionValue.value = errorCondition; - inputRuleConditionFocusNode.requestFocus(); + List errorCondition = []; + for (var ruleCondition in listRuleCondition) { + if (_getErrorStringByInputValue(context, ruleCondition.value) != null) { + errorCondition.add(_getErrorStringByInputValue(context, ruleCondition.value)!); + } + } + if (errorCondition.isNotEmpty) { + listErrorRuleConditionValue.value = errorCondition; + for (var inputRuleConditionFocusNode in listInputRuleConditionFocusNode) { + inputRuleConditionFocusNode.requestFocus(); + } return; } @@ -318,7 +351,7 @@ class RulesFilterCreatorController extends BaseMailboxController { condition: rule_condition.RuleCondition( field: ruleCondition.field, comparator: ruleCondition.comparator, - value: _newRuleConditionValue! + value: ruleCondition.value )); ruleFilterRequest = CreateNewEmailRuleFilterRequest(_listEmailRule ?? [], newTMailRule); } @@ -334,7 +367,7 @@ class RulesFilterCreatorController extends BaseMailboxController { condition: rule_condition.RuleCondition( field: listRuleCondition[0].field, comparator: listRuleCondition[0].comparator, - value: _newRuleConditionValue! + value: listRuleCondition[0].value )); ruleFilterRequest = EditEmailRuleFilterRequest(_listEmailRule?.withIds ?? [], newTMailRule); } @@ -353,9 +386,15 @@ class RulesFilterCreatorController extends BaseMailboxController { value: '' ); listRuleCondition.add(newRuleCondition); + listInputConditionValueController.add(TextEditingController()); + listInputRuleConditionFocusNode.add(FocusNode()); + listErrorRuleConditionValue.add(''); } void tapRemoveCondition(int ruleConditionIndex) { listRuleCondition.removeAt(ruleConditionIndex); + listInputConditionValueController.removeAt(ruleConditionIndex); + listInputRuleConditionFocusNode.removeAt(ruleConditionIndex); + listErrorRuleConditionValue.removeAt(ruleConditionIndex); } } \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart index 2284dee247..980a503a23 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart @@ -5,7 +5,6 @@ import 'package:get/get.dart'; import 'package:model/model.dart'; import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition; -import 'package:rule_filter/rule_filter/rule_condition.dart'; import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/rule_condition_extensions.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart'; @@ -153,18 +152,18 @@ class RuleFilterCreatorView extends GetWidget { itemCount: controller.listRuleCondition.length, itemBuilder: (context, index) { return RuleFilterConditionWidget( - ruleFilterConditionType: RuleFilterConditionType.desktop, + ruleFilterConditionScreenType: RuleFilterConditionScreenType.desktop, ruleCondition: controller.listRuleCondition[index], imagePaths: _imagePaths, - conditionValueErrorText: controller.errorRuleConditionValue.value, - conditionValueFocusNode: controller.inputRuleConditionFocusNode, - conditionValueEditingController: controller.inputConditionValueController, + conditionValueErrorText: controller.listErrorRuleConditionValue[index], + conditionValueFocusNode: controller.listInputRuleConditionFocusNode[index], + conditionValueEditingController: controller.listInputConditionValueController[index], tapRuleConditionFieldCallback: (value) => controller.selectRuleConditionField(value, index), tapRuleConditionComparatorCallback: (value) => controller.selectRuleConditionComparator(value, index), conditionValueOnChangeAction: (value) => - controller.updateConditionValue(context, value), + controller.updateConditionValue(context, value, index), tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), ); }, @@ -329,18 +328,18 @@ class RuleFilterCreatorView extends GetWidget { itemCount: controller.listRuleCondition.length, itemBuilder: (context, index) { return RuleFilterConditionWidget( - ruleFilterConditionType: RuleFilterConditionType.tablet, + ruleFilterConditionScreenType: RuleFilterConditionScreenType.tablet, ruleCondition: controller.listRuleCondition[index], imagePaths: _imagePaths, - conditionValueErrorText: controller.errorRuleConditionValue.value, - conditionValueFocusNode: controller.inputRuleConditionFocusNode, - conditionValueEditingController: controller.inputConditionValueController, + conditionValueErrorText: controller.listErrorRuleConditionValue.elementAtOrNull(index), + conditionValueFocusNode: controller.listInputRuleConditionFocusNode[index], + conditionValueEditingController: controller.listInputConditionValueController[index], tapRuleConditionFieldCallback: (value) => controller.selectRuleConditionField(value, index), tapRuleConditionComparatorCallback: (value) => controller.selectRuleConditionComparator(value, index), conditionValueOnChangeAction: (value) => - controller.updateConditionValue(context, value), + controller.updateConditionValue(context, value, index), tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), ); }, @@ -511,12 +510,12 @@ class RuleFilterCreatorView extends GetWidget { itemCount: controller.listRuleCondition.length, itemBuilder: (context, index) { return RuleFilterConditionWidget( - ruleFilterConditionType: RuleFilterConditionType.mobile, + ruleFilterConditionScreenType: RuleFilterConditionScreenType.mobile, ruleCondition: controller.listRuleCondition[index], imagePaths: _imagePaths, - conditionValueErrorText: controller.errorRuleConditionValue.value, - conditionValueFocusNode: controller.inputRuleConditionFocusNode, - conditionValueEditingController: controller.inputConditionValueController, + conditionValueErrorText: controller.listErrorRuleConditionValue.elementAtOrNull(index), + conditionValueFocusNode: controller.listInputRuleConditionFocusNode[index], + conditionValueEditingController: controller.listInputConditionValueController[index], tapRuleConditionFieldCallback: (value) => controller.openContextMenuAction( context, _bottomSheetRuleConditionFieldActionTiles( @@ -534,7 +533,7 @@ class RuleFilterCreatorView extends GetWidget { ) ), conditionValueOnChangeAction: (value) => - controller.updateConditionValue(context, value), + controller.updateConditionValue(context, value, index), tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), ); }, diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart index e4bd55b4c3..729bbeb28d 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart @@ -2,7 +2,6 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/keyboard_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:get/get.dart'; import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart'; import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition; @@ -13,8 +12,8 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:core/presentation/resources/image_paths.dart'; class RuleFilterConditionWidget extends StatelessWidget { - final RuleFilterConditionType? ruleFilterConditionType; - final RuleCondition? ruleCondition; + final RuleFilterConditionScreenType? ruleFilterConditionScreenType; + final RuleCondition ruleCondition; final Function(Field?)? tapRuleConditionFieldCallback; final Function(Comparator?)? tapRuleConditionComparatorCallback; final String? conditionValueErrorText; @@ -26,8 +25,8 @@ class RuleFilterConditionWidget extends StatelessWidget { const RuleFilterConditionWidget({ super.key, - this.ruleFilterConditionType, - this.ruleCondition, + this.ruleFilterConditionScreenType, + required this.ruleCondition, this.tapRuleConditionFieldCallback, this.tapRuleConditionComparatorCallback, this.conditionValueErrorText, @@ -48,7 +47,7 @@ class RuleFilterConditionWidget extends StatelessWidget { ), child: _buildRuleFilterCondition( context, - ruleFilterConditionType, + ruleFilterConditionScreenType, ruleCondition, tapRuleConditionFieldCallback, tapRuleConditionComparatorCallback, @@ -66,8 +65,8 @@ class RuleFilterConditionWidget extends StatelessWidget { Widget _buildRuleFilterCondition( BuildContext context, - RuleFilterConditionType? ruleFilterConditionType, - RuleCondition? ruleCondition, + RuleFilterConditionScreenType? ruleFilterConditionScreenType, + RuleCondition ruleCondition, Function(Field?)? tapRuleConditionFieldCallback, Function(Comparator?)? tapRuleConditionComparatorCallback, String? conditionValueErrorText, @@ -77,13 +76,13 @@ Widget _buildRuleFilterCondition( Function()? tapRemoveRuleFilterConditionCallback, ImagePaths? imagePaths, ) { - switch (ruleFilterConditionType) { - case RuleFilterConditionType.mobile: + switch (ruleFilterConditionScreenType) { + case RuleFilterConditionScreenType.mobile: return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ RuleFilterButtonField( - value: ruleCondition!.field.obs.value, + value: ruleCondition.field, tapActionCallback: (value) { KeyboardUtils.hideKeyboard(context); tapRuleConditionFieldCallback!(ruleCondition.field); @@ -92,7 +91,7 @@ Widget _buildRuleFilterCondition( Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: RuleFilterButtonField( - value: ruleCondition!.comparator.obs.value, + value: ruleCondition.comparator, tapActionCallback: (value) { KeyboardUtils.hideKeyboard(context); tapRuleConditionComparatorCallback!(ruleCondition.comparator); @@ -108,15 +107,15 @@ Widget _buildRuleFilterCondition( ), ], ); - case RuleFilterConditionType.tablet: - case RuleFilterConditionType.desktop: + case RuleFilterConditionScreenType.tablet: + case RuleFilterConditionScreenType.desktop: return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: DropDownButtonWidget( items: rule_condition.Field.values, - itemSelected: ruleCondition!.field.obs.value, + itemSelected: ruleCondition.field, dropdownMaxHeight: 250, onChanged: (newField) => { tapRuleConditionFieldCallback!(newField) @@ -129,7 +128,7 @@ Widget _buildRuleFilterCondition( padding: const EdgeInsets.symmetric(horizontal: 12), child: DropDownButtonWidget( items: rule_condition.Comparator.values, - itemSelected: ruleCondition!.comparator.obs.value, + itemSelected: ruleCondition.comparator, onChanged: (newComparator) => { tapRuleConditionComparatorCallback!(newComparator) }, diff --git a/lib/features/rules_filter_creator/presentation/widgets/rules_filter_input_decoration_builder.dart b/lib/features/rules_filter_creator/presentation/widgets/rules_filter_input_decoration_builder.dart index 8c757c4545..cbea00dce7 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rules_filter_input_decoration_builder.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rules_filter_input_decoration_builder.dart @@ -41,7 +41,7 @@ class RulesFilterInputDecorationBuilder extends InputDecorationBuilder { contentPadding: contentPadding ?? const EdgeInsets.symmetric( horizontal: 12, vertical: 12), - errorText: errorText, + errorText: errorText != '' ? errorText : null, errorStyle: errorTextStyle ?? const TextStyle( color: AppColor.colorInputBorderErrorVerifyName, fontSize: 13), From 324a895f1b35066a5e84caf06488663523b8e363 Mon Sep 17 00:00:00 2001 From: hieubt Date: Wed, 6 Sep 2023 18:55:56 +0700 Subject: [PATCH 5/7] tf-2083 add swipe to remove condition on mobile --- .../rules_filter_input_field_arguments.dart | 22 +++ .../rules_filter_creator_controller.dart | 128 ++++++++------- .../rules_filter_creator_view.dart | 150 +++++++----------- .../widgets/rule_filter_condition_widget.dart | 107 +++++++++---- pubspec.lock | 8 + pubspec.yaml | 2 + 6 files changed, 240 insertions(+), 177 deletions(-) create mode 100644 lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart diff --git a/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart b/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart new file mode 100644 index 0000000000..b9aa4674b7 --- /dev/null +++ b/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart @@ -0,0 +1,22 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; + +class RulesFilterInputFieldArguments with EquatableMixin { + final FocusNode inputRuleConditionValueFocusNode; + final String errorRuleConditionValue; + final TextEditingController inputRuleConditionValueController; + + RulesFilterInputFieldArguments({ + required this.inputRuleConditionValueFocusNode, + required this.errorRuleConditionValue, + required this.inputRuleConditionValueController, + }); + + @override + List get props => [ + inputRuleConditionValueFocusNode, + errorRuleConditionValue, + inputRuleConditionValueController, + ]; +} diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart index 7e7826e6bd..5ad7a84a79 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart @@ -41,6 +41,8 @@ import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/dialog_router.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +import 'model/rules_filter_input_field_arguments.dart'; + class RulesFilterCreatorController extends BaseMailboxController { final _appToast = Get.find(); @@ -50,7 +52,6 @@ class RulesFilterCreatorController extends BaseMailboxController { GetAllRulesInteractor? _getAllRulesInteractor; final errorRuleName = Rxn(); - final listErrorRuleConditionValue = RxList(); final errorRuleActionValue = Rxn(); final emailRuleFilterActionSelected = Rxn(); final mailboxSelected = Rxn(); @@ -58,9 +59,8 @@ class RulesFilterCreatorController extends BaseMailboxController { final listRuleCondition = RxList(); final TextEditingController inputRuleNameController = TextEditingController(); - final List listInputConditionValueController = []; final FocusNode inputRuleNameFocusNode = FocusNode(); - final List listInputRuleConditionFocusNode = []; + final listRuleConditionValueArguments = RxList(); String? _newRuleName; @@ -111,12 +111,10 @@ class RulesFilterCreatorController extends BaseMailboxController { void onClose() { log('RulesFilterCreatorController::onClose():'); inputRuleNameFocusNode.dispose(); - for (var inputRuleConditionFocusNode in listInputRuleConditionFocusNode) { - inputRuleConditionFocusNode.dispose(); - } inputRuleNameController.dispose(); - for (var inputConditionValueController in listInputConditionValueController) { - inputConditionValueController.dispose(); + for (var ruleConditionValueArguments in listRuleConditionValueArguments) { + ruleConditionValueArguments.inputRuleConditionValueFocusNode.dispose(); + ruleConditionValueArguments.inputRuleConditionValueController.dispose(); } super.onClose(); } @@ -153,9 +151,12 @@ class RulesFilterCreatorController extends BaseMailboxController { value: '' ); listRuleCondition.add(newRuleCondition); - listInputConditionValueController.add(TextEditingController()); - listInputRuleConditionFocusNode.add(FocusNode()); - listErrorRuleConditionValue.add(''); + RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( + inputRuleConditionValueFocusNode: FocusNode(), + errorRuleConditionValue: '', + inputRuleConditionValueController: TextEditingController(), + ); + listRuleConditionValueArguments.add(newRuleConditionValueArguments); emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; if (_emailAddress != null) { RuleCondition firstRuleCondition = RuleCondition( @@ -165,7 +166,10 @@ class RulesFilterCreatorController extends BaseMailboxController { ); listRuleCondition[0] = firstRuleCondition; listRuleCondition.refresh(); - _setValueInputField(listInputConditionValueController[0], listRuleCondition[0].value.obs.value); + _setValueInputField( + listRuleConditionValueArguments[0].inputRuleConditionValueController, + listRuleCondition[0].value + ); } if (_mailboxDestination != null) { mailboxSelected.value = _mailboxDestination; @@ -179,11 +183,17 @@ class RulesFilterCreatorController extends BaseMailboxController { value: _currentTMailRule!.condition.value ); listRuleCondition.add(currentRule); - listInputConditionValueController.add(TextEditingController()); - listInputRuleConditionFocusNode.add(FocusNode()); - listErrorRuleConditionValue.add(''); + RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( + inputRuleConditionValueFocusNode: FocusNode(), + errorRuleConditionValue: '', + inputRuleConditionValueController: TextEditingController(), + ); + listRuleConditionValueArguments.add(newRuleConditionValueArguments); emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; - _setValueInputField(listInputConditionValueController[0], listRuleCondition[0].value.obs.value); + _setValueInputField( + listRuleConditionValueArguments[0].inputRuleConditionValueController, + listRuleCondition[0].value + ); _newRuleName = _currentTMailRule!.name; _setValueInputField(inputRuleNameController, _newRuleName ?? ''); _getAllMailboxAction(); @@ -220,19 +230,24 @@ class RulesFilterCreatorController extends BaseMailboxController { void updateConditionValue(BuildContext context, String? value, int ruleConditionIndex) { RuleCondition newRuleCondition = RuleCondition( - field: listRuleCondition[ruleConditionIndex].field.obs.value, - comparator: listRuleCondition[ruleConditionIndex].comparator.obs.value, + field: listRuleCondition[ruleConditionIndex].field, + comparator: listRuleCondition[ruleConditionIndex].comparator, value: value!, ); listRuleCondition[ruleConditionIndex] = newRuleCondition; listRuleCondition.refresh(); - String? errorString = _getErrorStringByInputValue(context, listRuleCondition[ruleConditionIndex].value.obs.value); - if (listErrorRuleConditionValue.length > ruleConditionIndex) { - listErrorRuleConditionValue[ruleConditionIndex] = errorString ?? ''; + String? errorString = _getErrorStringByInputValue(context, listRuleCondition[ruleConditionIndex].value); + RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( + inputRuleConditionValueFocusNode: listRuleConditionValueArguments[ruleConditionIndex].inputRuleConditionValueFocusNode, + errorRuleConditionValue: errorString ?? '', + inputRuleConditionValueController: listRuleConditionValueArguments[ruleConditionIndex].inputRuleConditionValueController, + ); + if (listRuleConditionValueArguments.length > ruleConditionIndex) { + listRuleConditionValueArguments[ruleConditionIndex] = newRuleConditionValueArguments; } else { - listErrorRuleConditionValue.add(errorString ?? ''); + listRuleConditionValueArguments.add(newRuleConditionValueArguments); } - listErrorRuleConditionValue.refresh(); + listRuleConditionValueArguments.refresh(); } String? _getErrorStringByInputValue(BuildContext context, String? inputValue) { @@ -249,23 +264,27 @@ class RulesFilterCreatorController extends BaseMailboxController { } void selectRuleConditionField(rule_condition.Field? newField, int? ruleConditionIndex) { - RuleCondition newRuleCondition = RuleCondition( - field: newField!, - comparator: listRuleCondition[ruleConditionIndex!].comparator.obs.value, - value: listRuleCondition[ruleConditionIndex].value.obs.value, - ); - listRuleCondition[ruleConditionIndex] = newRuleCondition; - listRuleCondition.refresh(); + if (newField != null && ruleConditionIndex != null) { + RuleCondition newRuleCondition = RuleCondition( + field: newField, + comparator: listRuleCondition[ruleConditionIndex].comparator, + value: listRuleCondition[ruleConditionIndex].value, + ); + listRuleCondition[ruleConditionIndex] = newRuleCondition; + listRuleCondition.refresh(); + } } void selectRuleConditionComparator(rule_condition.Comparator? newComparator, int? ruleConditionIndex) { - RuleCondition newRuleCondition = RuleCondition( - field: listRuleCondition[ruleConditionIndex!].field.obs.value, - comparator: newComparator!, - value: listRuleCondition[ruleConditionIndex].value.obs.value, - ); - listRuleCondition[ruleConditionIndex] = newRuleCondition; - listRuleCondition.refresh(); + if (newComparator != null && ruleConditionIndex != null) { + RuleCondition newRuleCondition = RuleCondition( + field: listRuleCondition[ruleConditionIndex].field, + comparator: newComparator, + value: listRuleCondition[ruleConditionIndex].value, + ); + listRuleCondition[ruleConditionIndex] = newRuleCondition; + listRuleCondition.refresh(); + } } void selectEmailRuleFilterAction(EmailRuleFilterAction? newAction) { @@ -302,16 +321,19 @@ class RulesFilterCreatorController extends BaseMailboxController { return; } - List errorCondition = []; - for (var ruleCondition in listRuleCondition) { - if (_getErrorStringByInputValue(context, ruleCondition.value) != null) { - errorCondition.add(_getErrorStringByInputValue(context, ruleCondition.value)!); - } - } - if (errorCondition.isNotEmpty) { - listErrorRuleConditionValue.value = errorCondition; - for (var inputRuleConditionFocusNode in listInputRuleConditionFocusNode) { - inputRuleConditionFocusNode.requestFocus(); + if (listRuleCondition.isNotEmpty) { + for (var ruleCondition in listRuleCondition) { + String? errorString = _getErrorStringByInputValue(context, ruleCondition.value); + if (errorString != null) { + int ruleConditionIndex = listRuleCondition.indexOf(ruleCondition); + RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( + inputRuleConditionValueFocusNode: listRuleConditionValueArguments[ruleConditionIndex].inputRuleConditionValueFocusNode, + errorRuleConditionValue: errorString, + inputRuleConditionValueController: listRuleConditionValueArguments[ruleConditionIndex].inputRuleConditionValueController, + ); + listRuleConditionValueArguments[ruleConditionIndex] = newRuleConditionValueArguments; + listRuleConditionValueArguments[listRuleCondition.indexOf(ruleCondition)].inputRuleConditionValueFocusNode.requestFocus(); + } } return; } @@ -386,15 +408,15 @@ class RulesFilterCreatorController extends BaseMailboxController { value: '' ); listRuleCondition.add(newRuleCondition); - listInputConditionValueController.add(TextEditingController()); - listInputRuleConditionFocusNode.add(FocusNode()); - listErrorRuleConditionValue.add(''); + listRuleConditionValueArguments.add(RulesFilterInputFieldArguments( + inputRuleConditionValueFocusNode: FocusNode(), + errorRuleConditionValue: '', + inputRuleConditionValueController: TextEditingController(), + )); } void tapRemoveCondition(int ruleConditionIndex) { listRuleCondition.removeAt(ruleConditionIndex); - listInputConditionValueController.removeAt(ruleConditionIndex); - listInputRuleConditionFocusNode.removeAt(ruleConditionIndex); - listErrorRuleConditionValue.removeAt(ruleConditionIndex); + listRuleConditionValueArguments.removeAt(ruleConditionIndex); } } \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart index 980a503a23..ff370cebb9 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart @@ -146,32 +146,7 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - Obx(() { - return ListView.separated( - shrinkWrap: true, - itemCount: controller.listRuleCondition.length, - itemBuilder: (context, index) { - return RuleFilterConditionWidget( - ruleFilterConditionScreenType: RuleFilterConditionScreenType.desktop, - ruleCondition: controller.listRuleCondition[index], - imagePaths: _imagePaths, - conditionValueErrorText: controller.listErrorRuleConditionValue[index], - conditionValueFocusNode: controller.listInputRuleConditionFocusNode[index], - conditionValueEditingController: controller.listInputConditionValueController[index], - tapRuleConditionFieldCallback: (value) => - controller.selectRuleConditionField(value, index), - tapRuleConditionComparatorCallback: (value) => - controller.selectRuleConditionComparator(value, index), - conditionValueOnChangeAction: (value) => - controller.updateConditionValue(context, value, index), - tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), - ); - }, - separatorBuilder: (context, index) { - return const SizedBox(height: 12,); - }, - ); - }), + _buildListRuleFilterConditionList(context, RuleFilterConditionScreenType.desktop), Container( padding: const EdgeInsets.only(top: 8), child: InkWell( @@ -322,32 +297,7 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - Obx(() { - return ListView.separated( - shrinkWrap: true, - itemCount: controller.listRuleCondition.length, - itemBuilder: (context, index) { - return RuleFilterConditionWidget( - ruleFilterConditionScreenType: RuleFilterConditionScreenType.tablet, - ruleCondition: controller.listRuleCondition[index], - imagePaths: _imagePaths, - conditionValueErrorText: controller.listErrorRuleConditionValue.elementAtOrNull(index), - conditionValueFocusNode: controller.listInputRuleConditionFocusNode[index], - conditionValueEditingController: controller.listInputConditionValueController[index], - tapRuleConditionFieldCallback: (value) => - controller.selectRuleConditionField(value, index), - tapRuleConditionComparatorCallback: (value) => - controller.selectRuleConditionComparator(value, index), - conditionValueOnChangeAction: (value) => - controller.updateConditionValue(context, value, index), - tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), - ); - }, - separatorBuilder: (context, index) { - return const SizedBox(height: 12,); - }, - ); - }), + _buildListRuleFilterConditionList(context, RuleFilterConditionScreenType.tablet), Container( padding: const EdgeInsets.only(top: 8), child: InkWell( @@ -504,44 +454,7 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - Obx(() { - return ListView.separated( - shrinkWrap: true, - itemCount: controller.listRuleCondition.length, - itemBuilder: (context, index) { - return RuleFilterConditionWidget( - ruleFilterConditionScreenType: RuleFilterConditionScreenType.mobile, - ruleCondition: controller.listRuleCondition[index], - imagePaths: _imagePaths, - conditionValueErrorText: controller.listErrorRuleConditionValue.elementAtOrNull(index), - conditionValueFocusNode: controller.listInputRuleConditionFocusNode[index], - conditionValueEditingController: controller.listInputConditionValueController[index], - tapRuleConditionFieldCallback: (value) => controller.openContextMenuAction( - context, - _bottomSheetRuleConditionFieldActionTiles( - context, - controller.listRuleCondition[index].field.obs.value, - index, - ) - ), - tapRuleConditionComparatorCallback: (value) => controller.openContextMenuAction( - context, - _bottomSheetRuleConditionComparatorActionTiles( - context, - controller.listRuleCondition[index].comparator.obs.value, - index, - ) - ), - conditionValueOnChangeAction: (value) => - controller.updateConditionValue(context, value, index), - tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), - ); - }, - separatorBuilder: (context, index) { - return const SizedBox(height: 12,); - }, - ); - }), + _buildListRuleFilterConditionList(context, RuleFilterConditionScreenType.mobile), Container( padding: const EdgeInsets.only(top: 12), child: InkWell( @@ -668,6 +581,63 @@ class RuleFilterCreatorView extends GetWidget { ); } + Widget _buildListRuleFilterConditionList( + BuildContext context, + RuleFilterConditionScreenType ruleFilterConditionScreenType + ) { + return Obx(() { + return ListView.separated( + shrinkWrap: true, + itemCount: controller.listRuleCondition.length, + itemBuilder: (context, index) { + return RuleFilterConditionWidget( + key: ValueKey(controller.listRuleConditionValueArguments[index].inputRuleConditionValueFocusNode), + ruleFilterConditionScreenType: ruleFilterConditionScreenType, + ruleCondition: controller.listRuleCondition[index], + imagePaths: _imagePaths, + conditionValueErrorText: controller.listRuleConditionValueArguments[index].errorRuleConditionValue, + conditionValueFocusNode: controller.listRuleConditionValueArguments[index].inputRuleConditionValueFocusNode, + conditionValueEditingController: controller.listRuleConditionValueArguments[index].inputRuleConditionValueController, + tapRuleConditionFieldCallback: (value) => { + if (ruleFilterConditionScreenType == RuleFilterConditionScreenType.mobile) { + controller.openContextMenuAction( + context, + _bottomSheetRuleConditionFieldActionTiles( + context, + controller.listRuleCondition[index].field, + index, + ) + ), + } else { + controller.selectRuleConditionField(value, index) + } + }, + tapRuleConditionComparatorCallback: (value) => { + if (ruleFilterConditionScreenType == RuleFilterConditionScreenType.mobile) { + controller.openContextMenuAction( + context, + _bottomSheetRuleConditionComparatorActionTiles( + context, + controller.listRuleCondition[index].comparator, + index, + ) + ), + } else { + controller.selectRuleConditionComparator(value, index), + } + }, + conditionValueOnChangeAction: (value) => + controller.updateConditionValue(context, value, index), + tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), + ); + }, + separatorBuilder: (context, index) { + return const SizedBox(height: 12,); + }, + ); + }); + } + List _bottomSheetRuleConditionFieldActionTiles( BuildContext context, rule_condition.Field? fieldSelected, diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart index 729bbeb28d..f980ff5b93 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart @@ -1,6 +1,7 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/keyboard_utils.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart'; @@ -39,25 +40,63 @@ class RuleFilterConditionWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: AppColor.colorBackgroundFieldConditionRulesFilter, - borderRadius: BorderRadius.circular(12), + return Slidable( + enabled: ruleFilterConditionScreenType == RuleFilterConditionScreenType.mobile ? true : false, + endActionPane: ActionPane( + extentRatio: 0.1, + motion: const BehindMotion(), + children: [ + CustomSlidableAction( + padding: const EdgeInsets.only(right: 12), + borderRadius: const BorderRadius.only(topRight: Radius.circular(12), bottomRight: Radius.circular(12)), + onPressed: (_) => tapRemoveRuleFilterConditionCallback!(), + backgroundColor: AppColor.colorBackgroundFieldConditionRulesFilter, + child: CircleAvatar( + backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, + radius: 110, + child: SvgPicture.asset( + imagePaths!.icMinimize, + fit: BoxFit.fill, + colorFilter: AppColor.colorDeletePermanentlyButton.asFilter(), + ), + ) + ) + ] ), - child: _buildRuleFilterCondition( - context, - ruleFilterConditionScreenType, - ruleCondition, - tapRuleConditionFieldCallback, - tapRuleConditionComparatorCallback, - conditionValueErrorText, - conditionValueEditingController, - conditionValueFocusNode, - conditionValueOnChangeAction, - tapRemoveRuleFilterConditionCallback, - imagePaths, - ) + child: Builder(builder: (context) { + SlidableController? slideController = Slidable.of(context); + return ValueListenableBuilder( + valueListenable: slideController?.direction ?? ValueNotifier(0), + builder: (context, value, _) { + var borderRadius = value != -1 ? + BorderRadius.circular(12) : + const BorderRadius.only( + bottomLeft: Radius.circular(12), + topLeft: Radius.circular(12) + ); + return Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: AppColor.colorBackgroundFieldConditionRulesFilter, + borderRadius: borderRadius, + ), + child: _buildRuleFilterCondition( + context, + ruleFilterConditionScreenType, + ruleCondition, + tapRuleConditionFieldCallback, + tapRuleConditionComparatorCallback, + conditionValueErrorText, + conditionValueEditingController, + conditionValueFocusNode, + conditionValueOnChangeAction, + tapRemoveRuleFilterConditionCallback, + imagePaths, + ) + ); + } + ); + }) ); } @@ -144,7 +183,11 @@ Widget _buildRuleFilterCondition( editingController: conditionValueEditingController, ) ), - _buildRemoveRuleFilterConditionButton(tapRemoveRuleFilterConditionCallback, imagePaths), + Container( + padding: const EdgeInsets.only(left: 12), + alignment: Alignment.center, + child: _buildRemoveRuleFilterConditionButton(tapRemoveRuleFilterConditionCallback, imagePaths) + ), ], ); default: @@ -156,20 +199,16 @@ Widget _buildRemoveRuleFilterConditionButton ( Function()? tapRemoveRuleFilterConditionCallback, ImagePaths? imagePath, ) { - return Container( - padding: const EdgeInsets.only(left: 12), - alignment: Alignment.center, - child: InkWell( - onTap: tapRemoveRuleFilterConditionCallback, - child: CircleAvatar( - backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, - radius: 22, - child: SvgPicture.asset( - imagePath!.icMinimize, - fit: BoxFit.fill, - colorFilter: AppColor.colorDeletePermanentlyButton.asFilter(), - ), - ) - ), + return InkWell( + onTap: tapRemoveRuleFilterConditionCallback, + child: CircleAvatar( + backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, + radius: 22, + child: SvgPicture.asset( + imagePath!.icMinimize, + fit: BoxFit.fill, + colorFilter: AppColor.colorDeletePermanentlyButton.asFilter(), + ), + ) ); } \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 166983d376..0e85d09633 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -788,6 +788,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.3" + flutter_slidable: + dependency: "direct main" + description: + name: flutter_slidable + sha256: cc4231579e3eae41ae166660df717f4bad1359c87f4a4322ad8ba1befeb3d2be + url: "https://pub.dev" + source: hosted + version: "3.0.0" flutter_staggered_grid_view: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index d0ead2e9dd..9eb234041d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -204,6 +204,8 @@ dependencies: super_tag_editor: 0.2.0 + flutter_slidable: 3.0.0 + dev_dependencies: flutter_test: sdk: flutter From 9246bf985ae80fe4fb6a86a9fe52ae42968fdc99 Mon Sep 17 00:00:00 2001 From: hieubt Date: Fri, 8 Sep 2023 15:18:31 +0700 Subject: [PATCH 6/7] TF-2083 Change input field arguments --- .../rules_filter_input_field_arguments.dart | 18 ++++---- .../rules_filter_creator_controller.dart | 42 +++++++++---------- .../rules_filter_creator_view.dart | 8 ++-- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart b/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart index b9aa4674b7..8d383f9cf5 100644 --- a/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart +++ b/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart @@ -3,20 +3,20 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; class RulesFilterInputFieldArguments with EquatableMixin { - final FocusNode inputRuleConditionValueFocusNode; - final String errorRuleConditionValue; - final TextEditingController inputRuleConditionValueController; + final FocusNode focusNode; + final String errorText; + final TextEditingController controller; RulesFilterInputFieldArguments({ - required this.inputRuleConditionValueFocusNode, - required this.errorRuleConditionValue, - required this.inputRuleConditionValueController, + required this.focusNode, + required this.errorText, + required this.controller, }); @override List get props => [ - inputRuleConditionValueFocusNode, - errorRuleConditionValue, - inputRuleConditionValueController, + focusNode, + errorText, + controller, ]; } diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart index 5ad7a84a79..5f70f24817 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_controller.dart @@ -40,8 +40,8 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/dialog_router.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart'; -import 'model/rules_filter_input_field_arguments.dart'; class RulesFilterCreatorController extends BaseMailboxController { @@ -113,8 +113,8 @@ class RulesFilterCreatorController extends BaseMailboxController { inputRuleNameFocusNode.dispose(); inputRuleNameController.dispose(); for (var ruleConditionValueArguments in listRuleConditionValueArguments) { - ruleConditionValueArguments.inputRuleConditionValueFocusNode.dispose(); - ruleConditionValueArguments.inputRuleConditionValueController.dispose(); + ruleConditionValueArguments.focusNode.dispose(); + ruleConditionValueArguments.controller.dispose(); } super.onClose(); } @@ -152,9 +152,9 @@ class RulesFilterCreatorController extends BaseMailboxController { ); listRuleCondition.add(newRuleCondition); RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( - inputRuleConditionValueFocusNode: FocusNode(), - errorRuleConditionValue: '', - inputRuleConditionValueController: TextEditingController(), + focusNode: FocusNode(), + errorText: '', + controller: TextEditingController(), ); listRuleConditionValueArguments.add(newRuleConditionValueArguments); emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; @@ -167,7 +167,7 @@ class RulesFilterCreatorController extends BaseMailboxController { listRuleCondition[0] = firstRuleCondition; listRuleCondition.refresh(); _setValueInputField( - listRuleConditionValueArguments[0].inputRuleConditionValueController, + listRuleConditionValueArguments[0].controller, listRuleCondition[0].value ); } @@ -184,14 +184,14 @@ class RulesFilterCreatorController extends BaseMailboxController { ); listRuleCondition.add(currentRule); RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( - inputRuleConditionValueFocusNode: FocusNode(), - errorRuleConditionValue: '', - inputRuleConditionValueController: TextEditingController(), + focusNode: FocusNode(), + errorText: '', + controller: TextEditingController(), ); listRuleConditionValueArguments.add(newRuleConditionValueArguments); emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; _setValueInputField( - listRuleConditionValueArguments[0].inputRuleConditionValueController, + listRuleConditionValueArguments[0].controller, listRuleCondition[0].value ); _newRuleName = _currentTMailRule!.name; @@ -238,9 +238,9 @@ class RulesFilterCreatorController extends BaseMailboxController { listRuleCondition.refresh(); String? errorString = _getErrorStringByInputValue(context, listRuleCondition[ruleConditionIndex].value); RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( - inputRuleConditionValueFocusNode: listRuleConditionValueArguments[ruleConditionIndex].inputRuleConditionValueFocusNode, - errorRuleConditionValue: errorString ?? '', - inputRuleConditionValueController: listRuleConditionValueArguments[ruleConditionIndex].inputRuleConditionValueController, + focusNode: listRuleConditionValueArguments[ruleConditionIndex].focusNode, + errorText: errorString ?? '', + controller: listRuleConditionValueArguments[ruleConditionIndex].controller, ); if (listRuleConditionValueArguments.length > ruleConditionIndex) { listRuleConditionValueArguments[ruleConditionIndex] = newRuleConditionValueArguments; @@ -327,12 +327,12 @@ class RulesFilterCreatorController extends BaseMailboxController { if (errorString != null) { int ruleConditionIndex = listRuleCondition.indexOf(ruleCondition); RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( - inputRuleConditionValueFocusNode: listRuleConditionValueArguments[ruleConditionIndex].inputRuleConditionValueFocusNode, - errorRuleConditionValue: errorString, - inputRuleConditionValueController: listRuleConditionValueArguments[ruleConditionIndex].inputRuleConditionValueController, + focusNode: listRuleConditionValueArguments[ruleConditionIndex].focusNode, + errorText: errorString, + controller: listRuleConditionValueArguments[ruleConditionIndex].controller, ); listRuleConditionValueArguments[ruleConditionIndex] = newRuleConditionValueArguments; - listRuleConditionValueArguments[listRuleCondition.indexOf(ruleCondition)].inputRuleConditionValueFocusNode.requestFocus(); + listRuleConditionValueArguments[listRuleCondition.indexOf(ruleCondition)].focusNode.requestFocus(); } } return; @@ -409,9 +409,9 @@ class RulesFilterCreatorController extends BaseMailboxController { ); listRuleCondition.add(newRuleCondition); listRuleConditionValueArguments.add(RulesFilterInputFieldArguments( - inputRuleConditionValueFocusNode: FocusNode(), - errorRuleConditionValue: '', - inputRuleConditionValueController: TextEditingController(), + focusNode: FocusNode(), + errorText: '', + controller: TextEditingController(), )); } diff --git a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart index ff370cebb9..dc33991aa8 100644 --- a/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart +++ b/lib/features/rules_filter_creator/presentation/rules_filter_creator_view.dart @@ -591,13 +591,13 @@ class RuleFilterCreatorView extends GetWidget { itemCount: controller.listRuleCondition.length, itemBuilder: (context, index) { return RuleFilterConditionWidget( - key: ValueKey(controller.listRuleConditionValueArguments[index].inputRuleConditionValueFocusNode), + key: ValueKey(controller.listRuleConditionValueArguments[index].focusNode), ruleFilterConditionScreenType: ruleFilterConditionScreenType, ruleCondition: controller.listRuleCondition[index], imagePaths: _imagePaths, - conditionValueErrorText: controller.listRuleConditionValueArguments[index].errorRuleConditionValue, - conditionValueFocusNode: controller.listRuleConditionValueArguments[index].inputRuleConditionValueFocusNode, - conditionValueEditingController: controller.listRuleConditionValueArguments[index].inputRuleConditionValueController, + conditionValueErrorText: controller.listRuleConditionValueArguments[index].errorText, + conditionValueFocusNode: controller.listRuleConditionValueArguments[index].focusNode, + conditionValueEditingController: controller.listRuleConditionValueArguments[index].controller, tapRuleConditionFieldCallback: (value) => { if (ruleFilterConditionScreenType == RuleFilterConditionScreenType.mobile) { controller.openContextMenuAction( From 48c8a993549ee8d01ffbbb076c68e7aa6e2e81ae Mon Sep 17 00:00:00 2001 From: hieubt Date: Mon, 11 Sep 2023 11:12:54 +0700 Subject: [PATCH 7/7] TF-2083 Add condition row widget and condition remove button widget --- .../rules_filter_input_field_arguments.dart | 1 - ...ilter_condition_remove_button_builder.dart | 31 ++++ .../rule_filter_condition_row_builder.dart | 123 +++++++++++++++ .../widgets/rule_filter_condition_widget.dart | 140 ++---------------- 4 files changed, 166 insertions(+), 129 deletions(-) create mode 100644 lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_remove_button_builder.dart create mode 100644 lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_row_builder.dart diff --git a/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart b/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart index 8d383f9cf5..eefbb82d37 100644 --- a/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart +++ b/lib/features/rules_filter_creator/presentation/model/rules_filter_input_field_arguments.dart @@ -1,4 +1,3 @@ -// ignore_for_file: public_member_api_docs, sort_constructors_first import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_remove_button_builder.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_remove_button_builder.dart new file mode 100644 index 0000000000..24220254b2 --- /dev/null +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_remove_button_builder.dart @@ -0,0 +1,31 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class RuleFilterConditionRemoveButton extends StatelessWidget { + final Function()? tapRemoveRuleFilterConditionCallback; + final ImagePaths? imagePath; + + const RuleFilterConditionRemoveButton({ + Key? key, + this.tapRemoveRuleFilterConditionCallback, + this.imagePath, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: tapRemoveRuleFilterConditionCallback, + child: CircleAvatar( + backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, + radius: 22, + child: SvgPicture.asset( + imagePath!.icMinimize, + fit: BoxFit.fill, + colorFilter: AppColor.colorDeletePermanentlyButton.asFilter(), + ), + ) + ); + } +} \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_row_builder.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_row_builder.dart new file mode 100644 index 0000000000..a26cd3811a --- /dev/null +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_row_builder.dart @@ -0,0 +1,123 @@ +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/utils/keyboard_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:rule_filter/rule_filter/rule_condition.dart'; +import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition; +import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_condition_remove_button_builder.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class RuleFilterConditionRow extends StatelessWidget { + final RuleFilterConditionScreenType? ruleFilterConditionScreenType; + final RuleCondition ruleCondition; + final Function(Field?)? tapRuleConditionFieldCallback; + final Function(Comparator?)? tapRuleConditionComparatorCallback; + final String? conditionValueErrorText; + final TextEditingController? conditionValueEditingController; + final FocusNode? conditionValueFocusNode; + final OnChangeFilterInputAction? conditionValueOnChangeAction; + final Function()? tapRemoveRuleFilterConditionCallback; + final ImagePaths? imagePaths; + + const RuleFilterConditionRow({ + Key? key, + required this.ruleFilterConditionScreenType, + required this.ruleCondition, + this.tapRuleConditionFieldCallback, + this.tapRuleConditionComparatorCallback, + this.conditionValueErrorText, + this.conditionValueEditingController, + this.conditionValueFocusNode, + this.conditionValueOnChangeAction, + this.tapRemoveRuleFilterConditionCallback, + this.imagePaths, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + switch (ruleFilterConditionScreenType) { + case RuleFilterConditionScreenType.mobile: + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RuleFilterButtonField( + value: ruleCondition.field, + tapActionCallback: (value) { + KeyboardUtils.hideKeyboard(context); + tapRuleConditionFieldCallback!(ruleCondition.field); + }, + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 12), + child: RuleFilterButtonField( + value: ruleCondition.comparator, + tapActionCallback: (value) { + KeyboardUtils.hideKeyboard(context); + tapRuleConditionComparatorCallback!(ruleCondition.comparator); + }, + ) + ), + RulesFilterInputField( + hintText: AppLocalizations.of(context).conditionValueHintTextInput, + errorText: conditionValueErrorText, + focusNode: conditionValueFocusNode, + onChangeAction: conditionValueOnChangeAction, + editingController: conditionValueEditingController, + ), + ], + ); + case RuleFilterConditionScreenType.tablet: + case RuleFilterConditionScreenType.desktop: + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: DropDownButtonWidget( + items: rule_condition.Field.values, + itemSelected: ruleCondition.field, + dropdownMaxHeight: 250, + onChanged: (newField) => { + tapRuleConditionFieldCallback!(newField) + }, + supportSelectionIcon: true, + ) + ), + Container( + width: 220, + padding: const EdgeInsets.symmetric(horizontal: 12), + child: DropDownButtonWidget( + items: rule_condition.Comparator.values, + itemSelected: ruleCondition.comparator, + onChanged: (newComparator) => { + tapRuleConditionComparatorCallback!(newComparator) + }, + supportSelectionIcon: true, + ) + ), + Expanded( + child: RulesFilterInputField( + hintText: AppLocalizations.of(context).conditionValueHintTextInput, + errorText: conditionValueErrorText, + focusNode: conditionValueFocusNode, + onChangeAction: conditionValueOnChangeAction, + editingController: conditionValueEditingController, + ) + ), + Container( + padding: const EdgeInsets.only(left: 12), + alignment: Alignment.center, + child: RuleFilterConditionRemoveButton( + tapRemoveRuleFilterConditionCallback: tapRemoveRuleFilterConditionCallback, + imagePath: imagePaths, + ) + ), + ], + ); + default: + return const SizedBox.shrink(); + } + } +} diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart index f980ff5b93..460f929f24 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_widget.dart @@ -1,15 +1,11 @@ import 'package:core/presentation/extensions/color_extension.dart'; -import 'package:core/presentation/utils/keyboard_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:tmail_ui_user/features/base/widget/drop_down_button_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rule_filter_condition_type.dart'; -import 'package:rule_filter/rule_filter/rule_condition.dart' as rule_condition; import 'package:rule_filter/rule_filter/rule_condition.dart'; -import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_condition_row_builder.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart'; -import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:core/presentation/resources/image_paths.dart'; class RuleFilterConditionWidget extends StatelessWidget { @@ -80,18 +76,17 @@ class RuleFilterConditionWidget extends StatelessWidget { color: AppColor.colorBackgroundFieldConditionRulesFilter, borderRadius: borderRadius, ), - child: _buildRuleFilterCondition( - context, - ruleFilterConditionScreenType, - ruleCondition, - tapRuleConditionFieldCallback, - tapRuleConditionComparatorCallback, - conditionValueErrorText, - conditionValueEditingController, - conditionValueFocusNode, - conditionValueOnChangeAction, - tapRemoveRuleFilterConditionCallback, - imagePaths, + child: RuleFilterConditionRow( + ruleFilterConditionScreenType: ruleFilterConditionScreenType, + ruleCondition: ruleCondition, + tapRuleConditionFieldCallback: tapRuleConditionFieldCallback, + tapRuleConditionComparatorCallback: tapRuleConditionComparatorCallback, + conditionValueErrorText: conditionValueErrorText, + conditionValueEditingController: conditionValueEditingController, + conditionValueFocusNode: conditionValueFocusNode, + conditionValueOnChangeAction: conditionValueOnChangeAction, + tapRemoveRuleFilterConditionCallback: tapRemoveRuleFilterConditionCallback, + imagePaths: imagePaths, ) ); } @@ -100,115 +95,4 @@ class RuleFilterConditionWidget extends StatelessWidget { ); } -} - -Widget _buildRuleFilterCondition( - BuildContext context, - RuleFilterConditionScreenType? ruleFilterConditionScreenType, - RuleCondition ruleCondition, - Function(Field?)? tapRuleConditionFieldCallback, - Function(Comparator?)? tapRuleConditionComparatorCallback, - String? conditionValueErrorText, - TextEditingController? conditionValueEditingController, - FocusNode? conditionValueFocusNode, - OnChangeFilterInputAction? conditionValueOnChangeAction, - Function()? tapRemoveRuleFilterConditionCallback, - ImagePaths? imagePaths, -) { - switch (ruleFilterConditionScreenType) { - case RuleFilterConditionScreenType.mobile: - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - RuleFilterButtonField( - value: ruleCondition.field, - tapActionCallback: (value) { - KeyboardUtils.hideKeyboard(context); - tapRuleConditionFieldCallback!(ruleCondition.field); - }, - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: RuleFilterButtonField( - value: ruleCondition.comparator, - tapActionCallback: (value) { - KeyboardUtils.hideKeyboard(context); - tapRuleConditionComparatorCallback!(ruleCondition.comparator); - }, - ) - ), - RulesFilterInputField( - hintText: AppLocalizations.of(context).conditionValueHintTextInput, - errorText: conditionValueErrorText, - focusNode: conditionValueFocusNode, - onChangeAction: conditionValueOnChangeAction, - editingController: conditionValueEditingController, - ), - ], - ); - case RuleFilterConditionScreenType.tablet: - case RuleFilterConditionScreenType.desktop: - return Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: DropDownButtonWidget( - items: rule_condition.Field.values, - itemSelected: ruleCondition.field, - dropdownMaxHeight: 250, - onChanged: (newField) => { - tapRuleConditionFieldCallback!(newField) - }, - supportSelectionIcon: true, - ) - ), - Container( - width: 220, - padding: const EdgeInsets.symmetric(horizontal: 12), - child: DropDownButtonWidget( - items: rule_condition.Comparator.values, - itemSelected: ruleCondition.comparator, - onChanged: (newComparator) => { - tapRuleConditionComparatorCallback!(newComparator) - }, - supportSelectionIcon: true, - ) - ), - Expanded( - child: RulesFilterInputField( - hintText: AppLocalizations.of(context).conditionValueHintTextInput, - errorText: conditionValueErrorText, - focusNode: conditionValueFocusNode, - onChangeAction: conditionValueOnChangeAction, - editingController: conditionValueEditingController, - ) - ), - Container( - padding: const EdgeInsets.only(left: 12), - alignment: Alignment.center, - child: _buildRemoveRuleFilterConditionButton(tapRemoveRuleFilterConditionCallback, imagePaths) - ), - ], - ); - default: - return Container(); - } -} - -Widget _buildRemoveRuleFilterConditionButton ( - Function()? tapRemoveRuleFilterConditionCallback, - ImagePaths? imagePath, -) { - return InkWell( - onTap: tapRemoveRuleFilterConditionCallback, - child: CircleAvatar( - backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, - radius: 22, - child: SvgPicture.asset( - imagePath!.icMinimize, - fit: BoxFit.fill, - colorFilter: AppColor.colorDeletePermanentlyButton.asFilter(), - ), - ) - ); } \ No newline at end of file