From 8c3c7b1febe2ed92ab4e833ffb00e1e1ca5f6e11 Mon Sep 17 00:00:00 2001 From: dab246 Date: Mon, 8 Sep 2025 14:30:17 +0700 Subject: [PATCH] TF-4004 Apply new design for create rule view on web --- .../default_input_field_widget.dart | 28 +- .../base/widget/drop_down_button_widget.dart | 10 +- .../widget/label_input_field_builder.dart | 19 +- .../presentation_mailbox_extension.dart | 24 +- .../model/creator_action_type.dart | 6 +- .../rules_filter_input_field_arguments.dart | 6 +- .../rules_filter_creator_controller.dart | 5 +- .../rules_filter_creator_view.dart | 716 ++++++++---------- .../styles/rule_filter_action_styles.dart | 19 +- .../styles/rule_filter_title_styles.dart | 15 - .../rule_filter_action_detailed_builder.dart | 8 +- .../widgets/rule_filter_action_list.dart | 80 -- .../rule_filter_action_row_builder.dart | 90 ++- ...rule_filter_action_row_mobile_builder.dart | 11 +- .../widgets/rule_filter_action_widget.dart | 56 +- .../widgets/rule_filter_button_field.dart | 5 +- ...ilter_condition_remove_button_builder.dart | 24 - .../rule_filter_condition_row_builder.dart | 114 +-- .../widgets/rule_filter_condition_widget.dart | 81 +- .../rule_filter_delete_button_widget.dart | 31 + .../rule_filter_list_action_widget.dart | 58 ++ .../widgets/rule_filter_title_builder.dart | 86 ++- lib/l10n/intl_messages.arb | 42 + lib/main/localizations/app_localizations.dart | 49 ++ 24 files changed, 819 insertions(+), 764 deletions(-) delete mode 100644 lib/features/rules_filter_creator/presentation/styles/rule_filter_title_styles.dart delete mode 100644 lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_list.dart delete 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_delete_button_widget.dart create mode 100644 lib/features/rules_filter_creator/presentation/widgets/rule_filter_list_action_widget.dart diff --git a/lib/features/base/widget/default_field/default_input_field_widget.dart b/lib/features/base/widget/default_field/default_input_field_widget.dart index d2027adeb..c68ce28bf 100644 --- a/lib/features/base/widget/default_field/default_input_field_widget.dart +++ b/lib/features/base/widget/default_field/default_input_field_widget.dart @@ -9,6 +9,8 @@ typedef OnTextChange = void Function(String text); class DefaultInputFieldWidget extends StatelessWidget { final TextEditingController textEditingController; final String? hintText; + final String? errorText; + final Color? inputColor; final FocusNode? focusNode; final OnTextChange? onTextChange; final OnTextSubmitted? onTextSubmitted; @@ -17,7 +19,9 @@ class DefaultInputFieldWidget extends StatelessWidget { super.key, required this.textEditingController, this.hintText, + this.errorText, this.focusNode, + this.inputColor, this.onTextChange, this.onTextSubmitted, }); @@ -29,16 +33,22 @@ class DefaultInputFieldWidget extends StatelessWidget { maxLines: 1, textInputAction: TextInputAction.next, textStyle: ThemeUtils.textStyleBodyBody3( - color: AppColor.m3SurfaceBackground, + color: inputColor ?? AppColor.m3SurfaceBackground, ), focusNode: focusNode, onTextSubmitted: onTextSubmitted, onTextChange: onTextChange, decoration: InputDecoration( - constraints: const BoxConstraints(maxHeight: 40), + constraints: BoxConstraints( + maxHeight: errorText?.isNotEmpty == true ? 60 : 40, + ), filled: true, - fillColor: Colors.white, - contentPadding: const EdgeInsetsDirectional.only(start: 12, end: 8), + fillColor: errorText?.isNotEmpty == true + ? AppColor.colorInputBackgroundErrorVerifyName + : Colors.white, + contentPadding: errorText?.isNotEmpty == true + ? const EdgeInsetsDirectional.only(start: 12, end: 8) + : const EdgeInsetsDirectional.only(start: 12, end: 8, top: 12, bottom: 12), enabledBorder: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10)), borderSide: BorderSide(width: 1, color: AppColor.m3Neutral90), @@ -51,8 +61,18 @@ class DefaultInputFieldWidget extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(10)), borderSide: BorderSide(width: 1, color: AppColor.primaryColor), ), + errorBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(width: 1, color: AppColor.redFF3347), + ), + focusedErrorBorder: const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + borderSide: BorderSide(width: 1, color: AppColor.redFF3347), + ), hintText: hintText, hintStyle: ThemeUtils.textStyleBodyBody3(color: AppColor.m3Tertiary), + errorText: errorText, + errorStyle: ThemeUtils.textStyleBodyBody3(color: AppColor.redFF3347), ), ); } diff --git a/lib/features/base/widget/drop_down_button_widget.dart b/lib/features/base/widget/drop_down_button_widget.dart index 86407c7f0..007b4e45b 100644 --- a/lib/features/base/widget/drop_down_button_widget.dart +++ b/lib/features/base/widget/drop_down_button_widget.dart @@ -35,6 +35,8 @@ class DropDownButtonWidget extends StatelessWidget { final double? dropdownWidth; final double? dropdownMaxHeight; final String? hintText; + final TextStyle? labelTextStyle; + final TextStyle? hintTextStyle; const DropDownButtonWidget({ Key? key, @@ -54,6 +56,8 @@ class DropDownButtonWidget extends StatelessWidget { this.colorButton = Colors.white, this.tooltip = '', this.hintText, + this.labelTextStyle, + this.hintTextStyle, }) : super(key: key); @override @@ -68,7 +72,7 @@ class DropDownButtonWidget extends StatelessWidget { ? Row(children: [ Expanded(child: Text( _getTextItemDropdown(context, item: itemSelected), - style: ThemeUtils.defaultTextStyleInterFont.copyWith(fontSize: 16, + style: hintTextStyle ?? ThemeUtils.defaultTextStyleInterFont.copyWith(fontSize: 16, fontWeight: FontWeight.normal, color: Colors.black.withValues(alpha: opacity)), maxLines: 1, @@ -86,7 +90,7 @@ class DropDownButtonWidget extends StatelessWidget { height: heightItem, child: Row(children: [ Expanded(child: Text(_getTextItemDropdown(context, item: item), - style: ThemeUtils.defaultTextStyleInterFont.copyWith( + style: labelTextStyle ?? ThemeUtils.defaultTextStyleInterFont.copyWith( fontSize: 16, fontWeight: FontWeight.normal, color: Colors.black), @@ -122,7 +126,7 @@ class DropDownButtonWidget extends StatelessWidget { child: Row(children: [ Expanded(child: Text( _getTextItemDropdown(context, item: itemSelected), - style: ThemeUtils.defaultTextStyleInterFont.copyWith(fontSize: 16, + style: labelTextStyle ?? ThemeUtils.defaultTextStyleInterFont.copyWith(fontSize: 16, fontWeight: FontWeight.normal, color: itemSelected != null ? Colors.black.withValues(alpha: opacity) : AppColor.textFieldHintColor), maxLines: 1, diff --git a/lib/features/base/widget/label_input_field_builder.dart b/lib/features/base/widget/label_input_field_builder.dart index 569a2ae23..26ab69405 100644 --- a/lib/features/base/widget/label_input_field_builder.dart +++ b/lib/features/base/widget/label_input_field_builder.dart @@ -7,8 +7,12 @@ class LabelInputFieldBuilder extends StatelessWidget { final TextEditingController textEditingController; final String? errorText; final String? hintText; + final TextStyle? labelStyle; final FocusNode? focusNode; + final double? runSpacing; + final double? inputFieldMaxWidth; final bool arrangeHorizontally; + final bool isLabelHasColon; final OnTextChange? onTextChange; const LabelInputFieldBuilder({ @@ -16,19 +20,24 @@ class LabelInputFieldBuilder extends StatelessWidget { required this.label, required this.textEditingController, this.arrangeHorizontally = true, + this.isLabelHasColon = true, this.hintText, this.errorText, this.focusNode, + this.labelStyle, + this.runSpacing, + this.inputFieldMaxWidth, this.onTextChange, }); @override Widget build(BuildContext context) { Widget bodyWidget = ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 565), + constraints: BoxConstraints(maxWidth: inputFieldMaxWidth ?? 565), child: DefaultInputFieldWidget( textEditingController: textEditingController, hintText: hintText, + errorText: errorText, focusNode: focusNode, onTextChange: onTextChange, ), @@ -41,7 +50,7 @@ class LabelInputFieldBuilder extends StatelessWidget { ConstrainedBox( constraints: const BoxConstraints(minWidth: 83), child: Text( - '$label:', + isLabelHasColon ? '$label:' : label, style: ThemeUtils.textStyleBodyBody3(color: Colors.black), ), ), @@ -54,10 +63,10 @@ class LabelInputFieldBuilder extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - '$label:', - style: ThemeUtils.textStyleBodyBody3(color: Colors.black), + isLabelHasColon ? '$label:' : label, + style: labelStyle ?? ThemeUtils.textStyleBodyBody3(color: Colors.black), ), - const SizedBox(height: 10), + SizedBox(height: runSpacing ?? 10), bodyWidget, ], ); diff --git a/lib/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart b/lib/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart index 01f7b45cc..2b09580b1 100644 --- a/lib/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart +++ b/lib/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart @@ -10,33 +10,37 @@ import 'package:tmail_ui_user/main/routes/route_utils.dart'; extension PresentationMailboxExtension on PresentationMailbox { - String getDisplayName(BuildContext context) { + String getDisplayNameByLocalizations(AppLocalizations appLocalizations) { if (isDefault) { switch(role!.value.toLowerCase()) { case PresentationMailbox.inboxRole: - return AppLocalizations.of(context).inboxMailboxDisplayName; + return appLocalizations.inboxMailboxDisplayName; case PresentationMailbox.archiveRole: - return AppLocalizations.of(context).archiveMailboxDisplayName; + return appLocalizations.archiveMailboxDisplayName; case PresentationMailbox.draftsRole: - return AppLocalizations.of(context).draftsMailboxDisplayName; + return appLocalizations.draftsMailboxDisplayName; case PresentationMailbox.sentRole: - return AppLocalizations.of(context).sentMailboxDisplayName; + return appLocalizations.sentMailboxDisplayName; case PresentationMailbox.outboxRole: - return AppLocalizations.of(context).outboxMailboxDisplayName; + return appLocalizations.outboxMailboxDisplayName; case PresentationMailbox.trashRole: - return AppLocalizations.of(context).trashMailboxDisplayName; + return appLocalizations.trashMailboxDisplayName; case PresentationMailbox.spamRole: case PresentationMailbox.junkRole: - return AppLocalizations.of(context).spamMailboxDisplayName; + return appLocalizations.spamMailboxDisplayName; case PresentationMailbox.templatesRole: - return AppLocalizations.of(context).templatesMailboxDisplayName; + return appLocalizations.templatesMailboxDisplayName; case PresentationMailbox.recoveredRole: - return AppLocalizations.of(context).recoveredMailboxDisplayName; + return appLocalizations.recoveredMailboxDisplayName; } } return name?.name ?? ''; } + String getDisplayName(BuildContext context) { + return getDisplayNameByLocalizations(AppLocalizations.of(context)); + } + String getMailboxIcon(ImagePaths imagePaths) { if (hasRole()) { switch(role!.value) { diff --git a/lib/features/rules_filter_creator/presentation/model/creator_action_type.dart b/lib/features/rules_filter_creator/presentation/model/creator_action_type.dart index 61988611c..0b2307f97 100644 --- a/lib/features/rules_filter_creator/presentation/model/creator_action_type.dart +++ b/lib/features/rules_filter_creator/presentation/model/creator_action_type.dart @@ -7,12 +7,12 @@ enum CreatorActionType { create, edit; - String getTitle(BuildContext context) { + String getTitle(AppLocalizations appLocalizations) { switch(this) { case CreatorActionType.create: - return AppLocalizations.of(context).createNewRule.inCaps; + return appLocalizations.createANewRule; case CreatorActionType.edit: - return AppLocalizations.of(context).editRule.inCaps; + return appLocalizations.editRule.capitalizeFirstEach; } } 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 eefbb82d3..2d275372f 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,19 +3,19 @@ import 'package:flutter/material.dart'; class RulesFilterInputFieldArguments with EquatableMixin { final FocusNode focusNode; - final String errorText; final TextEditingController controller; + final String? errorText; RulesFilterInputFieldArguments({ required this.focusNode, - required this.errorText, required this.controller, + this.errorText, }); @override List get props => [ focusNode, - errorText, controller, + errorText, ]; } 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 97296c737..758aa772e 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 @@ -166,7 +166,6 @@ class RulesFilterCreatorController extends BaseMailboxController { listRuleCondition.add(newRuleCondition); RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( focusNode: FocusNode(), - errorText: '', controller: TextEditingController(), ); listRuleConditionValueArguments.add(newRuleConditionValueArguments); @@ -207,7 +206,6 @@ class RulesFilterCreatorController extends BaseMailboxController { listRuleCondition.add(condition); RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( focusNode: FocusNode(), - errorText: '', controller: TextEditingController(), ); listRuleConditionValueArguments.add(newRuleConditionValueArguments); @@ -300,7 +298,7 @@ class RulesFilterCreatorController extends BaseMailboxController { String? errorString = _getErrorStringByInputValue(context, listRuleCondition[ruleConditionIndex].value); RulesFilterInputFieldArguments newRuleConditionValueArguments = RulesFilterInputFieldArguments( focusNode: listRuleConditionValueArguments[ruleConditionIndex].focusNode, - errorText: errorString ?? '', + errorText: errorString, controller: listRuleConditionValueArguments[ruleConditionIndex].controller, ); if (listRuleConditionValueArguments.length > ruleConditionIndex) { @@ -611,7 +609,6 @@ class RulesFilterCreatorController extends BaseMailboxController { listRuleCondition.add(newRuleCondition); listRuleConditionValueArguments.add(RulesFilterInputFieldArguments( 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 a95a9ee46..7c073d375 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 @@ -1,16 +1,22 @@ +import 'dart:math' as math; + import 'package:core/core.dart'; +import 'package:core/presentation/views/dialog/confirm_dialog_button.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:get/get.dart'; -import 'package:pointer_interceptor/pointer_interceptor.dart'; import 'package:rule_filter/rule_filter/rule_condition_group.dart'; +import 'package:tmail_ui_user/features/base/widget/default_field/default_close_button_widget.dart'; +import 'package:tmail_ui_user/features/base/widget/label_input_field_builder.dart'; import 'package:tmail_ui_user/features/base/widget/pop_back_barrier_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/extensions/select_rule_action_field_extension.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rule_filter_action_arguments.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/rules_filter_creator_controller.dart'; -import 'package:tmail_ui_user/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart'; -import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_action_list.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_action_widget.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/rule_filter_list_action_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_title_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'; @@ -25,402 +31,258 @@ class RuleFilterCreatorView extends GetWidget { @override Widget build(BuildContext context) { final responsiveUtil = controller.responsiveUtils; + final isMobile = responsiveUtil.isMobile(context); final focusScope = FocusScope.of(context); + final currentScreenHeight = responsiveUtil.getSizeScreenHeight(context); + final currentScreenWidth = responsiveUtil.getSizeScreenWidth(context); - return PointerInterceptor( - child: ResponsiveWidget( - responsiveUtils: responsiveUtil, - mobile: Scaffold( - backgroundColor: - PlatformInfo.isWeb ? Colors.black.withAlpha(24) : Colors.black38, - body: PopBackBarrierWidget( - child: SafeArea( - bottom: false, - left: false, - right: false, - child: GestureDetector( - onTap: focusScope.unfocus, - child: Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.vertical( - top: Radius.circular(16), - ), - color: Colors.white, - ), - margin: EdgeInsets.only(top: PlatformInfo.isWeb ? 70 : 0), - child: SafeArea( - child: _buildRulesFilterFormOnMobile(context), - ), - ), + if (!isMobile) { + return Center( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(16)), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.08), + blurRadius: 24, + offset: const Offset(0, 2), ), + BoxShadow( + color: Colors.black.withValues(alpha: 0.08), + blurRadius: 2, + ), + ], + ), + width: math.min( + currentScreenWidth, + 612, + ), + constraints: BoxConstraints( + maxHeight: math.min( + currentScreenHeight - 100, + 674, ), ), + clipBehavior: Clip.antiAlias, + child: _buildRulesFilterFormOnDesktop(context), ), - tablet: Scaffold( - backgroundColor: Colors.black.withAlpha(24), - body: PopBackBarrierWidget( - child: Align( - alignment: Alignment.bottomCenter, - child: GestureDetector( - onTap: focusScope.unfocus, - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.vertical( - top: Radius.circular(16), - ), + ); + } + + return ResponsiveWidget( + responsiveUtils: responsiveUtil, + mobile: Scaffold( + backgroundColor: + PlatformInfo.isWeb ? Colors.black.withAlpha(24) : Colors.black38, + body: PopBackBarrierWidget( + child: SafeArea( + bottom: false, + left: false, + right: false, + child: GestureDetector( + onTap: focusScope.unfocus, + child: Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.vertical( + top: Radius.circular(16), ), - height: responsiveUtil.getSizeScreenHeight(context) * 0.7, - child: _buildRulesFilterFormOnTablet(context), - ), - ), - ), - ), - ), - desktop: Scaffold( - backgroundColor: Colors.black.withAlpha(24), - body: PopBackBarrierWidget( - child: Center( - child: GestureDetector( - onTap: focusScope.unfocus, - child: Card( color: Colors.white, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(16)), - ), - clipBehavior: Clip.hardEdge, - child: SizedBox( - width: responsiveUtil.getSizeScreenWidth(context) * 0.6, - height: responsiveUtil.getSizeScreenHeight(context) * 0.7, - child: _buildRulesFilterFormOnDesktop(context), - ), + ), + margin: EdgeInsets.only(top: PlatformInfo.isWeb ? 70 : 0), + child: SafeArea( + child: _buildRulesFilterFormOnMobile(context), ), ), ), ), ), ), + tablet: Scaffold( + backgroundColor: Colors.black.withAlpha(24), + body: Center( + child: GestureDetector( + onTap: focusScope.unfocus, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.all(Radius.circular(16)), + boxShadow: [ + BoxShadow( + color: Colors.black.withValues(alpha: 0.08), + blurRadius: 24, + offset: const Offset(0, 2), + ), + BoxShadow( + color: Colors.black.withValues(alpha: 0.08), + blurRadius: 2, + ), + ], + ), + width: math.min( + currentScreenWidth, + 612, + ), + constraints: BoxConstraints( + maxHeight: math.min( + currentScreenHeight - 100, + 674, + ), + ), + clipBehavior: Clip.antiAlias, + child: _buildRulesFilterFormOnDesktop(context), + ), + ), + ), + ), ); } Widget _buildRulesFilterFormOnDesktop(BuildContext context) { + final appLocalizations = AppLocalizations.of(context); + return Stack( children: [ - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - padding: const EdgeInsets.only(top: 16), - alignment: Alignment.center, - child: Obx(() => Text( - controller.actionType.value.getTitle(context), - style: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.bold, - fontSize: 20, - color: Colors.black)))), - Expanded(child: SingleChildScrollView( - physics: const ClampingScrollPhysics(), - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Obx(() => RulesFilterInputField( - hintText: AppLocalizations.of(context).rulesNameHintTextInput, - errorText: controller.errorRuleName.value, - editingController: controller.inputRuleNameController, - focusNode: controller.inputRuleNameFocusNode, - onChangeAction: (value) => controller.updateRuleName(context, value),)), - const SizedBox(height: 24), - Obx(() => RuleFilterTitle( - conditionCombinerType: controller.conditionCombinerType.value, - tapActionCallback: (value) => controller.selectConditionCombiner(value), - ruleFilterConditionScreenType: RuleFilterConditionScreenType.desktop, - )), - const SizedBox(height: 24), - _buildListRuleFilterConditionList(context, RuleFilterConditionScreenType.desktop), - Container( - padding: const EdgeInsets.only(top: 8), - child: InkWell( - onTap: controller.tapAddCondition, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset( - controller.imagePaths.icAddNewFolder, - fit: BoxFit.fill, - ), - const SizedBox(width: 15,), - Text( - AppLocalizations.of(context).addCondition, - maxLines: 1, - style: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: 17, - color: AppColor.primaryColor - ) - ) - ], + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: const EdgeInsets.only(top: 24, bottom: 12), + alignment: Alignment.center, + child: Obx( + () => Text( + controller.actionType.value.getTitle(appLocalizations), + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.headlineSmall?.copyWith( + color: AppColor.m3SurfaceBackground, ), - ), - ), - const SizedBox(height: 24), - Text(AppLocalizations.of(context).actionTitleRulesFilter, - overflow: CommonTextStyle.defaultTextOverFlow, - softWrap: CommonTextStyle.defaultSoftWrap, - maxLines: 1, - style: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: 16, - color: Colors.black)), - const SizedBox(height: 24), - Obx(() { - return RuleFilterActionListWidget( - responsiveUtils: controller.responsiveUtils, - actionList: controller.listEmailRuleFilterActionSelected, - onActionChanged: (newAction, index) { - controller.updateEmailRuleFilterAction(context, newAction, index); - }, - forwardEmailEditingController: controller.forwardEmailController, - forwardEmailFocusNode: controller.forwardEmailFocusNode, - onChangeForwardEmail: (value, index) => controller.updateForwardEmailValue(context, value, index), - tapActionDetailedCallback: (index) { - KeyboardUtils.hideKeyboard(context); - controller.selectMailbox(context, index); - }, - tapRemoveCallback: (index) => controller.tapRemoveAction(index), - imagePaths: controller.imagePaths, - errorForwardEmail: controller.errorForwardEmailValue.value, - errorMailboxSelected: controller.errorMailboxSelectedValue.value, - ); - }), - Obx(() { - if (controller.isShowAddAction.value == true) { - return Container( - padding: const EdgeInsets.only(top: 8), - child: InkWell( - onTap: controller.tapAddAction, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset( - controller.imagePaths.icAddNewFolder, - fit: BoxFit.fill, - ), - const SizedBox(width: 15,), - Text( - AppLocalizations.of(context).addAction, - maxLines: RuleFilterActionStyles.maxLines, - style: RuleFilterActionStyles.addActionButtonTextStyle - ) - ], - ), - ), - ); - } else { - return const SizedBox.shrink(); - } - }) - ] + ), ), ), - )), - Container( - padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24), - alignment: Alignment.centerRight, - color: Colors.white, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - buildTextButton( - AppLocalizations.of(context).cancel, - textStyle: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: 17, - color: AppColor.colorTextButton), - backgroundColor: AppColor.emailAddressChipColor, - width: 128, - height: 44, - radius: 10, - onTap: () => controller.closeView(context)), - const SizedBox(width: 12), - Obx(() => buildTextButton( - controller.actionType.value.getActionName(context), - width: 128, - height: 44, - backgroundColor: AppColor.colorTextButton, - radius: 10, - onTap: () => controller.createNewRuleFilter(context))), - ] - ), - ) - ]), - Positioned(top: 8, right: 8, - child: buildIconWeb( - icon: SvgPicture.asset( - controller.imagePaths.icCircleClose, - fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).close, - onTap: () => controller.closeView(context))) - ] - ); - } - - Widget _buildRulesFilterFormOnTablet(BuildContext context) { - return Stack( - children: [ - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - padding: const EdgeInsets.only(top: 16), - alignment: Alignment.center, - child: Obx(() => Text( - controller.actionType.value.getTitle(context), - style: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.bold, - fontSize: 20, - color: Colors.black)))), - Expanded(child: SingleChildScrollView( - physics: const ClampingScrollPhysics(), - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Column( + Expanded( + child: SingleChildScrollView( + physics: const ClampingScrollPhysics(), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Obx(() => RulesFilterInputField( - hintText: AppLocalizations.of(context).rulesNameHintTextInput, - errorText: controller.errorRuleName.value, - editingController: controller.inputRuleNameController, - focusNode: controller.inputRuleNameFocusNode, - onChangeAction: (value) => controller.updateRuleName(context, value),)), - const SizedBox(height: 24), - Obx(() => RuleFilterTitle( - conditionCombinerType: controller.conditionCombinerType.value, - tapActionCallback: (value) => controller.selectConditionCombiner(value), - ruleFilterConditionScreenType: RuleFilterConditionScreenType.tablet, - )), - const SizedBox(height: 24), - _buildListRuleFilterConditionList(context, RuleFilterConditionScreenType.tablet), - Container( - padding: const EdgeInsets.only(top: 8), - child: InkWell( - onTap: controller.tapAddCondition, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset( - controller.imagePaths.icAddNewFolder, - fit: BoxFit.fill, - ), - const SizedBox(width: 15,), - Text( - AppLocalizations.of(context).addCondition, - maxLines: 1, - style: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: 17, - color: AppColor.primaryColor - ) - ) - ], + Obx( + () => LabelInputFieldBuilder( + label: appLocalizations.ruleName, + hintText: appLocalizations.rulesNameHintTextInput, + textEditingController: + controller.inputRuleNameController, + focusNode: controller.inputRuleNameFocusNode, + errorText: controller.errorRuleName.value, + arrangeHorizontally: false, + isLabelHasColon: false, + labelStyle: ThemeUtils.textStyleInter600().copyWith( + fontSize: 14, + height: 18 / 14, + color: Colors.black, + ), + runSpacing: 16, + inputFieldMaxWidth: double.infinity, + onTextChange: (value) => + controller.updateRuleName(context, value), + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: 24, + ), + child: Text( + appLocalizations.condition, + style: ThemeUtils.textStyleInter600().copyWith( + fontSize: 14, + height: 18 / 14, + color: Colors.black, ), ), ), - const SizedBox(height: 24), - Text(AppLocalizations.of(context).actionTitleRulesFilter, - overflow: CommonTextStyle.defaultTextOverFlow, - softWrap: CommonTextStyle.defaultSoftWrap, - maxLines: 1, - style: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: 16, - color: Colors.black)), - const SizedBox(height: 24), - Obx(() { - return RuleFilterActionListWidget( + Obx( + () => RuleFilterTitle( + conditionCombinerType: + controller.conditionCombinerType.value, responsiveUtils: controller.responsiveUtils, - actionList: controller.listEmailRuleFilterActionSelected, - onActionChanged: (newAction, index) { - controller.updateEmailRuleFilterAction(context, newAction, index); - }, - forwardEmailEditingController: controller.forwardEmailController, - forwardEmailFocusNode: controller.forwardEmailFocusNode, - onChangeForwardEmail: (value, index) => controller.updateForwardEmailValue(context, value, index), - tapActionDetailedCallback: (index) { - KeyboardUtils.hideKeyboard(context); - controller.selectMailbox(context, index); - }, - tapRemoveCallback: (index) => controller.tapRemoveAction(index), - imagePaths: controller.imagePaths, - errorForwardEmail: controller.errorForwardEmailValue.value, - errorMailboxSelected: controller.errorMailboxSelectedValue.value, - ); - }), + tapActionCallback: (value) => + controller.selectConditionCombiner(value), + ruleFilterConditionScreenType: + RuleFilterConditionScreenType.desktop, + ), + ), + const SizedBox(height: 8), + _buildListRuleFilterConditionList( + context, + RuleFilterConditionScreenType.desktop, + ), + Container( + constraints: const BoxConstraints(minWidth: 161), + height: 36, + margin: const EdgeInsetsDirectional.only(top: 12), + child: ConfirmDialogButton( + label: AppLocalizations.of(context).addACondition, + backgroundColor: Colors.white, + textColor: AppColor.primaryMain, + borderColor: AppColor.primaryMain, + icon: controller.imagePaths.icAddIdentity, + onTapAction: controller.tapAddCondition, + ), + ), + Padding( + padding: const EdgeInsetsDirectional.only( + top: 24, + bottom: 8, + ), + child: Text( + appLocalizations.actionsToPerform, + style: ThemeUtils.textStyleInter600().copyWith( + fontSize: 14, + height: 18 / 14, + color: Colors.black, + ), + ), + ), + _buildListRuleFilterActionList(context), Obx(() { if (controller.isShowAddAction.value == true) { return Container( - padding: const EdgeInsets.only(top: 8), - child: InkWell( - onTap: controller.tapAddAction, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SvgPicture.asset( - controller.imagePaths.icAddNewFolder, - fit: BoxFit.fill, - ), - const SizedBox(width: 15,), - Text( - AppLocalizations.of(context).addAction, - maxLines: RuleFilterActionStyles.maxLines, - style: RuleFilterActionStyles.addActionButtonTextStyle - ) - ], - ), + constraints: const BoxConstraints(minWidth: 161), + height: 36, + margin: const EdgeInsetsDirectional.only(top: 4), + child: ConfirmDialogButton( + label: AppLocalizations.of(context).addAnAction, + backgroundColor: Colors.white, + textColor: AppColor.primaryMain, + borderColor: AppColor.primaryMain, + icon: controller.imagePaths.icAddIdentity, + onTapAction: controller.tapAddAction, ), ); } else { return const SizedBox.shrink(); } - }) - ] + }), + ], + ), ), ), - )), - Container( - padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24), - alignment: Alignment.center, - color: Colors.white, - child: Row( - children: [ - Expanded(child: buildTextButton( - AppLocalizations.of(context).cancel, - textStyle: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: 17, - color: AppColor.colorTextButton), - backgroundColor: AppColor.emailAddressChipColor, - width: 128, - height: 44, - radius: 10, - onTap: () => controller.closeView(context))), - const SizedBox(width: 12), - Expanded(child: Obx(() => buildTextButton( - controller.actionType.value.getActionName(context), - width: 128, - height: 44, - backgroundColor: AppColor.colorTextButton, - radius: 10, - onTap: () => controller.createNewRuleFilter(context)))), - ] - ), - ) - ]), - Positioned(top: 8, right: 8, - child: buildIconWeb( - icon: SvgPicture.asset( - controller.imagePaths.icCircleClose, - fit: BoxFit.fill), - tooltip: AppLocalizations.of(context).close, - onTap: () => controller.closeView(context))) - ] + ), + RuleFilterListActionWidget( + positiveLabel: appLocalizations.createRule, + negativeLabel: appLocalizations.cancel, + padding: const EdgeInsets.symmetric(vertical: 25, horizontal: 32), + onPositiveAction: () => controller.createNewRuleFilter(context), + onNegativeAction: () => controller.closeView(context), + ), + ], + ), + DefaultCloseButtonWidget( + iconClose: controller.imagePaths.icCloseDialog, + onTapActionCallback: () => controller.closeView(context), + ), + ], ); } @@ -432,7 +294,7 @@ class RuleFilterCreatorView extends GetWidget { padding: const EdgeInsets.only(top: 16), alignment: Alignment.center, child: Obx(() => Text( - controller.actionType.value.getTitle(context), + controller.actionType.value.getTitle(AppLocalizations.of(context)), style: ThemeUtils.defaultTextStyleInterFont.copyWith( fontWeight: FontWeight.bold, fontSize: 20, @@ -456,6 +318,7 @@ class RuleFilterCreatorView extends GetWidget { ), Obx(() => RuleFilterTitle( conditionCombinerType: controller.conditionCombinerType.value, + responsiveUtils: controller.responsiveUtils, ruleFilterConditionScreenType: RuleFilterConditionScreenType.mobile, tapActionCallback: (_) { controller.selectRuleConditionCombinerAction( @@ -506,58 +369,26 @@ class RuleFilterCreatorView extends GetWidget { fontSize: 16, color: Colors.black)), const SizedBox(height: 24), - Obx(() { - return RuleFilterActionListWidget( - responsiveUtils: controller.responsiveUtils, - actionList: controller.listEmailRuleFilterActionSelected, - onActionChangeMobile: (currentAction, index) { - controller.selectRuleFilterAction( - context, - currentAction, - index - ); - }, - forwardEmailEditingController: controller.forwardEmailController, - forwardEmailFocusNode: controller.forwardEmailFocusNode, - onChangeForwardEmail: (value, index) => controller.updateForwardEmailValue(context, value, index), - tapActionDetailedCallback: (index) { - KeyboardUtils.hideKeyboard(context); - controller.selectMailbox(context, index); - }, - tapRemoveCallback: (index) => controller.tapRemoveAction(index), - imagePaths: controller.imagePaths, - errorForwardEmail: controller.errorForwardEmailValue.value, - errorMailboxSelected: controller.errorMailboxSelectedValue.value, - ); - }), + _buildListRuleFilterActionList(context), Obx(() { if (controller.isShowAddAction.value == true) { return Container( - padding: const EdgeInsets.only(top: 12), - child: InkWell( - onTap: controller.tapAddAction, - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - controller.imagePaths.icAddNewFolder, - fit: BoxFit.fill, - ), - const SizedBox(width: 15,), - Text( - AppLocalizations.of(context).addAction, - maxLines: RuleFilterActionStyles.maxLines, - style: RuleFilterActionStyles.addActionButtonTextStyle - ) - ], - ), + constraints: const BoxConstraints(minWidth: 161), + height: 36, + margin: const EdgeInsetsDirectional.only(top: 4), + child: ConfirmDialogButton( + label: AppLocalizations.of(context).addAnAction, + backgroundColor: Colors.white, + textColor: AppColor.primaryMain, + borderColor: AppColor.primaryMain, + icon: controller.imagePaths.icAddIdentity, + onTapAction: controller.tapAddAction, ), ); } else { return const SizedBox.shrink(); } - }) + }), ] ), ), @@ -604,21 +435,23 @@ class RuleFilterCreatorView extends GetWidget { Widget _buildListRuleFilterConditionList( BuildContext context, - RuleFilterConditionScreenType ruleFilterConditionScreenType + RuleFilterConditionScreenType ruleFilterConditionScreenType, ) { return Obx(() { - return ListView.separated( + return ListView.builder( shrinkWrap: true, itemCount: controller.listRuleCondition.length, itemBuilder: (context, index) { + final conditionItem = + controller.listRuleConditionValueArguments[index]; return RuleFilterConditionWidget( - key: ValueKey(controller.listRuleConditionValueArguments[index].focusNode), + key: ValueKey(conditionItem.focusNode), ruleFilterConditionScreenType: ruleFilterConditionScreenType, ruleCondition: controller.listRuleCondition[index], imagePaths: controller.imagePaths, - conditionValueErrorText: controller.listRuleConditionValueArguments[index].errorText, - conditionValueFocusNode: controller.listRuleConditionValueArguments[index].focusNode, - conditionValueEditingController: controller.listRuleConditionValueArguments[index].controller, + conditionValueErrorText: conditionItem.errorText, + conditionValueFocusNode: conditionItem.focusNode, + textEditingController: conditionItem.controller, tapRuleConditionFieldCallback: (value) => controller.selectRuleConditionFieldAction( context, @@ -637,11 +470,66 @@ class RuleFilterCreatorView extends GetWidget { ), conditionValueOnChangeAction: (value) => controller.updateConditionValue(context, value, index), - tapRemoveRuleFilterConditionCallback: () => controller.tapRemoveCondition(index), + onDeleteRuleConditionAction: () => + controller.tapRemoveCondition(index), ); }, - separatorBuilder: (context, index) { - return const SizedBox(height: 12,); + ); + }); + } + + Widget _buildListRuleFilterActionList(BuildContext context) { + return Obx(() { + return ListView.builder( + shrinkWrap: true, + itemCount: controller.listEmailRuleFilterActionSelected.length, + padding: const EdgeInsetsDirectional.only(bottom: 8), + itemBuilder: (context, index) { + final currentAction = controller.listEmailRuleFilterActionSelected[index]; + String? errorValue; + if (currentAction is ForwardActionArguments) { + errorValue = controller.errorForwardEmailValue.value; + } else { + errorValue = controller.errorMailboxSelectedValue.value; + } + return RuleFilterActionWidget( + responsiveUtils: controller.responsiveUtils, + mailboxSelected: currentAction is MoveMessageActionArguments + ? currentAction.mailbox + : null, + errorValue: errorValue, + onActionChangeMobile: () { + controller.selectRuleFilterAction( + context, + currentAction.action, + index, + ); + }, + onActionChanged: (newAction) { + if (newAction != currentAction.action) { + controller.updateEmailRuleFilterAction( + context, + newAction, + index, + ); + } + }, + forwardEmailEditingController: currentAction.action == EmailRuleFilterAction.forwardTo + ? controller.forwardEmailController + : null, + forwardEmailFocusNode: currentAction.action == EmailRuleFilterAction.forwardTo + ? controller.forwardEmailFocusNode + : null, + onChangeForwardEmail: (value) => controller.updateForwardEmailValue(context, value, index), + actionSelected: currentAction.action, + tapActionDetailedCallback: () { + KeyboardUtils.hideKeyboard(context); + controller.selectMailbox(context, index); + }, + onDeleteRuleConditionAction: () => + controller.tapRemoveAction(index), + imagePaths: controller.imagePaths, + ); }, ); }); diff --git a/lib/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart b/lib/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart index 748a2d96a..10c96cfc4 100644 --- a/lib/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart +++ b/lib/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart @@ -1,24 +1,7 @@ -import 'package:core/presentation/extensions/color_extension.dart'; -import 'package:core/presentation/utils/theme_utils.dart'; -import 'package:flutter/material.dart'; - class RuleFilterActionStyles { static const double extentRatio = 0.1; static const double removeButtonRadius = 110.0; static const double mainPadding = 12.0; static const double mainBorderRadius = 12.0; - static const int maxLines = 1; - static const double fontSize = 16.0; - static const Color color = Colors.black; - static TextStyle textStyle = ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.normal, - fontSize: fontSize, - color: color, - ); static const double itemDistance = 12.0; - static TextStyle addActionButtonTextStyle = ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: 17.0, - color: AppColor.primaryColor, - ); -} \ No newline at end of file +} diff --git a/lib/features/rules_filter_creator/presentation/styles/rule_filter_title_styles.dart b/lib/features/rules_filter_creator/presentation/styles/rule_filter_title_styles.dart deleted file mode 100644 index 57d93aad6..000000000 --- a/lib/features/rules_filter_creator/presentation/styles/rule_filter_title_styles.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:core/presentation/utils/theme_utils.dart'; -import 'package:flutter/material.dart'; - -class RuleFilterTitleStyles { - static const double fontSize = 16.0; - static const Color textColor = Colors.black; - static TextStyle textStyle = ThemeUtils.defaultTextStyleInterFont.copyWith( - fontWeight: FontWeight.w500, - fontSize: fontSize, - color: textColor, - ); - static const int textMaxLines = 1; - static const double combinerTypeSelectionAreaWith = 200.0; - static const double combinerTypeSelectionAreaPadding = 12.0; -} \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_detailed_builder.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_detailed_builder.dart index f90450cb1..ca1d05b95 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_detailed_builder.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_detailed_builder.dart @@ -1,6 +1,7 @@ import 'package:core/core.dart'; import 'package:flutter/material.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:tmail_ui_user/features/base/widget/default_field/default_input_field_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.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'; @@ -39,12 +40,13 @@ class RuleFilterActionDetailed extends StatelessWidget { }, ); case EmailRuleFilterAction.forwardTo: - return RulesFilterInputField( + return DefaultInputFieldWidget( errorText: errorValue, hintText: AppLocalizations.of(context).forwardEmailHintText, - editingController: forwardEmailEditingController, + textEditingController: forwardEmailEditingController!, focusNode: forwardEmailFocusNode, - onChangeAction: forwardEmailOnChangeAction, + inputColor: Colors.black, + onTextChange: forwardEmailOnChangeAction, ); case EmailRuleFilterAction.maskAsSeen: case EmailRuleFilterAction.starIt: diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_list.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_list.dart deleted file mode 100644 index c20d5fb4e..000000000 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_list.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'package:core/presentation/resources/image_paths.dart'; -import 'package:core/presentation/utils/responsive_utils.dart'; -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/email_rule_filter_action.dart'; -import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rule_filter_action_arguments.dart'; -import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_action_widget.dart'; - -class RuleFilterActionListWidget extends StatelessWidget { - final ResponsiveUtils responsiveUtils; - final List actionList; - final Function(EmailRuleFilterAction?, int)? onActionChangeMobile; - final Function(EmailRuleFilterAction?, int)? onActionChanged; - final TextEditingController? forwardEmailEditingController; - final FocusNode? forwardEmailFocusNode; - final Function(int)? tapActionDetailedCallback; - final Function(int)? tapRemoveCallback; - final ImagePaths? imagePaths; - final Function(String?, int)? onChangeForwardEmail; - final String? errorForwardEmail; - final String? errorMailboxSelected; - - const RuleFilterActionListWidget({ - Key? key, - required this.responsiveUtils, - required this.actionList, - this.onActionChangeMobile, - this.onActionChanged, - this.forwardEmailEditingController, - this.forwardEmailFocusNode, - this.tapActionDetailedCallback, - this.tapRemoveCallback, - this.imagePaths, - this.onChangeForwardEmail, - this.errorForwardEmail, - this.errorMailboxSelected, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - return Obx(() { - return ListView.separated( - shrinkWrap: true, - itemCount: actionList.length, - separatorBuilder: (context, index) { - return const SizedBox(height: 12,); - }, - itemBuilder: (context, index) { - final RuleFilterActionArguments currentAction = actionList[index]; - String? errorValue; - if (currentAction is ForwardActionArguments) { - errorValue = errorForwardEmail; - } else { - errorValue = errorMailboxSelected; - } - return RuleFilterActionWidget( - responsiveUtils: responsiveUtils, - mailboxSelected: currentAction is MoveMessageActionArguments ? currentAction.mailbox : null, - errorValue: errorValue, - onActionChangeMobile: () { - onActionChangeMobile!(currentAction.action, index); - }, - onActionChanged: (newAction) { - if (newAction != currentAction.action) { - onActionChanged!(newAction, index); - } - }, - forwardEmailEditingController: currentAction.action == EmailRuleFilterAction.forwardTo ? forwardEmailEditingController : null, - forwardEmailFocusNode: currentAction.action == EmailRuleFilterAction.forwardTo ? forwardEmailFocusNode : null, - onChangeForwardEmail: (value) => onChangeForwardEmail!(value, index), - actionSelected: currentAction.action, - tapActionDetailedCallback: () => tapActionDetailedCallback!(index), - tapRemoveCallback: () => tapRemoveCallback!(index), - imagePaths: imagePaths, - ); - }, - ); - }); - } -} diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_builder.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_builder.dart index 7c7040e38..2c2eb60df 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_builder.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_builder.dart @@ -1,24 +1,25 @@ +import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/resources/image_paths.dart'; -import 'package:core/presentation/utils/style_utils.dart'; +import 'package:core/presentation/utils/theme_utils.dart'; import 'package:flutter/material.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; +import 'package:tmail_ui_user/features/base/widget/default_field/default_input_field_widget.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/email_rule_filter_action.dart'; -import 'package:tmail_ui_user/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart'; -import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_action_detailed_builder.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/rule_filter_button_field.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_delete_button_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'; class RuleFilterActionRow extends StatelessWidget { final List actionList; + final ImagePaths imagePaths; + final OnDeleteRuleConditionAction onDeleteRuleConditionAction; final EmailRuleFilterAction? actionSelected; final Function(EmailRuleFilterAction?)? onActionChanged; final PresentationMailbox? mailboxSelected; final String? errorValue; final Function()? tapActionDetailedCallback; - final ImagePaths? imagePaths; - final Function()? tapRemoveActionCallback; final TextEditingController? forwardEmailEditingController; final FocusNode? forwardEmailFocusNode; final OnChangeFilterInputAction? onChangeForwardEmail; @@ -26,13 +27,13 @@ class RuleFilterActionRow extends StatelessWidget { const RuleFilterActionRow({ Key? key, required this.actionList, + required this.imagePaths, + required this.onDeleteRuleConditionAction, this.actionSelected, this.onActionChanged, this.mailboxSelected, this.errorValue, this.tapActionDetailedCallback, - this.imagePaths, - this.tapRemoveActionCallback, this.forwardEmailEditingController, this.forwardEmailFocusNode, this.onChangeForwardEmail, @@ -40,9 +41,11 @@ class RuleFilterActionRow extends StatelessWidget { @override Widget build(BuildContext context) { - final supportedAction = actionList.where((action) => action.isSupported).toList(); + final supportedAction = actionList + .where((action) => action.isSupported) + .toList(); + return Row( - crossAxisAlignment: actionSelected == EmailRuleFilterAction.moveMessage ? CrossAxisAlignment.center : CrossAxisAlignment.start, children: [ Expanded( child: DropDownButtonWidget( @@ -51,41 +54,54 @@ class RuleFilterActionRow extends StatelessWidget { onChanged: (newAction) => onActionChanged!(newAction), supportSelectionIcon: true, supportHint: true, + labelTextStyle: ThemeUtils.textStyleBodyBody3( + color: Colors.black, + ), + hintTextStyle: ThemeUtils.textStyleBodyBody3( + color: AppColor.steelGray400, + ), hintText: AppLocalizations.of(context).selectAction, ), ), - actionSelected == EmailRuleFilterAction.moveMessage - ? Padding( - padding: const EdgeInsets.symmetric(horizontal: RuleFilterActionStyles.mainPadding), + if (actionSelected == EmailRuleFilterAction.moveMessage) + ...[ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), child: Text( AppLocalizations.of(context).toFolder, - overflow: CommonTextStyle.defaultTextOverFlow, - softWrap: CommonTextStyle.defaultSoftWrap, - maxLines: RuleFilterActionStyles.maxLines, - style: RuleFilterActionStyles.textStyle, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: ThemeUtils.textStyleInter400.copyWith( + fontSize: 14, + height: 18 / 14, + color: Colors.black, + ), ), - ) - : SizedBox( - width: actionSelected == EmailRuleFilterAction.forwardTo ? RuleFilterActionStyles.itemDistance : 0, ), - Expanded( - child: RuleFilterActionDetailed( - actionType: actionSelected, - mailboxSelected: mailboxSelected, - errorValue: errorValue, - tapActionDetailedCallback: tapActionDetailedCallback, - forwardEmailEditingController: forwardEmailEditingController, - forwardEmailFocusNode: forwardEmailFocusNode, - forwardEmailOnChangeAction: onChangeForwardEmail, - ), - ), - Container( - padding: const EdgeInsets.only(left: RuleFilterActionStyles.mainPadding), - alignment: Alignment.center, - child: RuleFilterConditionRemoveButton( - imagePath: imagePaths, - tapRemoveRuleFilterConditionCallback: tapRemoveActionCallback, + Expanded( + child: RuleFilterButtonField( + value: mailboxSelected, + borderColor: errorValue?.isNotEmpty == true + ? AppColor.redFF3347 + : AppColor.m3Neutral90, + tapActionCallback: (_) => tapActionDetailedCallback?.call(), + ), + ), + ] + else if (actionSelected == EmailRuleFilterAction.forwardTo) + Expanded( + child: DefaultInputFieldWidget( + errorText: errorValue, + hintText: AppLocalizations.of(context).forwardEmailHintText, + textEditingController: forwardEmailEditingController!, + focusNode: forwardEmailFocusNode, + inputColor: Colors.black, + onTextChange: onChangeForwardEmail, + ), ), + RuleFilterDeleteButtonWidget( + imagePaths: imagePaths, + onDeleteRuleConditionAction: onDeleteRuleConditionAction, ) ], ); diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_mobile_builder.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_mobile_builder.dart index bb3092a8c..29a7a954e 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_mobile_builder.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_mobile_builder.dart @@ -48,10 +48,13 @@ class RuleFilterActionRowMobile extends StatelessWidget { padding: const EdgeInsets.symmetric(vertical: RuleFilterActionStyles.mainPadding), child: Text( AppLocalizations.of(context).toFolder, - overflow: CommonTextStyle.defaultTextOverFlow, - softWrap: CommonTextStyle.defaultSoftWrap, - maxLines: RuleFilterActionStyles.maxLines, - style: RuleFilterActionStyles.textStyle, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: ThemeUtils.textStyleInter400.copyWith( + fontSize: 14, + height: 18 / 14, + color: Colors.black, + ), ), ) : SizedBox( diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_widget.dart index 29bb4b346..a1685863e 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_widget.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_action_widget.dart @@ -9,12 +9,13 @@ import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/e import 'package:tmail_ui_user/features/rules_filter_creator/presentation/styles/rule_filter_action_styles.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_builder.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_action_row_mobile_builder.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_delete_button_widget.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rules_filter_input_field_builder.dart'; class RuleFilterActionWidget extends StatelessWidget { final ResponsiveUtils responsiveUtils; - final Function()? tapRemoveCallback; - final ImagePaths? imagePaths; + final ImagePaths imagePaths; + final OnDeleteRuleConditionAction onDeleteRuleConditionAction; final EmailRuleFilterAction? actionSelected; final Function(EmailRuleFilterAction?)? onActionChanged; final Function()? onActionChangeMobile; @@ -28,8 +29,8 @@ class RuleFilterActionWidget extends StatelessWidget { const RuleFilterActionWidget({ Key? key, required this.responsiveUtils, - this.tapRemoveCallback, - this.imagePaths, + required this.imagePaths, + required this.onDeleteRuleConditionAction, this.actionSelected, this.onActionChanged, this.mailboxSelected, @@ -43,6 +44,47 @@ class RuleFilterActionWidget extends StatelessWidget { @override Widget build(BuildContext context) { + final isMobile = responsiveUtils.isMobile(context); + + Widget bodyWidget = Container( + padding: const EdgeInsetsDirectional.only(start: 12), + margin: const EdgeInsetsDirectional.only(top: 8), + decoration: const BoxDecoration( + color: AppColor.lightGrayF9FAFB, + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + height: 72, + alignment: Alignment.center, + child: isMobile + ? RuleFilterActionRowMobile( + actionSelected: actionSelected, + mailboxSelected: mailboxSelected, + errorValue: errorValue, + tapActionDetailedCallback: tapActionDetailedCallback, + forwardEmailEditingController: forwardEmailEditingController, + forwardEmailFocusNode: forwardEmailFocusNode, + onChangeForwardEmail: onChangeForwardEmail, + tapActionCallback: onActionChangeMobile, + ) + : RuleFilterActionRow( + actionList: EmailRuleFilterAction.values, + actionSelected: actionSelected, + onActionChanged: onActionChanged, + mailboxSelected: mailboxSelected, + errorValue: errorValue, + tapActionDetailedCallback: tapActionDetailedCallback, + imagePaths: imagePaths, + onDeleteRuleConditionAction: onDeleteRuleConditionAction, + forwardEmailEditingController: forwardEmailEditingController, + forwardEmailFocusNode: forwardEmailFocusNode, + onChangeForwardEmail: onChangeForwardEmail, + ), + ); + + if (!isMobile) { + return bodyWidget; + } + return Slidable( enabled: responsiveUtils.isMobile(context) ? true : false, endActionPane: ActionPane( @@ -55,13 +97,13 @@ class RuleFilterActionWidget extends StatelessWidget { topRight: Radius.circular(RuleFilterActionStyles.mainBorderRadius), bottomRight: Radius.circular(RuleFilterActionStyles.mainBorderRadius), ), - onPressed: (_) => tapRemoveCallback!(), + onPressed: (_) => onDeleteRuleConditionAction(), backgroundColor: AppColor.colorBackgroundFieldConditionRulesFilter, child: CircleAvatar( backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, radius: RuleFilterActionStyles.removeButtonRadius, child: SvgPicture.asset( - imagePaths!.icMinimize, + imagePaths.icMinimize, fit: BoxFit.fill, colorFilter: AppColor.colorDeletePermanentlyButton.asFilter(), ), @@ -106,7 +148,7 @@ class RuleFilterActionWidget extends StatelessWidget { errorValue: errorValue, tapActionDetailedCallback: tapActionDetailedCallback, imagePaths: imagePaths, - tapRemoveActionCallback: tapRemoveCallback, + onDeleteRuleConditionAction: onDeleteRuleConditionAction, forwardEmailEditingController: forwardEmailEditingController, forwardEmailFocusNode: forwardEmailFocusNode, onChangeForwardEmail: onChangeForwardEmail, diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart index 39c4661b7..73ffe0e2b 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart @@ -50,10 +50,7 @@ class RuleFilterButtonField extends StatelessWidget { child: Row(children: [ Expanded(child: Text( _getName(context, value), - style: ThemeUtils.defaultTextStyleInterFont.copyWith( - fontSize: 16, - fontWeight: FontWeight.normal, - color: textColor), + style: ThemeUtils.textStyleBodyBody3(color: textColor), maxLines: 1, softWrap: CommonTextStyle.defaultSoftWrap, overflow: CommonTextStyle.defaultTextOverFlow, 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 deleted file mode 100644 index bdae64bba..000000000 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_condition_remove_button_builder.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:core/presentation/resources/image_paths.dart'; -import 'package:core/presentation/views/button/tmail_button_widget.dart'; -import 'package:flutter/material.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 TMailButtonWidget.fromIcon( - icon: imagePath!.icRemoveRule, - backgroundColor: Colors.transparent, - padding: EdgeInsets.zero, - onTapActionCallback: tapRemoveRuleFilterConditionCallback, - ); - } -} \ 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 index 549c4feac..7318ddfa4 100644 --- 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 @@ -1,123 +1,139 @@ +import 'package:core/core.dart'; import 'package:core/presentation/resources/image_paths.dart'; import 'package:core/presentation/utils/keyboard_utils.dart'; +import 'package:core/presentation/utils/theme_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/default_field/default_input_field_widget.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: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/rule_filter_delete_button_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'; class RuleFilterConditionRow extends StatelessWidget { final RuleFilterConditionScreenType? ruleFilterConditionScreenType; final RuleCondition ruleCondition; + final ImagePaths imagePaths; + final OnDeleteRuleConditionAction onDeleteRuleConditionAction; final Function(Field?)? tapRuleConditionFieldCallback; final Function(Comparator?)? tapRuleConditionComparatorCallback; final String? conditionValueErrorText; - final TextEditingController? conditionValueEditingController; + final TextEditingController textEditingController; final FocusNode? conditionValueFocusNode; final OnChangeFilterInputAction? conditionValueOnChangeAction; - final Function()? tapRemoveRuleFilterConditionCallback; - final ImagePaths? imagePaths; const RuleFilterConditionRow({ Key? key, required this.ruleFilterConditionScreenType, required this.ruleCondition, + required this.imagePaths, + required this.textEditingController, + required this.onDeleteRuleConditionAction, 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, + case RuleFilterConditionScreenType.mobile: + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + RuleFilterButtonField( + value: ruleCondition.field, tapActionCallback: (value) { KeyboardUtils.hideKeyboard(context); - tapRuleConditionComparatorCallback!(ruleCondition.comparator); + tapRuleConditionFieldCallback!(ruleCondition.field); }, - ) - ), - RulesFilterInputField( - hintText: AppLocalizations.of(context).conditionValueHintTextInput, - errorText: conditionValueErrorText, - focusNode: conditionValueFocusNode, - onChangeAction: conditionValueOnChangeAction, - editingController: conditionValueEditingController, - ), - ], - ); + ), + 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: textEditingController, + ), + ], + ); case RuleFilterConditionScreenType.tablet: case RuleFilterConditionScreenType.desktop: return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ + const SizedBox(width: 12), Expanded( child: DropDownButtonWidget( items: rule_condition.Field.values, itemSelected: ruleCondition.field, dropdownMaxHeight: 250, + heightItem: 40, + labelTextStyle: ThemeUtils.textStyleBodyBody3( + color: Colors.black, + ), + hintTextStyle: ThemeUtils.textStyleBodyBody3( + color: AppColor.steelGray400, + ), onChanged: (newField) => { tapRuleConditionFieldCallback!(newField) }, supportSelectionIcon: true, ) ), - Container( - width: 220, - padding: const EdgeInsets.symmetric(horizontal: 12), + const SizedBox(width: 8), + Expanded( child: DropDownButtonWidget( items: rule_condition.Comparator.values, itemSelected: ruleCondition.comparator, + heightItem: 40, + labelTextStyle: ThemeUtils.textStyleBodyBody3( + color: Colors.black, + ), + hintTextStyle: ThemeUtils.textStyleBodyBody3( + color: AppColor.steelGray400, + ), onChanged: (newComparator) => { tapRuleConditionComparatorCallback!(newComparator) }, supportSelectionIcon: true, ) ), + const SizedBox(width: 8), Expanded( - child: RulesFilterInputField( + child: DefaultInputFieldWidget( hintText: AppLocalizations.of(context).conditionValueHintTextInput, errorText: conditionValueErrorText, focusNode: conditionValueFocusNode, - onChangeAction: conditionValueOnChangeAction, - editingController: conditionValueEditingController, - ) + inputColor: Colors.black, + onTextChange: conditionValueOnChangeAction, + textEditingController: textEditingController, + ), ), - Container( - padding: const EdgeInsetsDirectional.only(start: 12), - alignment: Alignment.center, - child: RuleFilterConditionRemoveButton( - tapRemoveRuleFilterConditionCallback: tapRemoveRuleFilterConditionCallback, - imagePath: imagePaths, - ) + RuleFilterDeleteButtonWidget( + imagePaths: imagePaths, + margin: const EdgeInsetsDirectional.only(top: 2), + onDeleteRuleConditionAction: onDeleteRuleConditionAction, ), ], ); default: - return const SizedBox.shrink(); + 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 7f89ca92d..2b056f07e 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 @@ -4,6 +4,7 @@ import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_svg/flutter_svg.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'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_delete_button_widget.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:core/presentation/resources/image_paths.dart'; @@ -11,31 +12,57 @@ import 'package:core/presentation/resources/image_paths.dart'; class RuleFilterConditionWidget extends StatelessWidget { final RuleFilterConditionScreenType? ruleFilterConditionScreenType; final RuleCondition ruleCondition; + final TextEditingController textEditingController; 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()? tapRemoveRuleFilterConditionCallback; + final ImagePaths imagePaths; + final OnDeleteRuleConditionAction onDeleteRuleConditionAction; const RuleFilterConditionWidget({ super.key, this.ruleFilterConditionScreenType, required this.ruleCondition, + required this.imagePaths, + required this.textEditingController, + required this.onDeleteRuleConditionAction, this.tapRuleConditionFieldCallback, this.tapRuleConditionComparatorCallback, this.conditionValueErrorText, - this.conditionValueEditingController, this.conditionValueFocusNode, this.conditionValueOnChangeAction, - this.imagePaths, - this.tapRemoveRuleFilterConditionCallback, }); @override Widget build(BuildContext context) { + Widget bodyWidget = Container( + padding: const EdgeInsetsDirectional.symmetric(vertical: 12), + margin: const EdgeInsetsDirectional.only(top: 8), + decoration: const BoxDecoration( + color: AppColor.lightGrayF9FAFB, + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + alignment: Alignment.center, + child: RuleFilterConditionRow( + ruleFilterConditionScreenType: ruleFilterConditionScreenType, + ruleCondition: ruleCondition, + tapRuleConditionFieldCallback: tapRuleConditionFieldCallback, + tapRuleConditionComparatorCallback: tapRuleConditionComparatorCallback, + conditionValueErrorText: conditionValueErrorText, + textEditingController: textEditingController, + conditionValueFocusNode: conditionValueFocusNode, + conditionValueOnChangeAction: conditionValueOnChangeAction, + onDeleteRuleConditionAction: onDeleteRuleConditionAction, + imagePaths: imagePaths, + ), + ); + + if (ruleFilterConditionScreenType != RuleFilterConditionScreenType.mobile) { + return bodyWidget; + } + return Slidable( enabled: ruleFilterConditionScreenType == RuleFilterConditionScreenType.mobile ? true : false, endActionPane: ActionPane( @@ -45,13 +72,13 @@ class RuleFilterConditionWidget extends StatelessWidget { CustomSlidableAction( padding: const EdgeInsets.only(right: 12), borderRadius: const BorderRadius.only(topRight: Radius.circular(12), bottomRight: Radius.circular(12)), - onPressed: (_) => tapRemoveRuleFilterConditionCallback!(), + onPressed: (_) => onDeleteRuleConditionAction(), backgroundColor: AppColor.colorBackgroundFieldConditionRulesFilter, child: CircleAvatar( backgroundColor: AppColor.colorRemoveRuleFilterConditionButton, radius: 110, child: SvgPicture.asset( - imagePaths!.icMinimize, + imagePaths.icMinimize, fit: BoxFit.fill, colorFilter: AppColor.colorDeletePermanentlyButton.asFilter(), ), @@ -59,40 +86,10 @@ class RuleFilterConditionWidget extends StatelessWidget { ) ] ), - 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: RuleFilterConditionRow( - ruleFilterConditionScreenType: ruleFilterConditionScreenType, - ruleCondition: ruleCondition, - tapRuleConditionFieldCallback: tapRuleConditionFieldCallback, - tapRuleConditionComparatorCallback: tapRuleConditionComparatorCallback, - conditionValueErrorText: conditionValueErrorText, - conditionValueEditingController: conditionValueEditingController, - conditionValueFocusNode: conditionValueFocusNode, - conditionValueOnChangeAction: conditionValueOnChangeAction, - tapRemoveRuleFilterConditionCallback: tapRemoveRuleFilterConditionCallback, - imagePaths: imagePaths, - ) - ); - } - ); - }) + child: ValueListenableBuilder( + valueListenable: Slidable.of(context)?.direction ?? ValueNotifier(0), + builder: (_, __, ___) => bodyWidget, + ), ); - } } \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_delete_button_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_delete_button_widget.dart new file mode 100644 index 000000000..f720ee455 --- /dev/null +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_delete_button_widget.dart @@ -0,0 +1,31 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/resources/image_paths.dart'; +import 'package:core/presentation/views/button/tmail_button_widget.dart'; +import 'package:flutter/material.dart'; + +typedef OnDeleteRuleConditionAction = Function(); + +class RuleFilterDeleteButtonWidget extends StatelessWidget { + final ImagePaths imagePaths; + final OnDeleteRuleConditionAction onDeleteRuleConditionAction; + final EdgeInsetsGeometry? margin; + + const RuleFilterDeleteButtonWidget({ + Key? key, + required this.imagePaths, + required this.onDeleteRuleConditionAction, + this.margin, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return TMailButtonWidget.fromIcon( + icon: imagePaths.icDeleteComposer, + iconSize: 20, + iconColor: AppColor.steelGrayA540, + backgroundColor: Colors.transparent, + margin: margin, + onTapActionCallback: onDeleteRuleConditionAction, + ); + } +} \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_list_action_widget.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_list_action_widget.dart new file mode 100644 index 000000000..69e17cfed --- /dev/null +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_list_action_widget.dart @@ -0,0 +1,58 @@ +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:core/presentation/views/dialog/confirm_dialog_button.dart'; +import 'package:flutter/material.dart'; + +class RuleFilterListActionWidget extends StatelessWidget { + final String positiveLabel; + final String negativeLabel; + final VoidCallback onNegativeAction; + final VoidCallback onPositiveAction; + final EdgeInsetsGeometry? padding; + + const RuleFilterListActionWidget({ + super.key, + required this.positiveLabel, + required this.negativeLabel, + required this.onPositiveAction, + required this.onNegativeAction, + this.padding, + }); + + @override + Widget build(BuildContext context) { + Widget negativeButton = Container( + constraints: const BoxConstraints(minWidth: 67), + height: 48, + child: ConfirmDialogButton( + label: negativeLabel, + onTapAction: onNegativeAction, + ), + ); + + Widget positiveButton = Container( + constraints: const BoxConstraints(minWidth: 143), + height: 48, + child: ConfirmDialogButton( + label: positiveLabel, + backgroundColor: AppColor.primaryMain, + textColor: Colors.white, + onTapAction: onPositiveAction, + ), + ); + + Widget bodyWidget = Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Flexible(child: negativeButton), + const SizedBox(width: 8), + Flexible(child: positiveButton), + ], + ); + + if (padding != null) { + return Padding(padding: padding!, child: bodyWidget); + } else { + return bodyWidget; + } + } +} \ No newline at end of file diff --git a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_title_builder.dart b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_title_builder.dart index 615b6989b..08063ff47 100644 --- a/lib/features/rules_filter_creator/presentation/widgets/rule_filter_title_builder.dart +++ b/lib/features/rules_filter_creator/presentation/widgets/rule_filter_title_builder.dart @@ -1,71 +1,87 @@ +import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/utils/keyboard_utils.dart'; -import 'package:core/presentation/utils/style_utils.dart'; +import 'package:core/presentation/utils/responsive_utils.dart'; +import 'package:core/presentation/utils/theme_utils.dart'; import 'package:flutter/material.dart'; import 'package:rule_filter/rule_filter/rule_condition_group.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:tmail_ui_user/features/rules_filter_creator/presentation/styles/rule_filter_title_styles.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/widgets/rule_filter_button_field.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; -typedef OnTapActionCallback = Function(ConditionCombiner? value); +typedef OnTapActionCallback = Function( + ConditionCombiner? value, +); class RuleFilterTitle extends StatelessWidget { - final ConditionCombiner? conditionCombinerType; final OnTapActionCallback? tapActionCallback; final RuleFilterConditionScreenType ruleFilterConditionScreenType; + final ResponsiveUtils responsiveUtils; const RuleFilterTitle({ Key? key, required this.ruleFilterConditionScreenType, + required this.responsiveUtils, this.conditionCombinerType, this.tapActionCallback, }) : super(key: key); @override Widget build(BuildContext context) { + final appLocalizations = AppLocalizations.of(context); + final isMobile = responsiveUtils.isMobile(context); - return Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, + return Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + runAlignment: WrapAlignment.center, + runSpacing: 8, children: [ Text( - AppLocalizations.of(context).conditionTitleRulesFilterBeforeCombiner, - overflow: CommonTextStyle.defaultTextOverFlow, - softWrap: CommonTextStyle.defaultSoftWrap, - maxLines: RuleFilterTitleStyles.textMaxLines, - style: RuleFilterTitleStyles.textStyle, + appLocalizations.conditionTitleRulesFilterBeforeCombiner, + style: ThemeUtils.textStyleInter400.copyWith( + fontSize: 14, + height: 18 / 14, + color: Colors.black, + ), ), Container( - padding: const EdgeInsets.symmetric(horizontal: RuleFilterTitleStyles.combinerTypeSelectionAreaPadding), - width: RuleFilterTitleStyles.combinerTypeSelectionAreaWith, - child: ruleFilterConditionScreenType == RuleFilterConditionScreenType.mobile + padding: const EdgeInsets.symmetric(horizontal: 12), + width: isMobile ? double.infinity : 158, + child: ruleFilterConditionScreenType == + RuleFilterConditionScreenType.mobile ? RuleFilterButtonField( - value: conditionCombinerType, - tapActionCallback: (value) { - KeyboardUtils.hideKeyboard(context); - tapActionCallback?.call(value); - }, - ) + value: conditionCombinerType, + tapActionCallback: (value) { + KeyboardUtils.hideKeyboard(context); + tapActionCallback?.call(value); + }, + ) : DropDownButtonWidget( - items: ConditionCombiner.values, - itemSelected: conditionCombinerType, - supportSelectionIcon: true, - onChanged: (value) { - KeyboardUtils.hideKeyboard(context); - tapActionCallback?.call(value); - }, - ), + items: ConditionCombiner.values, + itemSelected: conditionCombinerType, + supportSelectionIcon: true, + labelTextStyle: ThemeUtils.textStyleBodyBody3( + color: Colors.black, + ), + hintTextStyle: ThemeUtils.textStyleBodyBody3( + color: AppColor.steelGray400, + ), + onChanged: (value) { + KeyboardUtils.hideKeyboard(context); + tapActionCallback?.call(value); + }, + ), ), - Expanded( - child: Text( - AppLocalizations.of(context).conditionTitleRulesFilterAfterCombiner, - overflow: CommonTextStyle.defaultTextOverFlow, - style: RuleFilterTitleStyles.textStyle, + Text( + appLocalizations.conditionTitleRulesFilterAfterCombiner, + style: ThemeUtils.textStyleInter400.copyWith( + fontSize: 14, + height: 18 / 14, + color: Colors.black, ), ) - ] + ], ); } } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 0dd510f57..be8e55886 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -4723,5 +4723,47 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "createANewRule": "Create a New Rule", + "@createANewRule": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "ruleName": "Rule Name", + "@ruleName": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "condition": "Condition", + "@condition": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "addACondition": "Add a condition", + "@addACondition": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "actionsToPerform": "Actions to Perform", + "@actionsToPerform": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "addAnAction": "Add an action", + "@addAnAction": { + "type": "text", + "placeholders_order": [], + "placeholders": {} + }, + "createRule": "Create Rule", + "@createRule": { + "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 81e3d215a..02b1e07dd 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -4985,4 +4985,53 @@ class AppLocalizations { name: 'createMyFirstRule', ); } + + String get createANewRule { + return Intl.message( + 'Create a New Rule', + name: 'createANewRule', + ); + } + + String get ruleName { + return Intl.message( + 'Rule Name', + name: 'ruleName', + ); + } + + String get condition { + return Intl.message( + 'Condition', + name: 'condition', + ); + } + + String get addACondition { + return Intl.message( + 'Add a condition', + name: 'addACondition', + ); + } + + String get actionsToPerform { + return Intl.message( + 'Actions to Perform', + name: 'actionsToPerform', + ); + } + + String get addAnAction { + return Intl.message( + 'Add an action', + name: 'addAnAction', + ); + } + + String get createRule { + return Intl.message( + 'Create Rule', + name: 'createRule', + ); + } }