import 'package:core/core.dart'; import 'package:dartz/dartz.dart'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import 'package:jmap_dart_client/jmap/account_id.dart'; import 'package:jmap_dart_client/jmap/mail/email/email.dart'; import 'package:model/model.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:tmail_ui_user/features/base/base_controller.dart'; import 'package:tmail_ui_user/features/email/domain/state/download_attachments_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/export_attachment_state.dart'; import 'package:tmail_ui_user/features/email/domain/state/get_email_content_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/download_attachments_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/state/mark_as_email_read_state.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/export_attachment_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/get_email_content_interactor.dart'; import 'package:tmail_ui_user/features/email/domain/usecases/mark_as_email_read_interactor.dart'; import 'package:tmail_ui_user/features/email/presentation/model/composer_arguments.dart'; import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/mailbox_dashboard_controller.dart'; import 'package:tmail_ui_user/main/localizations/app_localizations.dart'; import 'package:tmail_ui_user/main/routes/app_routes.dart'; import 'package:tmail_ui_user/main/routes/route_navigation.dart'; import 'package:share/share.dart' as share_library; class EmailController extends BaseController { final mailboxDashBoardController = Get.find(); final responsiveUtils = Get.find(); final GetEmailContentInteractor _getEmailContentInteractor; final MarkAsEmailReadInteractor _markAsEmailReadInteractor; final DownloadAttachmentsInteractor _downloadAttachmentsInteractor; final DeviceManager _deviceManager; final AppToast _appToast; final ExportAttachmentInteractor _exportAttachmentInteractor; final emailAddressExpandMode = ExpandMode.COLLAPSE.obs; final attachmentsExpandMode = ExpandMode.COLLAPSE.obs; final emailContent = Rxn(); EmailController( this._getEmailContentInteractor, this._markAsEmailReadInteractor, this._downloadAttachmentsInteractor, this._deviceManager, this._appToast, this._exportAttachmentInteractor, ); @override void onReady() { super.onReady(); mailboxDashBoardController.selectedEmail.listen((presentationEmail) { _clearEmailContent(); final accountId = mailboxDashBoardController.accountId.value; if (accountId != null && presentationEmail != null) { _getEmailContentAction(accountId, presentationEmail.id); if (presentationEmail.isUnReadEmail()) { markAsEmailRead(presentationEmail, ReadActions.markAsRead); } } }); } @override void onClose() { mailboxDashBoardController.selectedEmail.close(); super.onClose(); } void _getEmailContentAction(AccountId accountId, EmailId emailId) async { consumeState(_getEmailContentInteractor.execute(accountId, emailId)); } @override void onData(Either newState) { super.onData(newState); } @override void onDone() { viewState.value.fold( (failure) { if (failure is MarkAsEmailReadFailure) { _markAsEmailReadFailure(failure); } else if (failure is DownloadAttachmentsFailure) { _downloadAttachmentsFailure(failure); } else if (failure is ExportAttachmentFailure) { _exportAttachmentFailureAction(failure); } }, (success) { if (success is GetEmailContentSuccess) { emailContent.value = success.emailContent; } else if (success is MarkAsEmailReadSuccess) { _markAsEmailReadSuccess(success); } else if (success is ExportAttachmentSuccess) { _exportAttachmentSuccessAction(success); } }); } @override void onError(error) { } void _clearEmailContent() { toggleDisplayEmailAddressAction(expandMode: ExpandMode.COLLAPSE); attachmentsExpandMode.value = ExpandMode.COLLAPSE; emailContent.value = null; } void toggleDisplayEmailAddressAction({required ExpandMode expandMode}) { emailAddressExpandMode.value = expandMode; } void markAsEmailRead(PresentationEmail presentationEmail, ReadActions readActions) async { final accountId = mailboxDashBoardController.accountId.value; final mailboxCurrent = mailboxDashBoardController.selectedMailbox.value; if (accountId != null && mailboxCurrent != null) { consumeState(_markAsEmailReadInteractor.execute(accountId, presentationEmail.id, readActions)); } } void _markAsEmailReadSuccess(Success success) { mailboxDashBoardController.dispatchState(Right(success)); if (success is MarkAsEmailReadSuccess && success.readActions == ReadActions.markAsUnread) { backToThreadView(); } } void _markAsEmailReadFailure(Failure failure) { backToThreadView(); } void toggleDisplayAttachmentsAction() { final newExpandMode = attachmentsExpandMode.value == ExpandMode.COLLAPSE ? ExpandMode.EXPAND : ExpandMode.COLLAPSE; attachmentsExpandMode.value = newExpandMode; } void downloadAttachments(BuildContext context, List attachments) async { final needRequestPermission = await _deviceManager.isNeedRequestStoragePermissionOnAndroid(); if (needRequestPermission) { final status = await Permission.storage.status; switch (status) { case PermissionStatus.granted: _downloadAttachmentsAction(context, attachments); break; case PermissionStatus.permanentlyDenied: _appToast.showToast(AppLocalizations.of(context).you_need_to_grant_files_permission_to_download_attachments); break; default: { final requested = await Permission.storage.request(); switch (requested) { case PermissionStatus.granted: _downloadAttachmentsAction(context, attachments); break; default: _appToast.showToast(AppLocalizations.of(context).you_need_to_grant_files_permission_to_download_attachments); break; } } } } else { _downloadAttachmentsAction(context, attachments); } } void _downloadAttachmentsAction(BuildContext context, List attachments) async { final accountId = mailboxDashBoardController.accountId.value; if (accountId != null && mailboxDashBoardController.sessionCurrent != null) { final baseDownloadUrl = mailboxDashBoardController.sessionCurrent!.getDownloadUrl(); consumeState(_downloadAttachmentsInteractor.execute(attachments, accountId, baseDownloadUrl)); } } void _downloadAttachmentsFailure(Failure failure) { if (Get.context != null) { _appToast.showErrorToast(AppLocalizations.of(Get.context!).attachment_download_failed); } } void exportAttachment(BuildContext context, Attachment attachment) { final cancelToken = CancelToken(); _showDownloadingFileDialog(context, attachment, cancelToken); _exportAttachmentAction(attachment, cancelToken); } void _showDownloadingFileDialog(BuildContext context, Attachment attachment, CancelToken cancelToken) { showCupertinoDialog( context: context, builder: (_) => (DownloadingFileDialogBuilder() ..key(Key('downloading_file_dialog')) ..title(AppLocalizations.of(context).preparing_to_export) ..content(AppLocalizations.of(context).downloading_file(attachment.name ?? '')) ..actionText(AppLocalizations.of(context).cancel) ..addCancelDownloadActionClick(() { cancelToken.cancel([AppLocalizations.of(context).user_cancel_download_file]); Get.back(); })) .build()); } void _exportAttachmentAction(Attachment attachment, CancelToken cancelToken) async { final accountId = mailboxDashBoardController.accountId.value; if (accountId != null && mailboxDashBoardController.sessionCurrent != null) { final baseDownloadUrl = mailboxDashBoardController.sessionCurrent!.getDownloadUrl(); consumeState(_exportAttachmentInteractor.execute(attachment, accountId, baseDownloadUrl, cancelToken)); } } void _exportAttachmentFailureAction(Failure failure) { if (failure is ExportAttachmentFailure && !(failure.exception is CancelDownloadFileException)) { popBack(); } } void _exportAttachmentSuccessAction(Success success) async { popBack(); if (success is ExportAttachmentSuccess) { await share_library.Share.shareFiles([success.filePath]); } } bool canComposeEmail() => mailboxDashBoardController.sessionCurrent != null && mailboxDashBoardController.userProfile.value != null && mailboxDashBoardController.mapMailboxId.containsKey(PresentationMailbox.roleOutbox) && mailboxDashBoardController.selectedEmail.value != null; void backToThreadView() { popBack(); } void pressEmailAction(EmailActionType emailActionType) { if (canComposeEmail()) { push( AppRoutes.COMPOSER, arguments: ComposerArguments( emailActionType: emailActionType, presentationEmail: mailboxDashBoardController.selectedEmail.value!, emailContent: emailContent.value, session: mailboxDashBoardController.sessionCurrent!, userProfile: mailboxDashBoardController.userProfile.value!, mapMailboxId: mailboxDashBoardController.mapMailboxId)); } } }