diff --git a/core/lib/presentation/extensions/color_extension.dart b/core/lib/presentation/extensions/color_extension.dart index e8cb7cca8..52317dee6 100644 --- a/core/lib/presentation/extensions/color_extension.dart +++ b/core/lib/presentation/extensions/color_extension.dart @@ -231,6 +231,7 @@ extension AppColor on Color { static const colorDropDownItemTitleComposer = Color(0xFF0A0A0A); static const messageDialogColor = Color(0xFF8C9CAF); static const messageDialogHighlightColor = Color(0xFF37383A); + static const labelColor = Color(0xFF71767C); static const mapGradientColor = [ [Color(0xFF21D4FD), Color(0xFFB721FF)], diff --git a/lib/features/composer/domain/model/email_request.dart b/lib/features/composer/domain/model/email_request.dart index e340b19aa..9528e6a7b 100644 --- a/lib/features/composer/domain/model/email_request.dart +++ b/lib/features/composer/domain/model/email_request.dart @@ -14,6 +14,7 @@ class EmailRequest with EquatableMixin { final IdentityId? identityId; final EmailActionType emailActionType; final String? storedSendingId; + final EmailId? previousEmailId; EmailRequest({ required this.email, @@ -23,6 +24,7 @@ class EmailRequest with EquatableMixin { this.emailIdDestroyed, this.emailIdAnsweredOrForwarded, this.storedSendingId, + this.previousEmailId, }); @override @@ -34,6 +36,7 @@ class EmailRequest with EquatableMixin { emailIdAnsweredOrForwarded, emailActionType, storedSendingId, + previousEmailId, ]; bool get isEmailAnswered => emailIdAnsweredOrForwarded != null && diff --git a/lib/features/composer/domain/state/send_email_state.dart b/lib/features/composer/domain/state/send_email_state.dart index 973ea5056..3aa23b7f0 100644 --- a/lib/features/composer/domain/state/send_email_state.dart +++ b/lib/features/composer/domain/state/send_email_state.dart @@ -12,18 +12,18 @@ class SendEmailLoading extends UIState {} class SendEmailSuccess extends UIActionState { - final String? storedSendingId; + final EmailRequest emailRequest; SendEmailSuccess({ jmap.State? currentEmailState, jmap.State? currentMailboxState, - this.storedSendingId, + required this.emailRequest, }) : super(currentEmailState, currentMailboxState); @override List get props => [ ...super.props, - storedSendingId, + emailRequest, ]; } diff --git a/lib/features/composer/domain/usecases/send_email_interactor.dart b/lib/features/composer/domain/usecases/send_email_interactor.dart index 52913e888..092ee78c0 100644 --- a/lib/features/composer/domain/usecases/send_email_interactor.dart +++ b/lib/features/composer/domain/usecases/send_email_interactor.dart @@ -52,7 +52,7 @@ class SendEmailInteractor { SendEmailSuccess( currentEmailState: currentEmailState, currentMailboxState: currentMailboxState, - storedSendingId: emailRequest.storedSendingId + emailRequest: emailRequest ) ); } else { diff --git a/lib/features/composer/presentation/composer_controller.dart b/lib/features/composer/presentation/composer_controller.dart index 51b2ed04d..b6c981c59 100644 --- a/lib/features/composer/presentation/composer_controller.dart +++ b/lib/features/composer/presentation/composer_controller.dart @@ -489,9 +489,7 @@ class ComposerController extends BaseController { isInitialRecipient.value = true; toAddressExpandMode.value = ExpandMode.COLLAPSE; } - if (arguments.body?.isNotEmpty == true) { - _getEmailContentFromMailtoUri(arguments.body!); - } + _getEmailContentFromMailtoUri(arguments.body ?? ''); _updateStatusEmailSendButton(); break; case EmailActionType.reply: @@ -537,9 +535,7 @@ class ComposerController extends BaseController { isInitialRecipient.value = true; toAddressExpandMode.value = ExpandMode.COLLAPSE; } - if (arguments.body?.isNotEmpty == true) { - _getEmailContentFromUnsubscribeMailtoLink(arguments.body!); - } + _getEmailContentFromUnsubscribeMailtoLink(arguments.body ?? ''); _updateStatusEmailSendButton(); break; default: @@ -969,7 +965,8 @@ class ComposerController extends BaseController { ? arguments.presentationEmail?.id : null, emailIdAnsweredOrForwarded: arguments.presentationEmail?.id, - emailActionType: arguments.emailActionType + emailActionType: arguments.emailActionType, + previousEmailId: arguments.previousEmailId, ); final mailboxRequest = mailboxDashBoardController.outboxMailbox?.id == null diff --git a/lib/features/email/presentation/controller/single_email_controller.dart b/lib/features/email/presentation/controller/single_email_controller.dart index e01462beb..f95a40d7d 100644 --- a/lib/features/email/presentation/controller/single_email_controller.dart +++ b/lib/features/email/presentation/controller/single_email_controller.dart @@ -32,6 +32,7 @@ import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart'; import 'package:tmail_ui_user/features/email/domain/model/event_action.dart'; import 'package:tmail_ui_user/features/email/domain/model/mark_read_action.dart'; import 'package:tmail_ui_user/features/email/domain/state/parse_calendar_event_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/parse_calendar_event_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/store_opened_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart'; @@ -231,6 +232,14 @@ class SingleEmailController extends BaseController with AppLoaderMixin { mailboxDashBoardController.clearEmailUIAction(); } }); + + ever(mailboxDashBoardController.viewState, (viewState) { + viewState.map((success) { + if (success is UnsubscribeEmailSuccess) { + emailUnsubscribe.value = null; + } + }); + }); } bool isListEmailContainSelectedEmail(PresentationEmail selectedEmail) { @@ -441,7 +450,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _handleReadReceipt(); } - if (success.emailCurrent?.hasListUnsubscribe == true) { + if (currentEmail?.isSubscribed == false && success.emailCurrent?.hasListUnsubscribe == true) { _handleUnsubscribe(success.emailCurrent!.listUnsubscribe); } else { emailUnsubscribe.value = null; @@ -501,7 +510,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin { _handleReadReceipt(); } - if (success.emailCurrent?.hasListUnsubscribe == true) { + if (currentEmail?.isSubscribed == false && success.emailCurrent?.hasListUnsubscribe == true) { _handleUnsubscribe(success.emailCurrent!.listUnsubscribe); } else { emailUnsubscribe.value = null; @@ -951,11 +960,9 @@ class SingleEmailController extends BaseController with AppLoaderMixin { } } - void _markAsEmailStarSuccess(Success success) { - if (success is MarkAsStarEmailSuccess) { - final selectedEmail = mailboxDashBoardController.selectedEmail.value; - mailboxDashBoardController.setSelectedEmail(selectedEmail?.updateKeywords(success.updatedEmail.keywords)); - } + void _markAsEmailStarSuccess(MarkAsStarEmailSuccess success) { + final selectedEmail = mailboxDashBoardController.selectedEmail.value; + mailboxDashBoardController.setSelectedEmail(selectedEmail?.updateKeywords(success.updatedEmail.keywords)); mailboxDashBoardController.dispatchState(Right(success)); } @@ -1406,9 +1413,17 @@ class SingleEmailController extends BaseController with AppLoaderMixin { AppLocalizations.of(context).unsubscribe, onConfirmAction: () { if (emailUnsubscribe.value?.httpLinks.isNotEmpty == true) { - _handleUnsubscribeMailByHttpsLink(context, emailUnsubscribe.value!.httpLinks); + _handleUnsubscribeMailByHttpsLink( + context: context, + emailId: presentationEmail.id!, + httpLinks: emailUnsubscribe.value!.httpLinks + ); } else if (emailUnsubscribe.value?.mailtoLinks.isNotEmpty == true) { - _handleUnsubscribeMailByMailtoLink(context, emailUnsubscribe.value!.mailtoLinks); + _handleUnsubscribeMailByMailtoLink( + context: context, + emailId: presentationEmail.id!, + mailtoLinks: emailUnsubscribe.value!.mailtoLinks + ); } }, showAsBottomSheet: true, @@ -1434,24 +1449,29 @@ class SingleEmailController extends BaseController with AppLoaderMixin { ); } - void _handleUnsubscribeMailByHttpsLink(BuildContext context, List httpLinks) async { + void _handleUnsubscribeMailByHttpsLink({ + required BuildContext context, + required EmailId emailId, + required List httpLinks + }) { log('SingleEmailController::_handleUnsubscribeMailByHttpsLink:httpLinks: $httpLinks'); - final result = await AppUtils.launchLink(httpLinks.first); - if (result && context.mounted) { - _appToast.showToastSuccessMessage( - context, - AppLocalizations.of(context).unsubscribedFromThisMailingList); - } + mailboxDashBoardController.unsubscribeMail(emailId); + AppUtils.launchLink(httpLinks.first); } - void _handleUnsubscribeMailByMailtoLink(BuildContext context, List mailtoLinks) { + void _handleUnsubscribeMailByMailtoLink({ + required BuildContext context, + required EmailId emailId, + required List mailtoLinks + }) { log('SingleEmailController::_handleUnsubscribeMailByMailtoLink:mailtoLinks: $mailtoLinks'); final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink(mailtoLinks.first); mailboxDashBoardController.goToComposer( ComposerArguments.fromUnsubscribeMailtoLink( emailAddress: navigationRouter.emailAddress, subject: navigationRouter.subject, - body: navigationRouter.body + body: navigationRouter.body, + previousEmailId: emailId, ) ); } diff --git a/lib/features/email/presentation/email_view.dart b/lib/features/email/presentation/email_view.dart index d0df5abdd..d456475fb 100644 --- a/lib/features/email/presentation/email_view.dart +++ b/lib/features/email/presentation/email_view.dart @@ -33,6 +33,7 @@ import 'package:tmail_ui_user/features/email/presentation/widgets/email_subject_ import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_empty_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/email_view_loading_bar_widget.dart'; import 'package:tmail_ui_user/features/email/presentation/widgets/information_sender_and_receiver_builder.dart'; +import 'package:tmail_ui_user/features/email/presentation/widgets/mail_unsubscribed_banner.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/extensions/vacation_response_extension.dart'; import 'package:tmail_ui_user/features/manage_account/presentation/vacation/widgets/vacation_notification_message_widget.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; @@ -307,6 +308,10 @@ class EmailView extends GetWidget { openEmailAddressDetailAction: controller.openEmailAddressDialog, onEmailActionClick: (presentationEmail, actionType) => controller.handleEmailAction(context, presentationEmail, actionType), )), + Obx(() => MailUnsubscribedBanner( + presentationEmail: controller.currentEmail, + emailUnsubscribe: controller.emailUnsubscribe.value + )), Obx(() { final attachments = controller.attachments.listAttachmentsDisplayedOutSide; if (attachments.isNotEmpty) { @@ -432,7 +437,7 @@ class EmailView extends GetWidget { EmailActionType.moveToSpam, if (presentationEmail.from?.isNotEmpty == true) EmailActionType.createRule, - if (controller.emailUnsubscribe.value != null) + if (!presentationEmail.isSubscribed && controller.emailUnsubscribe.value != null) EmailActionType.unsubscribe ]; diff --git a/lib/features/email/presentation/model/composer_arguments.dart b/lib/features/email/presentation/model/composer_arguments.dart index 4ed2aaad7..61afabf97 100644 --- a/lib/features/email/presentation/model/composer_arguments.dart +++ b/lib/features/email/presentation/model/composer_arguments.dart @@ -21,6 +21,7 @@ class ComposerArguments extends RouterArguments { final String? body; final MessageIdsHeaderValue? messageId; final MessageIdsHeaderValue? references; + final EmailId? previousEmailId; ComposerArguments({ this.emailActionType = EmailActionType.compose, @@ -35,6 +36,7 @@ class ComposerArguments extends RouterArguments { this.body, this.messageId, this.references, + this.previousEmailId, }); factory ComposerArguments.fromSendingEmail(SendingEmail sendingEmail) => @@ -139,12 +141,18 @@ class ComposerArguments extends RouterArguments { ? SendingEmailActionType.edit : SendingEmailActionType.create; - factory ComposerArguments.fromUnsubscribeMailtoLink({EmailAddress? emailAddress, String? subject, String? body}) => + factory ComposerArguments.fromUnsubscribeMailtoLink({ + EmailAddress? emailAddress, + String? subject, + String? body, + EmailId? previousEmailId + }) => ComposerArguments( emailActionType: EmailActionType.composeFromUnsubscribeMailtoLink, emailAddress: emailAddress, subject: subject, body: body, + previousEmailId: previousEmailId, ); diff --git a/lib/features/email/presentation/widgets/information_sender_and_receiver_builder.dart b/lib/features/email/presentation/widgets/information_sender_and_receiver_builder.dart index 8f6d913df..cbc882ff4 100644 --- a/lib/features/email/presentation/widgets/information_sender_and_receiver_builder.dart +++ b/lib/features/email/presentation/widgets/information_sender_and_receiver_builder.dart @@ -63,7 +63,7 @@ class InformationSenderAndReceiverBuilder extends StatelessWidget { openEmailAddressDetailAction: openEmailAddressDetailAction, ) )), - if (emailUnsubscribe != null && !responsiveUtils.isPortraitMobile(context)) + if (!emailSelected.isSubscribed && emailUnsubscribe != null && !responsiveUtils.isPortraitMobile(context)) TMailButtonWidget.fromText( text: AppLocalizations.of(context).unsubscribe, textStyle: const TextStyle( diff --git a/lib/features/email/presentation/widgets/mail_unsubscribed_banner.dart b/lib/features/email/presentation/widgets/mail_unsubscribed_banner.dart new file mode 100644 index 000000000..1ff93c156 --- /dev/null +++ b/lib/features/email/presentation/widgets/mail_unsubscribed_banner.dart @@ -0,0 +1,36 @@ + +import 'package:core/presentation/extensions/color_extension.dart'; +import 'package:flutter/material.dart'; +import 'package:model/email/presentation_email.dart'; +import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart'; +import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; + +class MailUnsubscribedBanner extends StatelessWidget { + final PresentationEmail? presentationEmail; + final EmailUnsubscribe? emailUnsubscribe; + + const MailUnsubscribedBanner({ + super.key, + required this.presentationEmail, + this.emailUnsubscribe + }); + + @override + Widget build(BuildContext context) { + if (presentationEmail?.isSubscribed == true && emailUnsubscribe == null) { + return Padding( + padding: const EdgeInsetsDirectional.only(bottom: 16, start: 20, end: 20), + child: Text( + AppLocalizations.of(context).mailUnsubscribedMessage(presentationEmail?.firstEmailAddressInFrom ?? ''), + style: const TextStyle( + fontWeight: FontWeight.normal, + fontSize: 15, + color: AppColor.labelColor + ), + ), + ); + } else { + return const SizedBox.shrink(); + } + } +} \ No newline at end of file diff --git a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart index 0fd4b85a0..69a1c9123 100644 --- a/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart +++ b/lib/features/mailbox_dashboard/presentation/bindings/mailbox_dashboard_bindings.dart @@ -24,6 +24,7 @@ import 'package:tmail_ui_user/features/email/domain/usecases/delete_multiple_ema import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/unsubscribe_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/email_supervisor_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/controller/single_email_controller.dart'; import 'package:tmail_ui_user/features/email/presentation/bindings/email_bindings.dart'; @@ -165,6 +166,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find(), Get.find(), + Get.find(), )); Get.put(AdvancedFilterController()); } @@ -306,6 +308,7 @@ class MailboxDashBoardBindings extends BaseBindings { Get.find(), Get.find() )); + Get.lazyPut(() => UnsubscribeEmailInteractor(Get.find())); } @override 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 0f70c2384..63d824852 100644 --- a/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart +++ b/lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart @@ -49,11 +49,13 @@ import 'package:tmail_ui_user/features/email/domain/state/delete_sending_email_s import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/store_sending_email_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/delete_email_permanently_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/delete_multiple_emails_permanently_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_star_email_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/move_to_mailbox_interactor.dart'; +import 'package:tmail_ui_user/features/email/domain/usecases/unsubscribe_email_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; @@ -174,6 +176,7 @@ class MailboxDashBoardController extends ReloadableController { final SaveEmailAsDraftsInteractor _saveEmailAsDraftsInteractor; final UpdateEmailDraftsInteractor _updateEmailDraftsInteractor; final DeleteSendingEmailInteractor _deleteSendingEmailInteractor; + final UnsubscribeEmailInteractor _unsubscribeEmailInteractor; GetAllVacationInteractor? _getAllVacationInteractor; UpdateVacationInteractor? _updateVacationInteractor; @@ -251,6 +254,7 @@ class MailboxDashBoardController extends ReloadableController { this._saveEmailAsDraftsInteractor, this._updateEmailDraftsInteractor, this._deleteSendingEmailInteractor, + this._unsubscribeEmailInteractor, ); @override @@ -343,6 +347,8 @@ class MailboxDashBoardController extends ReloadableController { _markAsReadEmailSuccess(success); } else if (success is DeleteSendingEmailSuccess) { getAllSendingEmails(); + } else if (success is UnsubscribeEmailSuccess) { + _handleUnsubscribeMailSuccess(success.newEmail); } } @@ -2123,14 +2129,14 @@ class MailboxDashBoardController extends ReloadableController { void _handleSendEmailSuccess(SendEmailSuccess success) { if (PlatformInfo.isIOS && - success.storedSendingId != null && + success.emailRequest.storedSendingId != null && accountId.value != null && sessionCurrent != null ) { consumeState(_deleteSendingEmailInteractor.execute( accountId.value!, sessionCurrent!.username, - success.storedSendingId! + success.emailRequest.storedSendingId! )); } if (currentOverlayContext != null && currentContext != null) { @@ -2140,6 +2146,11 @@ class MailboxDashBoardController extends ReloadableController { leadingSVGIcon: imagePaths.icSendSuccessToast ); } + + if (success.emailRequest.emailActionType == EmailActionType.composeFromUnsubscribeMailtoLink && + success.emailRequest.previousEmailId != null) { + unsubscribeMail(success.emailRequest.previousEmailId!); + } } void _updateSendingStateWhenSendEmailFailureOnIOS(SendEmailFailure failure) { @@ -2192,6 +2203,27 @@ class MailboxDashBoardController extends ReloadableController { dispatchAction(SearchEmailByFromFieldsAction(emailAddress)); } + void unsubscribeMail(EmailId emailId) { + if (accountId.value != null && sessionCurrent != null) { + consumeState( + _unsubscribeEmailInteractor.execute( + sessionCurrent!, + accountId.value!, + emailId + ) + ); + } + } + + void _handleUnsubscribeMailSuccess(Email email) { + if (currentContext != null && currentOverlayContext != null) { + appToast.showToastSuccessMessage( + currentOverlayContext!, + AppLocalizations.of(currentContext!).unsubscribedFromThisMailingList); + } + setSelectedEmail(email.toPresentationEmail()); + } + @override void onClose() { _emailReceiveManager.closeEmailReceiveManagerStream(); diff --git a/lib/features/search/email/presentation/search_email_controller.dart b/lib/features/search/email/presentation/search_email_controller.dart index e438c9834..a45f46dec 100644 --- a/lib/features/search/email/presentation/search_email_controller.dart +++ b/lib/features/search/email/presentation/search_email_controller.dart @@ -37,6 +37,7 @@ import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_emails import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart'; import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart'; @@ -209,7 +210,8 @@ class SearchEmailController extends BaseController success is EmptyTrashFolderSuccess || success is EmptySpamFolderSuccess || success is DeleteMultipleEmailsPermanentlyAllSuccess || - success is DeleteMultipleEmailsPermanentlyHasSomeEmailFailure + success is DeleteMultipleEmailsPermanentlyHasSomeEmailFailure || + success is UnsubscribeEmailSuccess ) { _refreshEmailChanges(); } diff --git a/lib/features/thread/presentation/thread_controller.dart b/lib/features/thread/presentation/thread_controller.dart index 78ce3978f..7663fa58f 100644 --- a/lib/features/thread/presentation/thread_controller.dart +++ b/lib/features/thread/presentation/thread_controller.dart @@ -28,6 +28,7 @@ import 'package:tmail_ui_user/features/email/domain/state/delete_multiple_emails import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_star_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/move_to_mailbox_state.dart'; +import 'package:tmail_ui_user/features/email/domain/state/unsubscribe_email_state.dart'; import 'package:tmail_ui_user/features/email/presentation/action/email_ui_action.dart'; import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart'; import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart'; @@ -348,6 +349,8 @@ class ThreadController extends BaseController with EmailActionController { _refreshEmailChanges(currentEmailState: success.currentEmailState); } else if (success is EmptyTrashFolderSuccess || success is EmptySpamFolderSuccess) { refreshAllEmail(); + } else if (success is UnsubscribeEmailSuccess) { + _refreshEmailChanges(currentEmailState: success.currentEmailState); } }); }); diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb index 8808c329c..a95e7866e 100644 --- a/lib/l10n/intl_messages.arb +++ b/lib/l10n/intl_messages.arb @@ -1,5 +1,5 @@ { - "@@last_modified": "2023-11-16T00:29:04.650547", + "@@last_modified": "2023-11-16T12:39:33.304952", "initializing_data": "Initializing data...", "@initializing_data": { "type": "text", @@ -3517,5 +3517,15 @@ "type": "text", "placeholders_order": [], "placeholders": {} + }, + "mailUnsubscribedMessage": "You unsubscribe from {senderName}", + "@mailUnsubscribedMessage": { + "type": "text", + "placeholders_order": [ + "senderName" + ], + "placeholders": { + "senderName": {} + } } } \ No newline at end of file diff --git a/lib/main/localizations/app_localizations.dart b/lib/main/localizations/app_localizations.dart index 3c9971fb6..50f5d1a58 100644 --- a/lib/main/localizations/app_localizations.dart +++ b/lib/main/localizations/app_localizations.dart @@ -3652,4 +3652,12 @@ class AppLocalizations { name: 'unsubscribedFromThisMailingList', ); } + + String mailUnsubscribedMessage(String senderName) { + return Intl.message( + 'You unsubscribe from $senderName', + name: 'mailUnsubscribedMessage', + args: [senderName] + ); + } } \ No newline at end of file diff --git a/model/lib/email/presentation_email.dart b/model/lib/email/presentation_email.dart index 4f18ee1fd..599aced12 100644 --- a/model/lib/email/presentation_email.dart +++ b/model/lib/email/presentation_email.dart @@ -13,6 +13,7 @@ import 'package:jmap_dart_client/jmap/mail/email/keyword_identifier.dart'; import 'package:jmap_dart_client/jmap/mail/mailbox/mailbox.dart'; import 'package:model/email/email_content.dart'; import 'package:model/extensions/email_address_extension.dart'; +import 'package:model/extensions/keyword_identifier_extension.dart'; import 'package:model/extensions/media_type_nullable_extension.dart'; import 'package:model/mailbox/presentation_mailbox.dart'; import 'package:model/mailbox/select_mode.dart'; @@ -110,6 +111,8 @@ class PresentationEmail with EquatableMixin { bool get isForwarded => keywords?.containsKey(KeyWordIdentifier.emailForwarded) == true; + bool get isSubscribed => keywords?.containsKey(KeyWordIdentifierExtension.unsubscribeMail) == true; + bool get isAnsweredAndForwarded => isAnswered && isForwarded; bool get withAttachments => hasAttachment == true; diff --git a/model/lib/extensions/email_extension.dart b/model/lib/extensions/email_extension.dart index 745580ba3..e7b50c44b 100644 --- a/model/lib/extensions/email_extension.dart +++ b/model/lib/extensions/email_extension.dart @@ -25,6 +25,8 @@ extension EmailExtension on Email { bool get isDraft => keywords?.containsKey(KeyWordIdentifier.emailDraft) == true; + bool get isUnsubscribed => keywords?.containsKey(KeyWordIdentifierExtension.unsubscribeMail) == true; + bool get withAttachments => hasAttachment == true; String get listUnsubscribe {