diff --git a/assets/images/ic_quick_creating_rule.svg b/assets/images/ic_quick_creating_rule.svg new file mode 100644 index 000000000..02f1b4e6f --- /dev/null +++ b/assets/images/ic_quick_creating_rule.svg @@ -0,0 +1,4 @@ + + + + diff --git a/core/lib/presentation/resources/image_paths.dart b/core/lib/presentation/resources/image_paths.dart index 0d342569d..d6e315a2c 100644 --- a/core/lib/presentation/resources/image_paths.dart +++ b/core/lib/presentation/resources/image_paths.dart @@ -175,6 +175,7 @@ class ImagePaths { String get icQuotas => _getImagePath('ic_quotas.svg'); String get icQuotasWarning => _getImagePath('ic_quotas_warning.svg'); String get icQuotasOutOfStorage => _getImagePath('ic_quotas_out_of_storage.svg'); + String get icQuickCreatingRule => _getImagePath('ic_quick_creating_rule.svg'); String _getImagePath(String imageName) { return AssetsPaths.images + imageName; diff --git a/lib/features/base/base_controller.dart b/lib/features/base/base_controller.dart index d280a04ea..2b945113a 100644 --- a/lib/features/base/base_controller.dart +++ b/lib/features/base/base_controller.dart @@ -8,12 +8,14 @@ import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/core/capability/capability_identifier.dart'; import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:rule_filter/rule_filter/capability_rule_filter.dart'; import 'package:tmail_ui_user/features/base/mixin/message_dialog_action_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/popup_context_menu_action_mixin.dart'; import 'package:tmail_ui_user/features/base/mixin/view_as_dialog_action_mixin.dart'; import 'package:tmail_ui_user/features/email/presentation/mdn_interactor_bindings.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/contact_autocomplete_bindings.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/bindings/tmail_autocomplete_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/bindings/email_rules_interactor_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/forward/bindings/forwarding_interactors_bindings.dart'; import 'package:tmail_ui_user/main/error/capability_validator.dart'; import 'package:tmail_ui_user/main/exceptions/remote_exception.dart'; @@ -129,4 +131,13 @@ abstract class BaseController extends GetxController logError('ReloadableController::injectForwardBindings(): exception: $e'); } } + + void injectRuleFilterBindings(Session? session, AccountId? accountId) { + try { + requireCapability(session!, accountId!, [capabilityRuleFilter]); + EmailRulesInteractorBindings().dependencies(); + } catch(e) { + logError('ReloadableController::injectRuleFilterBindings(): exception: $e'); + } + } } \ No newline at end of file diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index c5012b92a..13f4e07ec 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -55,9 +55,13 @@ import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_action import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/download/download_task_state.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/model/create_new_email_rule_filter_request.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/state/create_new_rule_filter_state.dart'; import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_identities_state.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_email_rule_filter_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_identities_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/extensions/datetime_extension.dart'; +import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart'; import 'package:tmail_ui_user/features/thread/domain/constants/thread_constants.dart'; import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -85,6 +89,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { final DownloadAttachmentForWebInteractor _downloadAttachmentForWebInteractor; final GetAllIdentitiesInteractor _getAllIdentitiesInteractor; + CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor; SendReceiptToSenderInteractor? _sendReceiptToSenderInteractor; final emailAddressExpandMode = ExpandMode.COLLAPSE.obs; @@ -126,6 +131,14 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _initializeDebounceTimeIndexPageViewChange(); _initWorker(); _listenDownloadAttachmentProgressState(); + injectRuleFilterBindings( + emailSupervisorController.sessionCurrent, + emailSupervisorController.accountId); + try { + _createNewEmailRuleFilterInteractor = Get.find(); + } catch (e) { + logError('SingleEmailController::onInit(): ${e.toString()}'); + } super.onInit(); } @@ -138,7 +151,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { try { _sendReceiptToSenderInteractor = Get.find(); } catch (e) { - logError('EmailController::onReady(): SendReceiptToSenderInteractor not registered'); + logError('SingleEmailController::onReady(): SendReceiptToSenderInteractor not registered'); } super.onReady(); } @@ -161,7 +174,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void _initWorker() { emailWorker = ever(emailSupervisorController.selectedEmail, (presentationEmail) { - log('EmailController::_initWorker(): $presentationEmail'); + log('SingleEmailController::_initWorker(): $presentationEmail'); if (presentationEmail is PresentationEmail) { if (_currentEmailId != presentationEmail.id) { _currentEmailId = presentationEmail.id; @@ -185,7 +198,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void _listenDownloadAttachmentProgressState() { downloadProgressState.listen((state) { - log('EmailController::_listenDownloadAttachmentProgressState(): $state'); + log('SingleEmailController::_listenDownloadAttachmentProgressState(): $state'); state.fold( (failure) => null, (success) { @@ -203,7 +216,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } } else if (success is DownloadingAttachmentForWeb) { final percent = success.progress.round(); - log('EmailController::DownloadingAttachmentForWeb(): $percent%'); + log('SingleEmailController::DownloadingAttachmentForWeb(): $percent%'); emailSupervisorController.mailboxDashBoardController.updateDownloadTask( success.taskId, @@ -234,7 +247,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { .firstWhere((identity) => identity.mayDelete == false); _identitySelected = identityDefault; } catch (e) { - logError('EmailController::_getAllIdentitiesSuccess(): ${e.toString()}'); + logError('SingleEmailController::_getAllIdentitiesSuccess(): ${e.toString()}'); _identitySelected = success.identities!.first; } } @@ -290,6 +303,8 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _getAllIdentitiesSuccess(success); } else if (success is SendReceiptToSenderSuccess) { _sendReceiptToSenderSuccess(success); + } else if (success is CreateNewRuleFilterSuccess) { + _createNewRuleFilterSuccess(success); } }); } @@ -479,7 +494,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _openDownloadedPreviewWorkGroupDocument(DownloadedResponse downloadedResponse) async { - log('EmailController::_openDownloadedPreviewWorkGroupDocument(): $downloadedResponse'); + log('SingleEmailController::_openDownloadedPreviewWorkGroupDocument(): $downloadedResponse'); if (downloadedResponse.mediaType == null) { await share_library.Share.shareFiles([downloadedResponse.filePath]); } @@ -490,7 +505,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { uti: Platform.isIOS ? downloadedResponse.mediaType!.getDocumentUti().value : null); if (openResult.type != open_file.ResultType.done) { - logError('EmailController::_openDownloadedPreviewWorkGroupDocument(): no preview available'); + logError('SingleEmailController::_openDownloadedPreviewWorkGroupDocument(): no preview available'); if (currentContext != null) { _appToast.showErrorToast(AppLocalizations.of(currentContext!).noPreviewAvailable); } @@ -516,7 +531,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _downloadAttachmentForWebSuccessAction(DownloadAttachmentForWebSuccess success) { - log('EmailController::_downloadAttachmentForWebSuccessAction():'); + log('SingleEmailController::_downloadAttachmentForWebSuccessAction():'); mailboxDashBoardController.deleteDownloadTask(success.taskId); _downloadManager.createAnchorElementDownloadFileWeb( @@ -525,7 +540,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _downloadAttachmentForWebFailureAction(DownloadAttachmentForWebFailure failure) { - log('EmailController::_downloadAttachmentForWebFailureAction(): $failure'); + log('SingleEmailController::_downloadAttachmentForWebFailureAction(): $failure'); mailboxDashBoardController.deleteDownloadTask(failure.taskId); if (currentOverlayContext != null && currentContext != null) { @@ -772,22 +787,25 @@ class SingleEmailController extends BaseController with AppLoaderMixin { void openEmailAddressDialog(BuildContext context, EmailAddress emailAddress) { if (responsiveUtils.isScreenWithShortestSide(context)) { (EmailAddressBottomSheetBuilder(context, imagePaths, emailAddress) - ..addOnCloseContextMenuAction(() => popBack()) - ..addOnCopyEmailAddressAction((emailAddress) => copyEmailAddress(context, emailAddress)) - ..addOnComposeEmailAction((emailAddress) => composeEmailFromEmailAddress(emailAddress))) - .show(); + ..addOnCloseContextMenuAction(() => popBack()) + ..addOnCopyEmailAddressAction((emailAddress) => copyEmailAddress(context, emailAddress)) + ..addOnComposeEmailAction((emailAddress) => composeEmailFromEmailAddress(emailAddress)) + ..addOnQuickCreatingRuleEmailBottomSheetAction((emailAddress) => quickCreatingRule(context, emailAddress)) + ).show(); } else { showDialog( - context: context, - barrierColor: AppColor.colorDefaultCupertinoActionSheet, - builder: (BuildContext context) => PointerInterceptor( - child: EmailAddressDialogBuilder( - emailAddress, - onCloseDialogAction: () => popBack(), - onCopyEmailAddressAction: (emailAddress) => - copyEmailAddress(context, emailAddress), - onComposeEmailAction: (emailAddress) => - composeEmailFromEmailAddress(emailAddress)))); + context: context, + barrierColor: AppColor.colorDefaultCupertinoActionSheet, + builder: (BuildContext context) => PointerInterceptor( + child: EmailAddressDialogBuilder( + emailAddress, + onCloseDialogAction: () => popBack(), + onCopyEmailAddressAction: (emailAddress) => copyEmailAddress(context, emailAddress), + onComposeEmailAction: (emailAddress) => composeEmailFromEmailAddress(emailAddress), + onQuickCreatingRuleEmailDialogAction: (emailAddress) => quickCreatingRule(context, emailAddress) + ) + ) + ); } } @@ -813,9 +831,9 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void openMailToLink(Uri? uri) { - log('EmailController::openMailToLink(): ${uri.toString()}'); + log('SingleEmailController::openMailToLink(): ${uri.toString()}'); String address = uri?.path ?? ''; - log('EmailController::openMailToLink(): address: $address'); + log('SingleEmailController::openMailToLink(): address: $address'); if (address.isNotEmpty) { final emailAddress = EmailAddress(null, address); final arguments = ComposerArguments( @@ -920,7 +938,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { mdn: mdnToSender, identityId: _identitySelected!.id!, sendId: Id(_uuid.v1())); - log('EmailController::_handleSendReceiptToSenderAction(): sendReceiptRequest: $sendReceiptRequest'); + log('SingleEmailController::_handleSendReceiptToSenderAction(): sendReceiptRequest: $sendReceiptRequest'); consumeState(_sendReceiptToSenderInteractor!.execute(accountId, sendReceiptRequest)); } @@ -948,7 +966,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } void _sendReceiptToSenderSuccess(SendReceiptToSenderSuccess success) { - log('EmailController::_sendReceiptToSenderSuccess(): ${success.mdn.toString()}'); + log('SingleEmailController::_sendReceiptToSenderSuccess(): ${success.mdn.toString()}'); if (currentContext != null) { _appToast.showBottomToast( currentOverlayContext!, @@ -997,4 +1015,63 @@ class SingleEmailController extends BaseController with AppLoaderMixin { mailboxDashBoardController.goToComposer(arguments); } } + + void quickCreatingRule(BuildContext context, EmailAddress emailAddress) async { + popBack(); + + final accountId = mailboxDashBoardController.accountId.value; + final session = mailboxDashBoardController.sessionCurrent; + if (accountId != null && session != null) { + final arguments = RulesFilterCreatorArguments( + accountId, + session, + emailAddress: emailAddress); + + if (BuildUtils.isWeb) { + showDialogRuleFilterCreator( + context: context, + arguments: arguments, + onCreatedRuleFilter: (arguments) { + if (arguments is CreateNewEmailRuleFilterRequest) { + _createNewRuleFilterAction(accountId, arguments); + } + } + ); + } else { + final newRuleFilterRequest = await push( + AppRoutes.rulesFilterCreator, + arguments: arguments + ); + + if (newRuleFilterRequest is CreateNewEmailRuleFilterRequest) { + _createNewRuleFilterAction(accountId, newRuleFilterRequest); + } + } + } + } + + void _createNewRuleFilterAction( + AccountId accountId, + CreateNewEmailRuleFilterRequest ruleFilterRequest + ) async { + try { + _createNewEmailRuleFilterInteractor = Get.find(); + } catch (e) { + logError('SingleEmailController::onInit(): ${e.toString()}'); + } + if (_createNewEmailRuleFilterInteractor != null) { + consumeState(_createNewEmailRuleFilterInteractor!.execute(accountId, ruleFilterRequest)); + } + } + + void _createNewRuleFilterSuccess(CreateNewRuleFilterSuccess success) { + if (success.newListRules.isNotEmpty == true) { + if (currentOverlayContext != null && currentContext != null) { + _appToast.showToastWithIcon( + currentOverlayContext!, + message: AppLocalizations.of(currentContext!).newFilterWasCreated, + icon: imagePaths.icSelected); + } + } + } } \ No newline at end of file diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index e82409d54..0340bf368 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -746,21 +746,27 @@ class EmailView extends GetWidget { return [ _markAsEmailUnreadAction(context, email), _markAsEmailSpamOrUnSpamAction(context, email), + _quickCreatingRuleAction(context, email), ]; } Widget _markAsEmailUnreadAction(BuildContext context, PresentationEmail email) { return (EmailActionCupertinoActionSheetActionBuilder( const Key('mark_as_unread_action'), - SvgPicture.asset(imagePaths.icUnreadEmail, width: 28, height: 28, fit: BoxFit.fill, color: AppColor.colorTextButton), + SvgPicture.asset( + imagePaths.icUnreadEmail, + width: 24, + height: 24, + fit: BoxFit.fill, + color: AppColor.colorTextButton), AppLocalizations.of(context).mark_as_unread, email, iconLeftPadding: responsiveUtils.isMobile(context) - ? const EdgeInsets.only(left: 12, right: 16) - : const EdgeInsets.only(right: 12), + ? const EdgeInsets.only(left: 12, right: 16) + : const EdgeInsets.only(right: 12), iconRightPadding: responsiveUtils.isMobile(context) - ? const EdgeInsets.only(right: 12) - : EdgeInsets.zero) + ? const EdgeInsets.only(right: 12) + : EdgeInsets.zero) ..onActionClick((email) => controller.handleEmailAction(context, email, EmailActionType.markAsUnread))) .build(); } @@ -771,100 +777,127 @@ class EmailView extends GetWidget { return (EmailActionCupertinoActionSheetActionBuilder( const Key('mark_as_spam_or_un_spam_action'), SvgPicture.asset( - currentMailbox?.isSpam == true ? imagePaths.icNotSpam : imagePaths.icMailboxSpam, - width: 28, height: 28, fit: BoxFit.fill, color: AppColor.colorTextButton), + currentMailbox?.isSpam == true ? imagePaths.icNotSpam : imagePaths.icMailboxSpam, + width: 24, + height: 24, + fit: BoxFit.fill, + color: AppColor.colorTextButton), currentMailbox?.isSpam == true - ? AppLocalizations.of(context).remove_from_spam - : AppLocalizations.of(context).mark_as_spam, + ? AppLocalizations.of(context).remove_from_spam + : AppLocalizations.of(context).mark_as_spam, email, iconLeftPadding: responsiveUtils.isMobile(context) - ? const EdgeInsets.only(left: 12, right: 16) - : const EdgeInsets.only(right: 12), + ? const EdgeInsets.only(left: 12, right: 16) + : const EdgeInsets.only(right: 12), iconRightPadding: responsiveUtils.isMobile(context) - ? const EdgeInsets.only(right: 12) - : EdgeInsets.zero) + ? const EdgeInsets.only(right: 12) + : EdgeInsets.zero) ..onActionClick((email) => controller.handleEmailAction(context, email, currentMailbox?.isSpam == true ? EmailActionType.unSpam : EmailActionType.moveToSpam))) .build(); } + Widget _quickCreatingRuleAction(BuildContext context, PresentationEmail email) { + return (EmailActionCupertinoActionSheetActionBuilder( + const Key('quick_creating_rule_action'), + SvgPicture.asset( + imagePaths.icQuickCreatingRule, + width: 24, + height: 24, + fit: BoxFit.fill, + color: AppColor.colorTextButton), + AppLocalizations.of(context).quickCreatingRule, + email, + iconLeftPadding: responsiveUtils.isMobile(context) + ? const EdgeInsets.only(left: 12, right: 16) + : const EdgeInsets.only(right: 12), + iconRightPadding: responsiveUtils.isMobile(context) + ? const EdgeInsets.only(right: 12) + : EdgeInsets.zero) + ..onActionClick((email) => controller.quickCreatingRule(context, email.from!.first))) + .build(); + } + List _popupMenuEmailActionTile(BuildContext context, PresentationEmail email) { return [ PopupMenuItem( - padding: EdgeInsets.zero, - child: _markAsEmailUnreadPopupItemAction(context, email)), + padding: EdgeInsets.zero, + child: _markAsEmailUnreadPopupItemAction(context, email)), PopupMenuItem( - padding: EdgeInsets.zero, - child: _markAsEmailSpamOrUnSpamPopupItemAction(context, email)), + padding: EdgeInsets.zero, + child: _markAsEmailSpamOrUnSpamPopupItemAction(context, email)), + PopupMenuItem( + padding: EdgeInsets.zero, + child: _quickCreatingRulePopupItemAction(context, email)), ]; } Widget _markAsEmailUnreadPopupItemAction(BuildContext context, PresentationEmail email) { - return InkWell( - onTap: () => controller.handleEmailAction(context, email, EmailActionType.markAsUnread), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: SizedBox( - width: 383, - height: 56, - child: Row(children: [ - SvgPicture.asset( - imagePaths.icUnreadEmail, - width: 24, - height: 24, - color: AppColor.colorTextButton, - fit: BoxFit.fill), - const SizedBox(width: 12), - Expanded(child: Text( - AppLocalizations.of(context).mark_as_unread, - style: const TextStyle( - fontSize: 16, - color: Colors.black, - fontWeight: FontWeight.w500) - )), - ]) - ), - ) + return _popupMenuItem( + icon: imagePaths.icUnreadEmail, + title: AppLocalizations.of(context).mark_as_unread, + onTapCallback: () => controller.handleEmailAction(context, email, EmailActionType.markAsUnread) ); } Widget _markAsEmailSpamOrUnSpamPopupItemAction(BuildContext context, PresentationEmail email) { final currentMailbox = controller.getMailboxContain(email); - return InkWell( - onTap: () => controller.handleEmailAction( - context, - email, - currentMailbox?.isSpam == true - ? EmailActionType.unSpam - : EmailActionType.moveToSpam), + return _popupMenuItem( + icon: currentMailbox?.isSpam == true + ? imagePaths.icNotSpam + : imagePaths.icMailboxSpam, + title: currentMailbox?.isSpam == true + ? AppLocalizations.of(context).remove_from_spam + : AppLocalizations.of(context).mark_as_spam, + onTapCallback: () => controller.handleEmailAction( + context, + email, + currentMailbox?.isSpam == true ? EmailActionType.unSpam : EmailActionType.moveToSpam) + ); + } + + Widget _quickCreatingRulePopupItemAction(BuildContext context, PresentationEmail email) { + return _popupMenuItem( + icon: imagePaths.icQuickCreatingRule, + title: AppLocalizations.of(context).quickCreatingRule, + onTapCallback: () => controller.quickCreatingRule(context, email.from!.first) + ); + } + + Widget _popupMenuItem({ + required String icon, + required String title, + Function()? onTapCallback + }) { + return Material( + color: Colors.transparent, + child: InkWell( + onTap: onTapCallback, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: SizedBox( - width: 383, - height: 56, - child: Row(children: [ - SvgPicture.asset( - currentMailbox?.isSpam == true - ? imagePaths.icNotSpam - : imagePaths.icMailboxSpam, - width: 24, - height: 24, - color: AppColor.colorTextButton, - fit: BoxFit.fill), - const SizedBox(width: 12), - Expanded(child: Text( - currentMailbox?.isSpam == true - ? AppLocalizations.of(context).remove_from_spam - : AppLocalizations.of(context).mark_as_spam, - style: const TextStyle( - fontSize: 16, - color: Colors.black, - fontWeight: FontWeight.w500) - )), - ]) + width: 300, + height: 44, + child: Row(children: [ + SvgPicture.asset( + icon, + width: 20, + height: 20, + color: AppColor.colorTextButton, + fit: BoxFit.fill), + const SizedBox(width: 12), + Expanded(child: Text( + title, + style: const TextStyle( + fontSize: 15, + color: Colors.black, + fontWeight: FontWeight.normal) + )), + ]) ), ) + ), ); } } \ No newline at end of file diff --git a/lib/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart b/lib/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart index 92e81c102..d28da2244 100644 --- a/lib/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart +++ b/lib/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart @@ -11,6 +11,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; typedef OnCloseBottomSheetAction = void Function(); typedef OnCopyEmailAddressBottomSheetAction = void Function(EmailAddress); typedef OnComposeEmailBottomSheetAction = void Function(EmailAddress); +typedef OnQuickCreatingRuleEmailBottomSheetAction = void Function(EmailAddress); class EmailAddressBottomSheetBuilder { @@ -21,6 +22,7 @@ class EmailAddressBottomSheetBuilder { OnCloseBottomSheetAction? _onCloseBottomSheetAction; OnCopyEmailAddressBottomSheetAction? _onCopyEmailAddressAction; OnComposeEmailBottomSheetAction? _onComposeEmailAction; + OnQuickCreatingRuleEmailBottomSheetAction? _creatingRuleEmailBottomSheetAction; EmailAddressBottomSheetBuilder( this._context, @@ -40,6 +42,10 @@ class EmailAddressBottomSheetBuilder { _onComposeEmailAction = onComposeEmailAction; } + void addOnQuickCreatingRuleEmailBottomSheetAction(OnQuickCreatingRuleEmailBottomSheetAction creatingRuleEmailBottomSheetAction) { + _creatingRuleEmailBottomSheetAction = creatingRuleEmailBottomSheetAction; + } + RoundedRectangleBorder _shape() { return const RoundedRectangleBorder( borderRadius: BorderRadius.only( @@ -132,28 +138,54 @@ class EmailAddressBottomSheetBuilder { onPressed: () => _onCopyEmailAddressAction?.call(_emailAddress) ) ), - SizedBox(height: _emailAddress.displayName.isNotEmpty ? 100 : 130), + const SizedBox(height: 24), Padding( - padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20), + padding: const EdgeInsets.only(left: 24, right: 24, bottom: 12), + child: SizedBox( + key: const Key('quick_creating_rule_email_button'), + width: double.infinity, + height: 44, + child: TextButton( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.resolveWith( + (Set states) => AppColor.colorTextButton), + backgroundColor: MaterialStateProperty.resolveWith( + (Set states) => AppColor.colorItemEmailSelectedDesktop), + shape: MaterialStateProperty.all(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: const BorderSide( + width: 0, + color: AppColor.colorItemEmailSelectedDesktop)))), + child: Text( + AppLocalizations.of(_context).quickCreatingRule, + style: const TextStyle( + fontSize: 17, + color: AppColor.colorTextButton, + fontWeight: FontWeight.w500)), + onPressed: () => _creatingRuleEmailBottomSheetAction?.call(_emailAddress)), + ) + ), + Padding( + padding: const EdgeInsets.only(left: 24, right: 24, bottom: 24), child: SizedBox( key: const Key('compose_email_button'), width: double.infinity, - height: 48, - child: ElevatedButton( + height: 44, + child: TextButton( style: ButtonStyle( foregroundColor: MaterialStateProperty.resolveWith( (Set states) => Colors.white), backgroundColor: MaterialStateProperty.resolveWith( (Set states) => AppColor.colorTextButton), shape: MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(8), side: const BorderSide( width: 0, color: AppColor.colorTextButton)))), child: Text( AppLocalizations.of(_context).compose_email, style: const TextStyle( - fontSize: 16, + fontSize: 17, color: Colors.white, fontWeight: FontWeight.w500)), onPressed: () => _onComposeEmailAction?.call(_emailAddress)), diff --git a/lib/features/email/presentation/widgets/email_address_dialog_builder.dart b/lib/features/email/presentation/widgets/email_address_dialog_builder.dart index 3d0223b85..3ef759c70 100644 --- a/lib/features/email/presentation/widgets/email_address_dialog_builder.dart +++ b/lib/features/email/presentation/widgets/email_address_dialog_builder.dart @@ -10,6 +10,7 @@ import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; typedef OnCloseDialogAction = void Function(); typedef OnCopyEmailAddressDialogAction = void Function(EmailAddress); typedef OnComposeEmailDialogAction = void Function(EmailAddress); +typedef OnQuickCreatingRuleEmailDialogAction = void Function(EmailAddress); class EmailAddressDialogBuilder extends StatelessWidget { @@ -17,6 +18,7 @@ class EmailAddressDialogBuilder extends StatelessWidget { final OnCloseDialogAction? onCloseDialogAction; final OnCopyEmailAddressDialogAction? onCopyEmailAddressAction; final OnComposeEmailDialogAction? onComposeEmailAction; + final OnQuickCreatingRuleEmailDialogAction? onQuickCreatingRuleEmailDialogAction; const EmailAddressDialogBuilder( this._emailAddress, { @@ -24,6 +26,7 @@ class EmailAddressDialogBuilder extends StatelessWidget { this.onCloseDialogAction, this.onCopyEmailAddressAction, this.onComposeEmailAction, + this.onQuickCreatingRuleEmailDialogAction, }) : super(key: key); @override @@ -43,7 +46,8 @@ class EmailAddressDialogBuilder extends StatelessWidget { decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(16))), - child: Wrap( + child: Column( + mainAxisSize: MainAxisSize.min, children: [ Align( alignment: Alignment.centerRight, @@ -115,28 +119,54 @@ class EmailAddressDialogBuilder extends StatelessWidget { onPressed: () => onCopyEmailAddressAction?.call(_emailAddress) ) ))), - SizedBox(height: _emailAddress.displayName.isNotEmpty ? 100 : 130), + const SizedBox(height: 24), Padding( - padding: const EdgeInsets.only(left: 16, right: 16, bottom: 20), + padding: const EdgeInsets.only(left: 24, right: 24, bottom: 12), + child: SizedBox( + key: const Key('quick_creating_rule_email_button'), + width: double.infinity, + height: 44, + child: TextButton( + style: ButtonStyle( + foregroundColor: MaterialStateProperty.resolveWith( + (Set states) => AppColor.colorTextButton), + backgroundColor: MaterialStateProperty.resolveWith( + (Set states) => AppColor.colorItemEmailSelectedDesktop), + shape: MaterialStateProperty.all(RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: const BorderSide( + width: 0, + color: AppColor.colorItemEmailSelectedDesktop)))), + child: Text( + AppLocalizations.of(context).quickCreatingRule, + style: const TextStyle( + fontSize: 17, + color: AppColor.colorTextButton, + fontWeight: FontWeight.w500)), + onPressed: () => onQuickCreatingRuleEmailDialogAction?.call(_emailAddress)), + ) + ), + Padding( + padding: const EdgeInsets.only(left: 24, right: 24, bottom: 24), child: SizedBox( key: const Key('compose_email_button'), width: double.infinity, - height: 48, - child: ElevatedButton( + height: 44, + child: TextButton( style: ButtonStyle( foregroundColor: MaterialStateProperty.resolveWith( (Set states) => Colors.white), backgroundColor: MaterialStateProperty.resolveWith( (Set states) => AppColor.colorTextButton), shape: MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(8), side: const BorderSide( width: 0, color: AppColor.colorTextButton)))), child: Text( AppLocalizations.of(context).compose_email, style: const TextStyle( - fontSize: 16, + fontSize: 17, color: Colors.white, fontWeight: FontWeight.w500)), onPressed: () => onComposeEmailAction?.call(_emailAddress)), diff --git a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart index 839e91eae..fad66a1b4 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -329,6 +329,7 @@ class MailboxDashBoardController extends ReloadableController { accountId.value = sessionCurrent?.accounts.keys.first; _getUserProfile(); injectAutoCompleteBindings(sessionCurrent, accountId.value); + injectRuleFilterBindings(sessionCurrent, accountId.value); injectVacationBindings(sessionCurrent, accountId.value); _getVacationResponse(); } else { @@ -1021,6 +1022,7 @@ class MailboxDashBoardController extends ReloadableController { _getUserProfile(); _handleComposerCache(); injectAutoCompleteBindings(sessionCurrent, accountId.value); + injectRuleFilterBindings(sessionCurrent, accountId.value); injectVacationBindings(sessionCurrent, accountId.value); _getVacationResponse(); } diff --git a/lib/features/manage_account/presentation/email_rules/bindings/email_rules_bindings.dart b/lib/features/manage_account/presentation/email_rules/bindings/email_rules_bindings.dart new file mode 100644 index 000000000..5cc5569a7 --- /dev/null +++ b/lib/features/manage_account/presentation/email_rules/bindings/email_rules_bindings.dart @@ -0,0 +1,10 @@ +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/email_rules_controller.dart'; + +class EmailRulesBindings extends Bindings { + + @override + void dependencies() { + Get.lazyPut(() => EmailRulesController()); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/email_rules/bindings/email_rules_interactor_bindings.dart b/lib/features/manage_account/presentation/email_rules/bindings/email_rules_interactor_bindings.dart new file mode 100644 index 000000000..6f7f73ae4 --- /dev/null +++ b/lib/features/manage_account/presentation/email_rules/bindings/email_rules_interactor_bindings.dart @@ -0,0 +1,45 @@ +import 'package:get/get.dart'; +import 'package:tmail_ui_user/features/base/interactors_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/data/datasource/rule_filter_datasource.dart'; +import 'package:tmail_ui_user/features/manage_account/data/datasource_impl/rule_filter_datasource_impl.dart'; +import 'package:tmail_ui_user/features/manage_account/data/network/rule_filter_api.dart'; +import 'package:tmail_ui_user/features/manage_account/data/repository/rule_filter_repository_impl.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/repository/rule_filter_repository.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/delete_email_rule_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_email_rule_filter_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/edit_email_rule_filter_interactor.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_rules_interactor.dart'; +import 'package:tmail_ui_user/main/exceptions/remote_exception_thrower.dart'; + +class EmailRulesInteractorBindings extends InteractorsBindings { + + @override + void bindingsDataSource() { + Get.lazyPut(() => Get.find()); + } + + @override + void bindingsDataSourceImpl() { + Get.lazyPut(() => RuleFilterDataSourceImpl( + Get.find(), + Get.find())); + } + + @override + void bindingsInteractor() { + Get.lazyPut(() => GetAllRulesInteractor(Get.find())); + Get.lazyPut(() => DeleteEmailRuleInteractor(Get.find())); + Get.lazyPut(() => CreateNewEmailRuleFilterInteractor(Get.find())); + Get.lazyPut(() => EditEmailRuleFilterInteractor(Get.find())); + } + + @override + void bindingsRepository() { + Get.lazyPut(() => Get.find()); + } + + @override + void bindingsRepositoryImpl() { + Get.lazyPut(() => RuleFilterRepositoryImpl(Get.find())); + } +} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/email_rules/email_rules_bindings.dart b/lib/features/manage_account/presentation/email_rules/email_rules_bindings.dart deleted file mode 100644 index ef7e2c51d..000000000 --- a/lib/features/manage_account/presentation/email_rules/email_rules_bindings.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:get/get.dart'; -import 'package:tmail_ui_user/features/base/base_bindings.dart'; -import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; -import 'package:tmail_ui_user/features/manage_account/domain/usecases/delete_email_rule_interactor.dart'; -import 'package:tmail_ui_user/features/manage_account/domain/usecases/create_new_email_rule_filter_interactor.dart'; -import 'package:tmail_ui_user/features/manage_account/domain/usecases/edit_email_rule_filter_interactor.dart'; -import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_rules_interactor.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/email_rules_controller.dart'; - -class EmailRulesBindings extends BaseBindings { - - @override - void bindingsController() { - Get.lazyPut(() => EmailRulesController( - Get.find(), - Get.find(), - Get.find(), - Get.find(), - )); - } - - @override - void bindingsDataSource() {} - - @override - void bindingsDataSourceImpl() {} - - @override - void bindingsInteractor() { - Get.lazyPut(() => GetAllRulesInteractor(Get.find())); - Get.lazyPut(() => DeleteEmailRuleInteractor(Get.find())); - Get.lazyPut(() => CreateNewEmailRuleFilterInteractor(Get.find())); - Get.lazyPut(() => EditEmailRuleFilterInteractor(Get.find())); - } - - @override - void bindingsRepository() {} - - @override - void bindingsRepositoryImpl() {} -} \ No newline at end of file diff --git a/lib/features/manage_account/presentation/email_rules/email_rules_controller.dart b/lib/features/manage_account/presentation/email_rules/email_rules_controller.dart index 78557ec1d..5dbf62b0a 100644 --- a/lib/features/manage_account/presentation/email_rules/email_rules_controller.dart +++ b/lib/features/manage_account/presentation/email_rules/email_rules_controller.dart @@ -4,6 +4,7 @@ import 'package:core/presentation/utils/app_toast.dart'; import 'package:core/presentation/utils/responsive_utils.dart'; import 'package:core/presentation/views/bottom_popup/confirmation_dialog_action_sheet_builder.dart'; import 'package:core/presentation/views/dialog/confirmation_dialog_builder.dart'; +import 'package:core/utils/app_logger.dart'; import 'package:core/utils/build_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -33,10 +34,10 @@ import 'package:tmail_ui_user/main/routes/app_routes.dart'; class EmailRulesController extends BaseController { - final GetAllRulesInteractor _getAllRulesInteractor; - final DeleteEmailRuleInteractor _deleteEmailRuleInteractor; - final CreateNewEmailRuleFilterInteractor _createNewEmailRuleFilterInteractor; - final EditEmailRuleFilterInteractor _editEmailRuleFilterInteractor; + GetAllRulesInteractor? _getAllRulesInteractor; + DeleteEmailRuleInteractor? _deleteEmailRuleInteractor; + CreateNewEmailRuleFilterInteractor? _createNewEmailRuleFilterInteractor; + EditEmailRuleFilterInteractor? _editEmailRuleFilterInteractor; final _accountDashBoardController = Get.find(); final _imagePaths = Get.find(); @@ -45,12 +46,7 @@ class EmailRulesController extends BaseController { final listEmailRule = [].obs; - EmailRulesController( - this._getAllRulesInteractor, - this._deleteEmailRuleInteractor, - this._createNewEmailRuleFilterInteractor, - this._editEmailRuleFilterInteractor, - ); + EmailRulesController(); @override void onDone() { @@ -71,16 +67,28 @@ class EmailRulesController extends BaseController { @override void onInit() { - _getAllRules(); super.onInit(); + try { + _getAllRulesInteractor = Get.find(); + _deleteEmailRuleInteractor = Get.find(); + _createNewEmailRuleFilterInteractor = Get.find(); + _editEmailRuleFilterInteractor = Get.find(); + } catch (e) { + logError('EmailRulesController::onInit(): ${e.toString()}'); + } + } + + @override + void onReady() { + _getAllRules(); + super.onReady(); } void goToCreateNewRule(BuildContext context) async { final accountId = _accountDashBoardController.accountId.value; - if (accountId != null) { - final arguments = RulesFilterCreatorArguments( - accountId, - listEmailRule: listEmailRule); + final session = _accountDashBoardController.sessionCurrent.value; + if (accountId != null && session != null) { + final arguments = RulesFilterCreatorArguments(accountId, session); if (BuildUtils.isWeb) { showDialogRuleFilterCreator( @@ -107,9 +115,9 @@ class EmailRulesController extends BaseController { AccountId accountId, CreateNewEmailRuleFilterRequest ruleFilterRequest ) async { - consumeState(_createNewEmailRuleFilterInteractor.execute( - accountId, - ruleFilterRequest)); + if (_createNewEmailRuleFilterInteractor != null) { + consumeState(_createNewEmailRuleFilterInteractor!.execute(accountId, ruleFilterRequest)); + } } void _createNewRuleFilterSuccess(CreateNewRuleFilterSuccess success) { @@ -127,12 +135,13 @@ class EmailRulesController extends BaseController { void editEmailRule(BuildContext context, TMailRule rule) async { final accountId = _accountDashBoardController.accountId.value; - if (accountId != null) { + final session = _accountDashBoardController.sessionCurrent.value; + if (accountId != null && session != null) { final arguments = RulesFilterCreatorArguments( accountId, + session, actionType: CreatorActionType.edit, - tMailRule: rule, - listEmailRule: listEmailRule); + tMailRule: rule); if (BuildUtils.isWeb) { showDialogRuleFilterCreator( @@ -159,7 +168,9 @@ class EmailRulesController extends BaseController { AccountId accountId, EditEmailRuleFilterRequest ruleFilterRequest ) { - consumeState(_editEmailRuleFilterInteractor.execute(accountId, ruleFilterRequest)); + if (_editEmailRuleFilterInteractor != null) { + consumeState(_editEmailRuleFilterInteractor!.execute(accountId, ruleFilterRequest)); + } } void _editEmailRuleFilterSuccess(EditEmailRuleFilterSuccess success) { @@ -214,13 +225,16 @@ class EmailRulesController extends BaseController { void _handleDeleteEmailRuleAction(TMailRule emailRule) { popBack(); - final deleteEmailRuleRequest = DeleteEmailRuleRequest( - emailRuleDelete : emailRule, - currentEmailRules: listEmailRule, - ); - consumeState(_deleteEmailRuleInteractor.execute( + if (_deleteEmailRuleInteractor != null) { + final deleteEmailRuleRequest = DeleteEmailRuleRequest( + emailRuleDelete : emailRule, + currentEmailRules: listEmailRule, + ); + + consumeState(_deleteEmailRuleInteractor!.execute( _accountDashBoardController.accountId.value!, deleteEmailRuleRequest)); + } } void _handleDeleteEmailRuleSuccess(DeleteEmailRuleSuccess success) { @@ -239,7 +253,9 @@ class EmailRulesController extends BaseController { } void _getAllRules() { - consumeState(_getAllRulesInteractor.execute(_accountDashBoardController.accountId.value!)); + if (_getAllRulesInteractor != null) { + consumeState(_getAllRulesInteractor!.execute(_accountDashBoardController.accountId.value!)); + } } void openEditRuleMenuAction(BuildContext context, TMailRule rule) { diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart b/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart index 36c82e03d..53191d1ce 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_bindings.dart @@ -21,7 +21,6 @@ import 'package:tmail_ui_user/features/login/domain/usecases/get_stored_token_oi import 'package:tmail_ui_user/features/manage_account/data/datasource/manage_account_datasource.dart'; import 'package:tmail_ui_user/features/manage_account/data/datasource_impl/manage_account_datasource_impl.dart'; import 'package:tmail_ui_user/features/manage_account/data/local/language_cache_manager.dart'; -import 'package:tmail_ui_user/features/manage_account/data/network/manage_account_api.dart'; import 'package:tmail_ui_user/features/manage_account/data/repository/manage_account_repository_impl.dart'; import 'package:tmail_ui_user/features/manage_account/domain/repository/manage_account_repository.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; @@ -73,7 +72,6 @@ class ManageAccountDashBoardBindings extends BaseBindings { Get.find() )); Get.lazyPut(() => ManageAccountDataSourceImpl( - Get.find(), Get.find(), Get.find())); } diff --git a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart index a799f4023..db2c89ca5 100644 --- a/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart +++ b/lib/features/manage_account/presentation/manage_account_dashboard_controller.dart @@ -22,7 +22,7 @@ import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_va import 'package:tmail_ui_user/features/manage_account/domain/usecases/log_out_oidc_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/domain/usecases/update_vacation_interactor.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/action/dashboard_setting_action.dart'; -import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/email_rules_bindings.dart'; +import 'package:tmail_ui_user/features/manage_account/presentation/email_rules/bindings/email_rules_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/forward/bindings/forward_bindings.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/model/account_menu_item.dart'; @@ -95,6 +95,7 @@ class ManageAccountDashBoardController extends ReloadableController { _getUserProfile(); injectAutoCompleteBindings(sessionCurrent.value, accountId.value); injectForwardBindings(sessionCurrent.value, accountId.value); + injectRuleFilterBindings(sessionCurrent.value, accountId.value); injectVacationBindings(sessionCurrent.value, accountId.value); _getVacationResponse(); } @@ -108,6 +109,7 @@ class ManageAccountDashBoardController extends ReloadableController { _getUserProfile(); injectAutoCompleteBindings(sessionCurrent.value, accountId.value); injectForwardBindings(sessionCurrent.value, accountId.value); + injectRuleFilterBindings(sessionCurrent.value, accountId.value); injectVacationBindings(sessionCurrent.value, accountId.value); _getVacationResponse(); if (arguments.menuSettingCurrent != null) { diff --git a/lib/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart b/lib/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart index 8dc74bfba..b3a2b15cf 100644 --- a/lib/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart +++ b/lib/features/rules_filter_creator/presentation/model/rules_filter_creator_arguments.dart @@ -1,21 +1,24 @@ import 'package:equatable/equatable.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:rule_filter/rule_filter/tmail_rule.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/creator_action_type.dart'; class RulesFilterCreatorArguments with EquatableMixin { final AccountId accountId; + final Session session; final CreatorActionType actionType; final TMailRule? tMailRule; - final List? listEmailRule; + final EmailAddress? emailAddress; - RulesFilterCreatorArguments(this.accountId, { + RulesFilterCreatorArguments(this.accountId, this.session, { this.actionType = CreatorActionType.create, this.tMailRule, - this.listEmailRule + this.emailAddress }); @override - List get props => [accountId, actionType, tMailRule]; + List get props => [accountId, actionType, session, tMailRule, emailAddress]; } \ No newline at end of file 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 e561a5058..d2fe570c0 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 @@ -3,12 +3,16 @@ import 'package:core/presentation/extensions/color_extension.dart'; import 'package:core/presentation/state/failure.dart'; import 'package:core/presentation/state/success.dart'; import 'package:core/presentation/utils/app_toast.dart'; +import 'package:core/utils/app_logger.dart'; import 'package:core/utils/build_utils.dart'; import 'package:dartz/dartz.dart'; import 'package:flutter/cupertino.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; +import 'package:jmap_dart_client/jmap/core/session/session.dart'; +import 'package:jmap_dart_client/jmap/mail/email/email_address.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; +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; @@ -25,6 +29,8 @@ import 'package:tmail_ui_user/features/mailbox_creator/presentation/extensions/v import 'package:tmail_ui_user/features/manage_account/data/extensions/list_tmail_rule_extensions.dart'; import 'package:tmail_ui_user/features/manage_account/domain/model/create_new_email_rule_filter_request.dart'; import 'package:tmail_ui_user/features/manage_account/domain/model/edit_email_rule_filter_request.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/state/get_all_rules_state.dart'; +import 'package:tmail_ui_user/features/manage_account/domain/usecases/get_all_rules_interactor.dart'; import 'package:tmail_ui_user/features/rules_filter_creator/presentation/model/creator_action_type.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/rules_filter_creator_arguments.dart'; @@ -41,6 +47,8 @@ class RulesFilterCreatorController extends BaseMailboxController { final VerifyNameInteractor _verifyNameInteractor; final GetAllMailboxInteractor _getAllMailboxInteractor; + GetAllRulesInteractor? _getAllRulesInteractor; + final errorRuleName = Rxn(); final errorRuleConditionValue = Rxn(); final errorRuleActionValue = Rxn(); @@ -62,7 +70,9 @@ class RulesFilterCreatorController extends BaseMailboxController { OnCreatedRuleFilterCallback? onCreatedRuleFilterCallback; VoidCallback? onDismissRuleFilterCreator; AccountId? _accountId; + Session? _session; TMailRule? _currentTMailRule; + EmailAddress? _emailAddress; List? _listEmailRule; RulesFilterCreatorController( @@ -78,6 +88,7 @@ class RulesFilterCreatorController extends BaseMailboxController { inputConditionValueController = TextEditingController(); inputRuleNameFocusNode = FocusNode(); inputRuleConditionFocusNode = FocusNode(); + } @override @@ -85,10 +96,18 @@ class RulesFilterCreatorController extends BaseMailboxController { super.onReady(); if (arguments != null) { _accountId = arguments!.accountId; + _session = arguments!.session; _currentTMailRule = arguments!.tMailRule; - _listEmailRule = arguments!.listEmailRule; + _emailAddress = arguments!.emailAddress; actionType.value = arguments!.actionType; + injectRuleFilterBindings(_session, _accountId); + try { + _getAllRulesInteractor = Get.find(); + } catch (e) { + logError('RulesFilterCreatorController::onInit(): ${e.toString()}'); + } _setUpDefaultValueRuleFilter(); + _getAllRules(); } } @@ -99,7 +118,16 @@ class RulesFilterCreatorController extends BaseMailboxController { } @override - void onDone() {} + void onDone() { + viewState.value.fold((failure) {}, (success) { + if (success is GetAllRulesSuccess) { + log('RulesFilterCreatorController::onDone():GetAllRulesSuccess: ${success.rules}'); + if (success.rules?.isNotEmpty == true) { + _listEmailRule = success.rules!; + } + } + }); + } @override void onData(Either newState) { @@ -114,12 +142,22 @@ class RulesFilterCreatorController extends BaseMailboxController { }); } + void _getAllRules() { + if (_accountId != null && _getAllRulesInteractor != null) { + consumeState(_getAllRulesInteractor!.execute(_accountId!)); + } + } + void _setUpDefaultValueRuleFilter() { switch(actionType.value) { case CreatorActionType.create: ruleConditionFieldSelected.value = rule_condition.Field.from; ruleConditionComparatorSelected.value = rule_condition.Comparator.contains; emailRuleFilterActionSelected.value = EmailRuleFilterAction.moveMessage; + if (_emailAddress != null) { + _newRuleConditionValue = _emailAddress?.email; + _setValueInputField(inputConditionValueController, _newRuleConditionValue ?? ''); + } break; case CreatorActionType.edit: if (_currentTMailRule != null) { 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 d1fb715bf..4c4b6390c 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 @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; 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: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'; @@ -42,79 +43,81 @@ class RuleFilterCreatorView extends GetWidget { @override Widget build(BuildContext context) { - return ResponsiveWidget( - responsiveUtils: _responsiveUtils, - mobile: Scaffold( - backgroundColor: BuildUtils.isWeb - ? Colors.black.withAlpha(24) - : Colors.black38, - body: GestureDetector( - onTap: () => FocusScope.of(context).unfocus(), - child: SafeArea( - bottom: false, - left: false, - right: false, - child: Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16)), - color: Colors.white), - margin: const EdgeInsets.only(top: BuildUtils.isWeb ? 70 : 0), - child: ClipRRect( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16)), - child: SafeArea(child: _buildRulesFilterFormOnMobile(context)) - ) - ), - ), - ) - ), - tablet: Scaffold( - backgroundColor: Colors.black.withAlpha(24), - body: GestureDetector( - onTap: () => FocusScope.of(context).unfocus(), - child: Align(alignment: Alignment.bottomCenter, child: Container( - decoration: const BoxDecoration( - color: Colors.white, + return PointerInterceptor( + child: ResponsiveWidget( + responsiveUtils: _responsiveUtils, + mobile: Scaffold( + backgroundColor: BuildUtils.isWeb + ? Colors.black.withAlpha(24) + : Colors.black38, + body: GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: SafeArea( + bottom: false, + left: false, + right: false, + child: Container( + decoration: const BoxDecoration( borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - )), - width: double.infinity, - height: _responsiveUtils.getSizeScreenHeight(context) * 0.7, - child: ClipRRect( - borderRadius: const BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16)), - child: _buildRulesFilterFormOnTablet(context) - ) - )), - ) - ), - desktop: Scaffold( - backgroundColor: Colors.black.withAlpha(24), - body: GestureDetector( - onTap: () => FocusScope.of(context).unfocus(), - child: Center(child: Card( - color: Colors.transparent, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(16))), - child: Container( - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.all(Radius.circular(16))), - width: _responsiveUtils.getSizeScreenWidth(context) * 0.6, - height: _responsiveUtils.getSizeScreenHeight(context) * 0.7, - child: ClipRRect( - borderRadius: const BorderRadius.all(Radius.circular(16)), - child: _buildRulesFilterFormOnDesktop(context) - ) - ) - )), - ) - ) + color: Colors.white), + margin: const EdgeInsets.only(top: BuildUtils.isWeb ? 70 : 0), + child: ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16)), + child: SafeArea(child: _buildRulesFilterFormOnMobile(context)) + ) + ), + ), + ) + ), + tablet: Scaffold( + backgroundColor: Colors.black.withAlpha(24), + body: GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: Align(alignment: Alignment.bottomCenter, child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + )), + width: double.infinity, + height: _responsiveUtils.getSizeScreenHeight(context) * 0.7, + child: ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16)), + child: _buildRulesFilterFormOnTablet(context) + ) + )), + ) + ), + desktop: Scaffold( + backgroundColor: Colors.black.withAlpha(24), + body: GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: Center(child: Card( + color: Colors.transparent, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(16))), + child: Container( + decoration: const BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(16))), + width: _responsiveUtils.getSizeScreenWidth(context) * 0.6, + height: _responsiveUtils.getSizeScreenHeight(context) * 0.7, + child: ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(16)), + child: _buildRulesFilterFormOnDesktop(context) + ) + ) + )), + ) + ) + ), ); } diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index c7f16973c..c7e0e0cfc 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2022-11-10T15:16:34.946211", + "@@last_modified": "2022-11-11T04:08:42.994169", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -2497,5 +2497,11 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "quickCreatingRule": "Create a rule with this email", + "@quickCreatingRule": { + "type": "text", + "placeholders_order": [], + "placeholders": {} } } \ No newline at end of file diff --git a/lib/main/bindings/network/network_bindings.dart b/lib/main/bindings/network/network_bindings.dart index 7ededc3c8..4d65efc5b 100644 --- a/lib/main/bindings/network/network_bindings.dart +++ b/lib/main/bindings/network/network_bindings.dart @@ -19,7 +19,7 @@ import 'package:tmail_ui_user/features/login/data/utils/library_platform/app_aut import 'package:tmail_ui_user/features/mailbox/data/network/mailbox_api.dart'; import 'package:tmail_ui_user/features/manage_account/data/network/forwarding_api.dart'; import 'package:tmail_ui_user/features/manage_account/data/network/identity_api.dart'; -import 'package:tmail_ui_user/features/manage_account/data/network/manage_account_api.dart'; +import 'package:tmail_ui_user/features/manage_account/data/network/rule_filter_api.dart'; import 'package:tmail_ui_user/features/manage_account/data/network/vacation_api.dart'; import 'package:tmail_ui_user/features/quotas/data/network/quotas_api.dart'; import 'package:tmail_ui_user/features/session/data/network/session_api.dart'; @@ -81,7 +81,7 @@ class NetworkBindings extends Bindings { Get.find(), Get.find(), Get.find())); - Get.put(ManageAccountAPI(Get.find())); + Get.put(RuleFilterAPI(Get.find())); Get.put(VacationAPI(Get.find())); Get.put(ContactAPI(Get.find())); Get.put(IdentityAPI(Get.find())); diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 3cb27478a..bd0a60262 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -2563,4 +2563,10 @@ class AppLocalizations { name: 'textQuotasRunOutOfStorageContent', ); } + + String get quickCreatingRule { + return Intl.message( + 'Create a rule with this email', + name: 'quickCreatingRule'); + } } \ No newline at end of file