TF-3715 Thread Detail create resuable actions

TF-3715 Thread Detail refactor actions for expanded email view

TF-3715 Thread Detail apply actions for collapsed email view

TF-3715 Thread Detail fix unit tests

TF-3715 Thread Detail add await for _getEmailContent in composer

TF-3715 Thread Detail remove unused emailLoaded in ThreadDetailAppBar

TF-3715 Thread Detail hide print action when isMobile

TF-3715 Thread Detail allow mark as read in EmailActionReactor

TF-3715 Thread Detail fix loadMoreThreadDetailEmails unit test

TF-3715 Thread Detail fix action small tap region

TF-3715 Thread Detail fix cannot permanent delete email

TF-3715 Thread Detail prevent close when move email

TF-3715 Thread Detail fix refresh when mark star selected collapsed email

TF-3715 Thread Detail update print action display logic

TF-3715 Thread Detail fix duplicate mark star in app bar

TF-3715 Thread Detail create new transformer for reply forward empty content email

TF-3715 Thread Detail fix email not load after open multiple times

TF-3715 Thread Detail fix close when move expanded email

TF-3715 Thread Detail fix duplicate and missing actions

TF-3715 Thread Detail restore editAsNewEmail action to _getEmailContent in setupEmailContent

TF-3715 Thread Detail update print action name

TF-3715 Thread Detail handle move and delete email with 1 item in thread detail

TF-3715 Thread Detail fix tap outside to close context menu

TF-3715 Thread Detail fix create rule and compose from recipient info

TF-3715 Thread Detail handle move and delete email with 1 item in thread detail

TF-3715 Thread Detail Fix cannot create email rule

TF-3715 Thread Detail Fix crash composer

TF-3715 Thread Detail Fix cannot unsubscribe

TF-3715 Thread Detail Fix duplicate actions on single email

TF-3715 Thread Detail Fix refresh view when reply/forward

TF-3715 Thread Detail Revert old logic to _getEmailContent

TF-3715 Thread Detail Update specific cases for UpdatedEmailKeywordsAction

TF-3715 Thread Detail Fix concurrent modification during iteration

TF-3715 Thread Detail Fix unsubscribe for all thread detail emails

TF-3715 Thread Detail Remove unnecessary Future in reactor

TF-3715 Thread Detail Remove dependency from SingleEmailController

TF-3715 Thread Detail Apply individual list post and unsubscribe header

TF-3715 Thread Detail Fix unsubscribe collapsed email

TF-3715 Thread Detail Conditionally inject rule filter interactor
This commit is contained in:
DatDang
2025-05-16 15:37:07 +07:00
committed by Dat H. Pham
parent 421fa321ba
commit 8a2ea62987
38 changed files with 2135 additions and 715 deletions
@@ -43,11 +43,9 @@ import 'package:tmail_ui_user/features/base/base_controller.dart';
import 'package:tmail_ui_user/features/base/mixin/app_loader_mixin.dart';
import 'package:tmail_ui_user/features/base/state/button_state.dart';
import 'package:tmail_ui_user/features/composer/presentation/extensions/email_action_type_extension.dart';
import 'package:tmail_ui_user/features/destination_picker/presentation/model/destination_picker_arguments.dart';
import 'package:tmail_ui_user/features/email/domain/exceptions/email_exceptions.dart';
import 'package:tmail_ui_user/features/email/domain/extensions/list_attachments_extension.dart';
import 'package:tmail_ui_user/features/email/domain/model/detailed_email.dart';
import 'package:tmail_ui_user/features/email/domain/model/email_print.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/model/move_action.dart';
@@ -110,39 +108,35 @@ import 'package:tmail_ui_user/features/email/presentation/model/composer_argumen
import 'package:tmail_ui_user/features/email/presentation/model/email_loaded.dart';
import 'package:tmail_ui_user/features/email/presentation/model/email_unsubscribe.dart';
import 'package:tmail_ui_user/features/email/presentation/model/eml_previewer.dart';
import 'package:tmail_ui_user/features/email/presentation/utils/email_action_reactor/email_action_reactor.dart';
import 'package:tmail_ui_user/features/email/presentation/utils/email_utils.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_bottom_sheet_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/attachment_list/attachment_list_dialog_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_bottom_sheet_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/email_address_dialog_builder.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/html_attachment_previewer.dart';
import 'package:tmail_ui_user/features/email/presentation/widgets/pdf_viewer/pdf_viewer.dart';
import 'package:tmail_ui_user/features/email_previewer/email_previewer_dialog_view.dart';
import 'package:tmail_ui_user/features/home/data/exceptions/session_exceptions.dart';
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.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';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/get_mailbox_contain_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/update_current_emails_flags_extension.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/search/email/presentation/search_email_controller.dart';
import 'package:tmail_ui_user/features/thread/presentation/model/delete_action_type.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/close_thread_detail_action.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/extension/focus_thread_detail_expanded_email.dart';
import 'package:tmail_ui_user/features/thread_detail/presentation/thread_detail_controller.dart';
import 'package:tmail_ui_user/main/error/capability_validator.dart';
import 'package:tmail_ui_user/main/localizations/app_localizations.dart';
import 'package:tmail_ui_user/main/localizations/localization_service.dart';
import 'package:tmail_ui_user/main/routes/app_routes.dart';
import 'package:tmail_ui_user/main/routes/dialog_router.dart';
import 'package:tmail_ui_user/main/routes/navigation_router.dart';
import 'package:tmail_ui_user/main/routes/route_navigation.dart';
import 'package:tmail_ui_user/main/routes/route_utils.dart';
@@ -203,6 +197,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
Identity? _identitySelected;
ButtonState? _printEmailButtonState;
final obxListeners = <Worker>[];
late final EmailActionReactor emailActionReactor;
final StreamController<Either<Failure, Success>> _downloadProgressStateController =
StreamController<Either<Failure, Success>>.broadcast();
@@ -254,6 +249,14 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_injectCalendarEventBindings(session, accountId);
_registerObxStreamListener();
_listenDownloadAttachmentProgressState();
emailActionReactor = EmailActionReactor(
_markAsEmailReadInteractor,
_markAsStarEmailInteractor,
_createNewEmailRuleFilterInteractor,
_printEmailInteractor,
_getEmailContentInteractor,
_downloadAttachmentForWebInteractor,
);
super.onInit();
}
@@ -408,6 +411,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
obxListeners.add(ever(mailboxDashBoardController.viewState, (viewState) {
viewState.map((success) {
if (success is UnsubscribeEmailSuccess) {
if (success.emailId != _currentEmailId) return;
emailUnsubscribe.value = null;
}
});
@@ -766,13 +770,7 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
PresentationMailbox? getMailboxContain(PresentationEmail email) {
if (mailboxDashBoardController.selectedMailbox.value == null) {
return email.findMailboxContain(mailboxDashBoardController.mapMailboxById);
} else {
return mailboxDashBoardController.searchController.isSearchEmailRunning
? email.findMailboxContain(mailboxDashBoardController.mapMailboxById)
: mailboxDashBoardController.selectedMailbox.value;
}
return mailboxDashBoardController.getMailboxContain(email);
}
void markAsEmailRead(
@@ -1200,81 +1198,28 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
void moveToMailbox(BuildContext context, PresentationEmail email) async {
final currentMailbox = getMailboxContain(email);
if (currentMailbox != null && accountId != null) {
final arguments = DestinationPickerArguments(
if (session != null && accountId != null) {
final moveActionRequest = await emailActionReactor.moveToMailbox(
session!,
accountId!,
MailboxActions.moveEmail,
session,
mailboxIdSelected: currentMailbox.mailboxId
email,
mapMailbox: mailboxDashBoardController.mapMailboxById,
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
);
final destinationMailbox = PlatformInfo.isWeb
? await DialogRouter.pushGeneralDialog(routeName: AppRoutes.destinationPicker, arguments: arguments)
: await push(AppRoutes.destinationPicker, arguments: arguments);
if (destinationMailbox != null &&
destinationMailbox is PresentationMailbox &&
session != null &&
context.mounted
) {
_dispatchMoveToAction(
context,
accountId!,
session!,
email,
currentMailbox,
destinationMailbox);
if (!context.mounted || moveActionRequest == null) return;
mailboxDashBoardController.moveToMailbox(
session!,
accountId!,
moveActionRequest.moveRequest,
moveActionRequest.emailIdsWithReadStatus,
);
if (_threadDetailController?.emailIdsPresentation.length == 1) {
_threadDetailController?.closeThreadDetailAction(context);
}
}
}
void _dispatchMoveToAction(
BuildContext context,
AccountId accountId,
Session session,
PresentationEmail emailSelected,
PresentationMailbox currentMailbox,
PresentationMailbox destinationMailbox
) {
if (destinationMailbox.isTrash) {
_moveToTrashAction(
context,
session,
accountId,
MoveToMailboxRequest(
{currentMailbox.id: [emailSelected.id!]},
destinationMailbox.id,
MoveAction.moving,
EmailActionType.moveToTrash),
{emailSelected.id!: emailSelected.hasRead});
} else if (destinationMailbox.isSpam) {
_moveToSpamAction(
context,
session,
accountId,
MoveToMailboxRequest(
{currentMailbox.id: [emailSelected.id!]},
destinationMailbox.id,
MoveAction.moving,
EmailActionType.moveToSpam),
{emailSelected.id!: emailSelected.hasRead});
} else {
_moveToMailbox(
context,
session,
accountId,
MoveToMailboxRequest(
{currentMailbox.id: [emailSelected.id!]},
destinationMailbox.id,
MoveAction.moving,
EmailActionType.moveToMailbox,
destinationPath: destinationMailbox.mailboxPath),
{emailSelected.id!: emailSelected.hasRead});
}
}
void _moveToMailbox(
BuildContext context,
Session session,
@@ -1282,7 +1227,6 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
MoveToMailboxRequest moveRequest,
Map<EmailId, bool> emailIdsWithReadStatus,
) {
closeEmailView(context: context);
consumeState(_moveToMailboxInteractor.execute(
session,
accountId,
@@ -1332,94 +1276,71 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
void moveToTrash(BuildContext context, PresentationEmail email) {
final trashMailboxId = mailboxDashBoardController.getMailboxIdByRole(PresentationMailbox.roleTrash);
final currentMailbox = getMailboxContain(email);
if (session != null && accountId != null && currentMailbox != null && trashMailboxId != null) {
_moveToTrashAction(
context,
if (session != null && accountId != null) {
final moveActionRequest = emailActionReactor.moveToTrash(
email,
mapMailbox: mailboxDashBoardController.mapMailboxById,
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
);
if (!context.mounted || moveActionRequest == null) return;
mailboxDashBoardController.moveToMailbox(
session!,
accountId!,
MoveToMailboxRequest(
{currentMailbox.id: [email.id!]},
trashMailboxId,
MoveAction.moving,
EmailActionType.moveToTrash),
{email.id!: email.hasRead},
moveActionRequest.moveRequest,
moveActionRequest.emailIdsWithReadStatus,
);
if (_threadDetailController?.emailIdsPresentation.length == 1) {
_threadDetailController?.closeThreadDetailAction(context);
}
}
}
void _moveToTrashAction(
BuildContext context,
Session session,
AccountId accountId,
MoveToMailboxRequest moveRequest,
Map<EmailId, bool> emailIdsWithReadStatus,
) {
closeEmailView(context: context);
mailboxDashBoardController.moveToMailbox(
session,
accountId,
moveRequest,
emailIdsWithReadStatus,
);
}
void moveToSpam(BuildContext context, PresentationEmail email) {
final spamMailboxId = mailboxDashBoardController.spamMailboxId;
final currentMailbox = getMailboxContain(email);
if (session != null && accountId != null && currentMailbox != null && spamMailboxId != null) {
_moveToSpamAction(
context,
if (session != null && accountId != null) {
final moveActionRequest = emailActionReactor.moveToSpam(
email,
mapMailbox: mailboxDashBoardController.mapMailboxById,
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
);
if (!context.mounted || moveActionRequest == null) return;
mailboxDashBoardController.moveToMailbox(
session!,
accountId!,
MoveToMailboxRequest(
{currentMailbox.id: [email.id!]},
spamMailboxId,
MoveAction.moving,
EmailActionType.moveToSpam),
{email.id!: email.hasRead},
moveActionRequest.moveRequest,
moveActionRequest.emailIdsWithReadStatus,
);
if (_threadDetailController?.emailIdsPresentation.length == 1) {
_threadDetailController?.closeThreadDetailAction(context);
}
}
}
void unSpam(BuildContext context, PresentationEmail email) {
final spamMailboxId = mailboxDashBoardController.spamMailboxId;
final inboxMailboxId = mailboxDashBoardController.getMailboxIdByRole(PresentationMailbox.roleInbox);
if (session != null && accountId != null && spamMailboxId != null && inboxMailboxId != null) {
_moveToSpamAction(
context,
if (session != null && accountId != null) {
final moveActionRequest = emailActionReactor.unSpam(
email,
mapMailbox: mailboxDashBoardController.mapMailboxById,
selectedMailbox: mailboxDashBoardController.selectedMailbox.value,
isSearchEmailRunning: mailboxDashBoardController.searchController.isSearchEmailRunning,
mapDefaultMailboxIdByRole: mailboxDashBoardController.mapDefaultMailboxIdByRole,
);
if (!context.mounted || moveActionRequest == null) return;
mailboxDashBoardController.moveToMailbox(
session!,
accountId!,
MoveToMailboxRequest(
{spamMailboxId: [email.id!]},
inboxMailboxId,
MoveAction.moving,
EmailActionType.unSpam),
{email.id!: email.hasRead},
moveActionRequest.moveRequest,
moveActionRequest.emailIdsWithReadStatus,
);
if (_threadDetailController?.emailIdsPresentation.length == 1) {
_threadDetailController?.closeThreadDetailAction(context);
}
}
}
void _moveToSpamAction(
BuildContext context,
Session session,
AccountId accountId,
MoveToMailboxRequest moveRequest,
Map<EmailId, bool> emailIdsWithReadStatus,
) {
closeEmailView(context: context);
mailboxDashBoardController.moveToMailbox(
session,
accountId,
moveRequest,
emailIdsWithReadStatus,
);
}
void markAsStarEmail(
PresentationEmail presentationEmail,
MarkStarAction markStarAction,
@@ -1451,13 +1372,34 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
void handleEmailAction(BuildContext context, PresentationEmail presentationEmail, EmailActionType actionType) {
switch(actionType) {
case EmailActionType.markAsUnread:
markAsEmailRead(presentationEmail, ReadActions.markAsUnread, MarkReadAction.tap);
if (session != null && accountId != null) {
consumeState(emailActionReactor.markAsEmailRead(
session!,
accountId!,
presentationEmail,
readAction: ReadActions.markAsUnread,
));
}
break;
case EmailActionType.markAsStarred:
markAsStarEmail(presentationEmail, MarkStarAction.markStar);
if (session != null && accountId != null) {
consumeState(emailActionReactor.markAsStarEmail(
session!,
accountId!,
presentationEmail,
markStarAction: MarkStarAction.markStar,
));
}
break;
case EmailActionType.unMarkAsStarred:
markAsStarEmail(presentationEmail, MarkStarAction.unMarkStar);
if (session != null && accountId != null) {
consumeState(emailActionReactor.markAsStarEmail(
session!,
accountId!,
presentationEmail,
markStarAction: MarkStarAction.unMarkStar,
));
}
break;
case EmailActionType.moveToMailbox:
moveToMailbox(context, presentationEmail);
@@ -1495,69 +1437,38 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
case EmailActionType.reply:
_replyEmail(presentationEmail);
break;
case EmailActionType.replyAll:
case EmailActionType.replyToList:
case EmailActionType.forward:
pressEmailAction(actionType, presentationEmail);
break;
default:
break;
}
}
void openEmailAddressDialog(BuildContext context, EmailAddress emailAddress) {
if (responsiveUtils.isScreenWithShortestSide(context)) {
Get.bottomSheet(
PointerInterceptor(
child: EmailAddressBottomSheetBuilder(
imagePaths: imagePaths,
emailAddress: emailAddress,
onCloseDialogAction: popBack,
onCopyEmailAddressAction: (emailAddress) =>
copyEmailAddress(context, emailAddress),
onComposeEmailAction: composeEmailFromEmailAddress,
onQuickCreatingRuleEmailDialogAction: (emailAddress) =>
quickCreatingRule(context, emailAddress),
),
),
useRootNavigator: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadiusDirectional.only(
topStart: Radius.circular(16.0),
topEnd: Radius.circular(16.0),
),
),
isScrollControlled: true,
enableDrag: false,
backgroundColor: Colors.transparent,
);
} else {
Get.dialog(
PointerInterceptor(
child: EmailAddressDialogBuilder(
imagePaths: imagePaths,
emailAddress: emailAddress,
onCloseDialogAction: popBack,
onCopyEmailAddressAction: (emailAddress) =>
copyEmailAddress(context, emailAddress),
onComposeEmailAction: composeEmailFromEmailAddress,
onQuickCreatingRuleEmailDialogAction: (emailAddress) =>
quickCreatingRule(context, emailAddress),
),
),
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
);
}
}
void openEmailAddressDialog(EmailAddress emailAddress) {
if (session == null || accountId == null) return;
void copyEmailAddress(BuildContext context, EmailAddress emailAddress) {
Clipboard.setData(ClipboardData(text: emailAddress.emailAddress));
appToast.showToastSuccessMessage(
context,
AppLocalizations.of(context).email_address_copied_to_clipboard,
emailActionReactor.openEmailAddressDialog(
session!,
accountId!,
emailAddress: emailAddress,
responsiveUtils: responsiveUtils,
imagePaths: imagePaths,
appToast: appToast,
onComposeEmailFromEmailAddressRequest: (emailAddress) {
popBack();
mailboxDashBoardController.openComposer(
ComposerArguments.fromEmailAddress(emailAddress),
);
},
onQuickCreateRuleRequest: (quickCreateRuleStream) {
consumeState(quickCreateRuleStream);
},
);
}
void composeEmailFromEmailAddress(EmailAddress emailAddress) {
popBack();
mailboxDashBoardController.openComposer(ComposerArguments.fromEmailAddress(emailAddress));
}
Future<void> openMailToLink(Uri? uri) async {
if (uri == null) return;
@@ -1577,34 +1488,18 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
void deleteEmailPermanently(BuildContext context, PresentationEmail email) {
if (responsiveUtils.isMobile(context)) {
(ConfirmationDialogActionSheetBuilder(context)
..messageText(DeleteActionType.single.getContentDialog(context))
..onCancelAction(AppLocalizations.of(context).cancel, () => popBack())
..onConfirmAction(DeleteActionType.single.getConfirmActionName(context), () => _deleteEmailPermanentlyAction(context, email)))
.show();
} else {
Get.dialog(
PointerInterceptor(child: ConfirmationDialogBuilder(
key: const Key('confirm_dialog_delete_email_permanently'),
imagePath: imagePaths,
title: DeleteActionType.single.getTitleDialog(context),
textContent: DeleteActionType.single.getContentDialog(context),
confirmText: DeleteActionType.single.getConfirmActionName(context),
cancelText: AppLocalizations.of(context).cancel,
onConfirmButtonAction: () => _deleteEmailPermanentlyAction(context, email),
onCancelButtonAction: popBack,
onCloseButtonAction: popBack,
)),
barrierColor: AppColor.colorDefaultCupertinoActionSheet,
);
}
}
void _deleteEmailPermanentlyAction(BuildContext context, PresentationEmail email) {
popBack();
closeEmailView(context: context);
mailboxDashBoardController.deleteEmailPermanently(email);
emailActionReactor.deleteEmailPermanently(
email,
onDeleteEmailRequest: (email) {
popBack();
mailboxDashBoardController.deleteEmailPermanently(email);
if (_threadDetailController?.emailIdsPresentation.length == 1) {
_threadDetailController?.closeThreadDetailAction(context);
}
},
responsiveUtils: responsiveUtils,
imagePaths: imagePaths,
);
}
void _handleSendReceiptToSenderAction(BuildContext context) {
@@ -1793,32 +1688,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
popBack();
if (accountId != null && session != null) {
final arguments = RulesFilterCreatorArguments(
accountId!,
consumeState(emailActionReactor.quickCreateRule(
session!,
emailAddress: emailAddress);
final newRuleFilterRequest = PlatformInfo.isWeb
? await DialogRouter.pushGeneralDialog(routeName: AppRoutes.rulesFilterCreator, arguments: arguments)
: await push(AppRoutes.rulesFilterCreator, arguments: arguments);
if (newRuleFilterRequest is CreateNewEmailRuleFilterRequest) {
_createNewRuleFilterAction(accountId!, newRuleFilterRequest);
}
}
}
void _createNewRuleFilterAction(
AccountId accountId,
CreateNewEmailRuleFilterRequest ruleFilterRequest
) async {
try {
_createNewEmailRuleFilterInteractor = Get.find<CreateNewEmailRuleFilterInteractor>();
} catch (e) {
logError('SingleEmailController::onInit(): ${e.toString()}');
}
if (_createNewEmailRuleFilterInteractor != null) {
consumeState(_createNewEmailRuleFilterInteractor!.execute(accountId, ruleFilterRequest));
accountId!,
emailAddress: emailAddress,
));
}
}
@@ -1929,70 +1803,30 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
void _unsubscribeEmail(BuildContext context, PresentationEmail presentationEmail) {
showConfirmDialogAction(
context,
'',
AppLocalizations.of(context).unsubscribe,
onConfirmAction: () {
if (emailUnsubscribe.value?.httpLinks.isNotEmpty == true) {
_handleUnsubscribeMailByHttpsLink(
context: context,
emailId: presentationEmail.id!,
httpLinks: emailUnsubscribe.value!.httpLinks
);
} else if (emailUnsubscribe.value?.mailtoLinks.isNotEmpty == true) {
_handleUnsubscribeMailByMailtoLink(
context: context,
emailId: presentationEmail.id!,
mailtoLinks: emailUnsubscribe.value!.mailtoLinks
);
}
emailActionReactor.unsubscribeEmail(
presentationEmail,
emailUnsubscribe: emailUnsubscribe.value,
onUnsubscribeByHttpsLink: mailboxDashBoardController.unsubscribeMail,
onUnsubscribeByMailtoLink: (emailId, navigationRouter) {
mailboxDashBoardController.openComposer(
ComposerArguments.fromUnsubscribeMailtoLink(
listEmailAddress: navigationRouter.listEmailAddress,
subject: navigationRouter.subject,
body: navigationRouter.body,
previousEmailId: emailId,
)
);
},
showAsBottomSheet: true,
dialogMargin: MediaQuery.paddingOf(context).add(const EdgeInsets.only(bottom: 12)),
title: AppLocalizations.of(context).unsubscribeMail,
listTextSpan: [
TextSpan(text: AppLocalizations.of(context).unsubscribeMailDialogMessage),
TextSpan(
text: ' ${presentationEmail.getSenderName()}',
style: ThemeUtils.textStyleM3BodyMedium1.copyWith(
fontWeight: FontWeight.w700,
),
),
const TextSpan(text: ' ?'),
]
);
}
void _handleUnsubscribeMailByHttpsLink({
required BuildContext context,
required EmailId emailId,
required List<String> httpLinks
}) {
log('SingleEmailController::_handleUnsubscribeMailByHttpsLink:httpLinks: $httpLinks');
mailboxDashBoardController.unsubscribeMail(emailId);
AppUtils.launchLink(httpLinks.first);
}
void _handleUnsubscribeMailByMailtoLink({
required BuildContext context,
required EmailId emailId,
required List<String> mailtoLinks
}) {
log('SingleEmailController::_handleUnsubscribeMailByMailtoLink:mailtoLinks: $mailtoLinks');
final navigationRouter = RouteUtils.generateNavigationRouterFromMailtoLink(mailtoLinks.first);
mailboxDashBoardController.openComposer(
ComposerArguments.fromUnsubscribeMailtoLink(
listEmailAddress: navigationRouter.listEmailAddress,
subject: navigationRouter.subject,
body: navigationRouter.body,
previousEmailId: emailId,
)
);
}
void archiveMessage(BuildContext context, PresentationEmail email) {
mailboxDashBoardController.archiveMessage(context, email);
emailActionReactor.archiveMessage(
email,
onArchiveEmailRequest: (presentationEmail) {
mailboxDashBoardController.archiveMessage(context, presentationEmail);
},
);
}
void _printEmail(BuildContext context, PresentationEmail email) {
@@ -2003,40 +1837,11 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
_printEmailButtonState = ButtonState.disabled;
final locale = Localizations.localeOf(context);
final appLocalizations = AppLocalizations.of(context);
consumeState(
_printEmailInteractor.execute(
EmailPrint(
appName: appLocalizations.app_name,
userName: mailboxDashBoardController.ownEmailAddress.value,
attachments: currentEmailLoaded.value!.attachments,
emailContent: currentEmailLoaded.value!.htmlContent,
fromPrefix: appLocalizations.from_email_address_prefix,
toPrefix: appLocalizations.to_email_address_prefix,
ccPrefix: appLocalizations.cc_email_address_prefix,
bccPrefix: appLocalizations.bcc_email_address_prefix,
replyToPrefix: appLocalizations.replyToEmailAddressPrefix,
titleAttachment: appLocalizations.attachments.toLowerCase(),
toAddress: email.to?.listEmailAddressToString(isFullEmailAddress: true),
ccAddress: email.cc?.listEmailAddressToString(isFullEmailAddress: true),
bccAddress: email.bcc?.listEmailAddressToString(isFullEmailAddress: true),
replyToAddress: email.replyTo?.listEmailAddressToString(isFullEmailAddress: true),
sender: email.from?.isNotEmpty == true
? email.from!.first
: null,
receiveTime: email.getReceivedAt(
locale.toLanguageTag(),
pattern: email.receivedAt
?.value
.toLocal()
.toPatternForPrinting(locale.toLanguageTag()),
),
subject: email.subject,
)
)
);
consumeState(emailActionReactor.printEmail(
email,
ownEmailAddress: mailboxDashBoardController.ownEmailAddress.value,
emailLoaded: currentEmailLoaded.value!,
));
}
void _showMessageWhenStartingEmailPrinting() {
@@ -2181,34 +1986,46 @@ class SingleEmailController extends BaseController with AppLoaderMixin {
}
void _downloadMessageAsEML(PresentationEmail presentationEmail) {
final emlAttachment = presentationEmail.createEMLAttachment();
if (emlAttachment.blobId == null) {
consumeState(Stream.value(Left(DownloadAttachmentForWebFailure(exception: NotFoundEmailBlobIdException()))));
return;
}
if (accountId == null || session == null) return;
downloadAttachmentForWeb(emlAttachment);
consumeState(emailActionReactor.downloadMessageAsEML(
session!,
accountId!,
presentationEmail,
downloadProgressStateController: _downloadProgressStateController,
));
}
void _editAsNewEmail(PresentationEmail presentationEmail) {
if (accountId == null || session == null) return;
mailboxDashBoardController.openComposer(
ComposerArguments.editAsNewEmail(presentationEmail),
emailActionReactor.editAsNewEmail(
presentationEmail,
onEditAsEmailRequest: (presentationEmail) {
mailboxDashBoardController.openComposer(
ComposerArguments.editAsNewEmail(presentationEmail),
);
},
);
}
void _replyEmail(PresentationEmail presentationEmail) {
mailboxDashBoardController.openComposer(
ComposerArguments.replyEmail(
presentationEmail: presentationEmail,
content: currentEmailLoaded.value?.htmlContent ?? '',
inlineImages: currentEmailLoaded.value?.inlineImages ?? [],
mailboxRole: presentationEmail.mailboxContain?.role,
messageId: currentEmailLoaded.value?.emailCurrent?.messageId,
references: currentEmailLoaded.value?.emailCurrent?.references,
listPost: currentEmailLoaded.value?.emailCurrent?.listPost,
)
emailActionReactor.replyEmail(
presentationEmail,
emailLoaded: currentEmailLoaded.value,
onReplyEmailRequest: (presentationEmail, emailLoaded) {
mailboxDashBoardController.openComposer(
ComposerArguments.replyEmail(
presentationEmail: presentationEmail,
content: emailLoaded?.htmlContent,
inlineImages: emailLoaded?.inlineImages,
mailboxRole: presentationEmail.mailboxContain?.role,
messageId: emailLoaded?.emailCurrent?.messageId,
references: emailLoaded?.emailCurrent?.references,
listPost: emailLoaded?.emailCurrent?.listPost,
)
);
},
);
}